| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- ---
- title: Clients
- description: Manage clients as first-class entities that can be attached to one
- or more inbounds. A single client row drives the settings.clients entry in
- every inbound it belongs to. Endpoints live under /panel/api/clients.
- full: true
- _openapi:
- preload:
- - ./public/openapi.json
- toc:
- - depth: 2
- title: List every client with its attached inbound IDs and traffic record. The
- reverse field, if set, is returned as a nested JSON object (legacy
- JSON-encoded-string form is still accepted on write).
- url: '#list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write'
- - depth: 2
- title: 'Filter, sort, and paginate clients on the server. Each item is a slim
- row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
- page can ship 25-ish rows in a few KB instead of the full table. The
- response also includes a summary computed across the full DB row set so
- dashboard counters stay stable as the user paginates or filters: the
- *Count fields are exact, while the email arrays beside them stop at 200
- entries so the payload does not grow with the panel. Page size capped at
- 200; fetch /get/:email to obtain the full per-client payload for an
- edit/info modal.'
- url: '#filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-the-count-fields-are-exact-while-the-email-arrays-beside-them-stop-at-200-entries-so-the-payload-does-not-grow-with-the-panel-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal'
- - depth: 2
- title: Fetch one client by email, including the inbound IDs and external config
- IDs it is attached to.
- url: '#fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to'
- - depth: 2
- title: Fetch clients by Telegram user ID. Returns an array since multiple
- clients can share the same Telegram ID.
- url: '#fetch-clients-by-telegram-user-id-returns-an-array-since-multiple-clients-can-share-the-same-telegram-id'
- - depth: 2
- title: Create a new client and attach it to one or more inbounds in a single
- call. Body is JSON. Per-protocol secrets are generated server-side when
- omitted, so callers can send only the universal fields.
- url: '#create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields'
- - depth: 2
- title: Update an existing client by email. Changes propagate to every attached
- inbound. Body is the JSON client payload — supply the full set of fields
- you want to keep (the server replaces the row, it does not patch).
- url: '#update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch'
- - depth: 2
- title: Delete a client by email. Removes it from every attached inbound and
- drops its traffic record unless keepTraffic=1 is passed.
- url: '#delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed'
- - depth: 2
- title: Attach an existing client to one or more additional inbounds. Body is
- JSON.
- url: '#attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json'
- - depth: 2
- title: Detach a client from one or more inbounds without deleting the client.
- url: '#detach-a-client-from-one-or-more-inbounds-without-deleting-the-client'
- - depth: 2
- title: Replace a client's external links and external subscriptions. Sends the
- full set; the server replaces all rows. Disabled rows stay saved for
- editing but are not emitted in generated subscriptions. The owning
- client's disabled or expired state also stops these rows from being
- emitted on future subscription fetches; credentials already imported by
- an app remain valid until the external provider revokes them.
- url: '#replace-a-clients-external-links-and-external-subscriptions-sends-the-full-set-the-server-replaces-all-rows-disabled-rows-stay-saved-for-editing-but-are-not-emitted-in-generated-subscriptions-the-owning-clients-disabled-or-expired-state-also-stops-these-rows-from-being-emitted-on-future-subscription-fetches-credentials-already-imported-by-an-app-remain-valid-until-the-external-provider-revokes-them'
- - depth: 2
- title: Reset the up/down counters for every client globally. Quotas and expiry
- are not affected. Triggers an Xray restart if any counter actually
- moved.
- url: '#reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved'
- - depth: 2
- title: Delete every client whose traffic quota is exhausted (used >= total, when
- reset is disabled) or whose expiry has passed. Returns the deleted count
- and triggers an Xray restart when any client was on a running inbound.
- url: '#delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound'
- - depth: 2
- title: Delete every client that is not attached to any inbound, along with its
- traffic record, IP log, HWID devices, and external links. Useful for
- clearing clients left unattached after their inbounds were removed.
- Returns the deleted count. Cannot be undone.
- url: '#delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-hwid-devices-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone'
- - depth: 2
- title: Return every client as a {client, inboundIds} array — the same shape
- /bulkCreate and /import accept — so the payload round-trips straight
- back through /import. Clients with no inbound attachment are included
- with an empty inboundIds list. The UI shows this in a CodeMirror viewer
- (copy / download); programmatic callers get the array in obj.
- url: '#return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj'
- - depth: 2
- title: 'Import clients from a JSON body { "data": "<json>" }, where data is a
- string-encoded array produced by /export ([{client, inboundIds}]). Items
- with inboundIds are created and attached to those inbounds; items with
- an empty inboundIds list are restored as unattached client records.
- Existing emails are never overwritten — they are returned in skipped.
- Triggers a single Xray restart at the end if any target inbound was
- running.'
- url: '#import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running'
- - depth: 2
- title: 'Shift expiry and/or traffic quota for many clients in one call.
- addDays/addBytes may be negative. Clients with unlimited expiry
- (expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
- corresponding field — bulk extend never converts unlimited to limited. A
- client that was auto-disabled solely because it was depleted (expired or
- over quota) is automatically re-enabled — locally and on its node — when
- the adjustment lifts it out of depletion; a manually-disabled or
- still-depleted client is left disabled. The optional flow directive sets
- the XTLS flow on every client: "none" clears it,
- "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where the inbound
- supports it (omit or "" to leave it unchanged). The optional limitHwid
- sets maximum registered devices (0 = unlimited). The optional adTag sets
- MTProto Telegram sponsor channel ("none" clears). Returns the adjusted
- count and per-email skip reasons.'
- url: '#shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-a-client-that-was-auto-disabled-solely-because-it-was-depleted-expired-or-over-quota-is-automatically-re-enabled--locally-and-on-its-node--when-the-adjustment-lifts-it-out-of-depletion-a-manually-disabled-or-still-depleted-client-is-left-disabled-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-the-optional-limithwid-sets-maximum-registered-devices-0--unlimited-the-optional-adtag-sets-mtproto-telegram-sponsor-channel-none-clears-returns-the-adjusted-count-and-per-email-skip-reasons'
- - depth: 2
- title: Enable many clients in one call. Emails are grouped by inbound and
- applied with a single read-modify-write per inbound; the running Xray
- (local or remote node) is updated to add each user. Note that enabling a
- client whose quota is exhausted or whose expiry has passed only flips
- the flag — the traffic loop will disable it again on the next tick.
- Returns the changed count and per-email skip reasons.
- url: '#enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons'
- - depth: 2
- title: Disable many clients in one call. Emails are grouped by inbound and
- applied with a single read-modify-write per inbound; the running Xray
- (local or remote node) is updated to remove each user. Returns the
- changed count and per-email skip reasons.
- url: '#disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons'
- - depth: 2
- title: Delete many clients in one call. The server processes the list
- sequentially so each delete sees the committed state of the previous one
- — avoids the race the per-email fan-out had on the panel side. Pass
- keepTraffic=true to retain the xray_client_traffic rows after deletion.
- url: '#delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion'
- - depth: 2
- title: Create many clients in one call. Body is a JSON array of {client,
- inboundIds} payloads — the same shape /add accepts. Items are processed
- sequentially; per-email skip reasons are returned for items that fail
- (e.g., duplicate email). Triggers a single Xray restart at the end if
- any inbound was running.
- url: '#create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running'
- - depth: 2
- title: Add many clients to a group in one call. Updates clients.group_name and
- patches the matching client entry inside every owning inbound's settings
- JSON in a single transaction. If the group name does not yet exist (in
- client_groups or as a derived label), it is auto-created as a persistent
- group. To clear the group label, use /groups/bulkRemove instead.
- url: '#add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead'
- - depth: 2
- title: Clear the group label on many clients in one call. Inverse of
- /groups/bulkAdd. Clients themselves are kept — only the group label is
- cleared from clients.group_name and from each owning inbound's settings
- JSON. Groups become empty if all their members are removed.
- url: '#clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed'
- - depth: 2
- title: Attach many existing clients to many inbounds in one call. Each client
- keeps its identity (email/UUID/password/subId) and a shared traffic row;
- all clients are added to a target inbound in a single AddInboundClient
- call. Clients already present on a target are reported under skipped.
- Returns per-email attached/skipped/errors lists and triggers a single
- Xray restart if any target inbound was running.
- url: '#attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running'
- - depth: 2
- title: "Mirror of bulkAttach: detach many existing clients from many inbounds in
- one call. For each email, intersects the client's current inbounds with
- the requested set and detaches from those only; (email, inbound) pairs
- where the client is not currently attached are silently no-ops. Emails
- not attached to any of the requested inbounds are reported under
- skipped. Client records are kept even if they become orphaned — use
- bulkDel for full removal. Returns per-email detached/skipped/errors
- lists and triggers a single Xray restart if any target inbound was
- running."
- url: '#mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running'
- - depth: 2
- title: Zero up/down counters for many clients in one call. Loops the
- single-reset path so each client is re-enabled across its attached
- inbounds and pushed to Xray/remote nodes. Returns the count of
- successfully reset clients.
- url: '#zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients'
- - depth: 2
- title: List all client groups with their member counts. Merges persisted groups
- (rows in client_groups, including empty placeholders) with the distinct
- group_name values currently set on clients. Sorted alphabetically
- (case-insensitive).
- url: '#list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive'
- - depth: 2
- title: Return just the email list of clients that currently belong to the given
- group. Useful for fanning a single bulk action over an entire group
- without round-tripping the full client list.
- url: '#return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list'
- - depth: 2
- title: Create a new empty (placeholder) group. The group becomes selectable in
- client forms and the filter drawer even before any client is added to
- it. Errors if a group with the same name already exists.
- url: '#create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists'
- - depth: 2
- title: Rename a group. The new name is applied to the client_groups row AND
- propagated to every matching client (both clients.group_name and the
- client entry inside every owning inbound's settings JSON) in a single
- transaction. Returns the number of clients whose label was updated.
- url: '#rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated'
- - depth: 2
- title: Remove a group. Deletes the client_groups row and clears the group label
- from every matching client (both clients.group_name and the inbound
- settings JSON). The clients themselves are NOT deleted — use /bulkDel
- after filtering by group for that. Returns the count of clients whose
- label was cleared.
- url: '#remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared'
- - depth: 2
- title: Reset only the group-level traffic counter shown on the groups page.
- Snapshots the current up/down sum of the group's members as a baseline
- so the group total reads zero, while leaving each client's own counters
- (and their quotas) untouched. No Xray restart is triggered. Creates the
- client_groups row if the group exists only as a derived label.
- url: '#reset-only-the-group-level-traffic-counter-shown-on-the-groups-page-snapshots-the-current-updown-sum-of-the-groups-members-as-a-baseline-so-the-group-total-reads-zero-while-leaving-each-clients-own-counters-and-their-quotas-untouched-no-xray-restart-is-triggered-creates-the-client_groups-row-if-the-group-exists-only-as-a-derived-label'
- - depth: 2
- title: Zero out a single client’s up/down counters. Re-enables the client across
- every attached inbound and pushes the change to Xray (or the remote
- node) so depleted users can connect again immediately.
- url: '#zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately'
- - depth: 2
- title: Manually adjust a client’s upload + download counters. Useful for
- migrations from external accounting systems.
- url: '#manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems'
- - depth: 2
- title: List source IPs that have connected with the given client’s credentials.
- Returns an array of "ip (timestamp)" strings.
- url: '#list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings'
- - depth: 2
- title: Reset the recorded IP list for a client.
- url: '#reset-the-recorded-ip-list-for-a-client'
- - depth: 2
- title: List registered HWID devices for a client with a short fingerprint. Full hashes are not exposed.
- url: '#list-registered-hwid-devices-for-a-client-with-a-short-fingerprint-full-hashes-are-not-exposed'
- - depth: 2
- title: Clear all registered HWID devices for a client so new devices can
- register again.
- url: '#clear-all-registered-hwid-devices-for-a-client-so-new-devices-can-register-again'
- - depth: 2
- title: Remove a single registered HWID device by its id, freeing one slot under
- the HWID limit.
- url: '#remove-a-single-registered-hwid-device-by-its-id-freeing-one-slot-under-the-hwid-limit'
- - depth: 2
- title: List the emails of currently connected clients (last seen within the
- heartbeat window), deduped across every node.
- url: '#list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node'
- - depth: 2
- title: Online client emails grouped by the panelGuid of the node that physically
- hosts each client. The local panel uses its own GUID; each node (at any
- depth in a chain) uses its GUID. Lets the inbounds page attribute online
- status to the real node instead of the intermediate one it syncs
- through.
- url: '#online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through'
- - depth: 2
- title: Per-client source IPs grouped by the panelGuid of the node that observed
- them. Lets the central panel attribute and enforce per-client IP limits
- using the real visitor IPs each node sees, instead of the address of the
- intermediate panel it syncs through.
- url: '#per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through'
- - depth: 2
- title: Inbound tags that carried traffic within the heartbeat window, grouped by
- the hosting node's panelGuid. Pairs with onlinesByGuid so the inbounds
- page only marks a multi-inbound client online on the inbounds it
- actually used. Nodes that do not report per-inbound activity are absent.
- url: '#inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent'
- - depth: 2
- title: Map of client email → last-seen unix timestamp.
- url: '#map-of-client-email--last-seen-unix-timestamp'
- - depth: 2
- title: Traffic counters for a client identified by email.
- url: '#traffic-counters-for-a-client-identified-by-email'
- - depth: 2
- title: Return every protocol URL (vless://, vmess://, trojan://, ss://,
- hysteria://, hy2://) for clients matching the subscription ID. Same
- result set as the configured subPath endpoint, but as a JSON array — no
- base64. When an inbound has streamSettings.externalProxy set, one URL is
- emitted per external proxy. Empty array when the subId has no enabled
- clients.
- url: '#return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-the-configured-subpath-endpoint-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients'
- - depth: 2
- title: 'Return every URL for one client across all attached inbounds, one per
- advertised endpoint: the managed hosts of the inbound, else its
- streamSettings.externalProxy entries, else its own address. Supported
- protocols: vmess, vless, trojan, shadowsocks, hysteria, mtproto.
- Protocols without a URL form (socks, http, mixed, wireguard, dokodemo,
- tunnel) contribute nothing.'
- url: '#return-every-url-for-one-client-across-all-attached-inbounds-one-per-advertised-endpoint-the-managed-hosts-of-the-inbound-else-its-streamsettingsexternalproxy-entries-else-its-own-address-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-mtproto-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing'
- structuredData:
- headings:
- - content: List every client with its attached inbound IDs and traffic record. The
- reverse field, if set, is returned as a nested JSON object (legacy
- JSON-encoded-string form is still accepted on write).
- id: list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write
- - content: 'Filter, sort, and paginate clients on the server. Each item is a slim
- row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
- page can ship 25-ish rows in a few KB instead of the full table. The
- response also includes a summary computed across the full DB row set
- so dashboard counters stay stable as the user paginates or filters:
- the *Count fields are exact, while the email arrays beside them stop
- at 200 entries so the payload does not grow with the panel. Page size
- capped at 200; fetch /get/:email to obtain the full per-client payload
- for an edit/info modal.'
- id: filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-the-count-fields-are-exact-while-the-email-arrays-beside-them-stop-at-200-entries-so-the-payload-does-not-grow-with-the-panel-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal
- - content: Fetch one client by email, including the inbound IDs and external
- config IDs it is attached to.
- id: fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
- - content: Fetch clients by Telegram user ID. Returns an array since multiple
- clients can share the same Telegram ID.
- id: fetch-clients-by-telegram-user-id-returns-an-array-since-multiple-clients-can-share-the-same-telegram-id
- - content: Create a new client and attach it to one or more inbounds in a single
- call. Body is JSON. Per-protocol secrets are generated server-side
- when omitted, so callers can send only the universal fields.
- id: create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- - content: Update an existing client by email. Changes propagate to every attached
- inbound. Body is the JSON client payload — supply the full set of
- fields you want to keep (the server replaces the row, it does not
- patch).
- id: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- - content: Delete a client by email. Removes it from every attached inbound and
- drops its traffic record unless keepTraffic=1 is passed.
- id: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- - content: Attach an existing client to one or more additional inbounds. Body is
- JSON.
- id: attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- - content: Detach a client from one or more inbounds without deleting the client.
- id: detach-a-client-from-one-or-more-inbounds-without-deleting-the-client
- - content: Replace a client's external links and external subscriptions. Sends the
- full set; the server replaces all rows. Disabled rows stay saved for
- editing but are not emitted in generated subscriptions. The owning
- client's disabled or expired state also stops these rows from being
- emitted on future subscription fetches; credentials already imported
- by an app remain valid until the external provider revokes them.
- id: replace-a-clients-external-links-and-external-subscriptions-sends-the-full-set-the-server-replaces-all-rows-disabled-rows-stay-saved-for-editing-but-are-not-emitted-in-generated-subscriptions-the-owning-clients-disabled-or-expired-state-also-stops-these-rows-from-being-emitted-on-future-subscription-fetches-credentials-already-imported-by-an-app-remain-valid-until-the-external-provider-revokes-them
- - content: Reset the up/down counters for every client globally. Quotas and expiry
- are not affected. Triggers an Xray restart if any counter actually
- moved.
- id: reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved
- - content: Delete every client whose traffic quota is exhausted (used >= total,
- when reset is disabled) or whose expiry has passed. Returns the
- deleted count and triggers an Xray restart when any client was on a
- running inbound.
- id: delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound
- - content: Delete every client that is not attached to any inbound, along with its
- traffic record, IP log, HWID devices, and external links. Useful for
- clearing clients left unattached after their inbounds were removed.
- Returns the deleted count. Cannot be undone.
- id: delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-hwid-devices-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone
- - content: Return every client as a {client, inboundIds} array — the same shape
- /bulkCreate and /import accept — so the payload round-trips straight
- back through /import. Clients with no inbound attachment are included
- with an empty inboundIds list. The UI shows this in a CodeMirror
- viewer (copy / download); programmatic callers get the array in obj.
- id: return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj
- - content: 'Import clients from a JSON body { "data": "<json>" }, where data is a
- string-encoded array produced by /export ([{client, inboundIds}]).
- Items with inboundIds are created and attached to those inbounds;
- items with an empty inboundIds list are restored as unattached client
- records. Existing emails are never overwritten — they are returned in
- skipped. Triggers a single Xray restart at the end if any target
- inbound was running.'
- id: import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running
- - content: 'Shift expiry and/or traffic quota for many clients in one call.
- addDays/addBytes may be negative. Clients with unlimited expiry
- (expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
- corresponding field — bulk extend never converts unlimited to limited.
- A client that was auto-disabled solely because it was depleted
- (expired or over quota) is automatically re-enabled — locally and on
- its node — when the adjustment lifts it out of depletion; a
- manually-disabled or still-depleted client is left disabled. The
- optional flow directive sets the XTLS flow on every client: "none"
- clears it, "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where
- the inbound supports it (omit or "" to leave it unchanged). The
- optional limitHwid sets maximum registered devices (0 = unlimited).
- The optional adTag sets MTProto Telegram sponsor channel ("none"
- clears). Returns the adjusted count and per-email skip reasons.'
- id: shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-a-client-that-was-auto-disabled-solely-because-it-was-depleted-expired-or-over-quota-is-automatically-re-enabled--locally-and-on-its-node--when-the-adjustment-lifts-it-out-of-depletion-a-manually-disabled-or-still-depleted-client-is-left-disabled-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-the-optional-limithwid-sets-maximum-registered-devices-0--unlimited-the-optional-adtag-sets-mtproto-telegram-sponsor-channel-none-clears-returns-the-adjusted-count-and-per-email-skip-reasons
- - content: Enable many clients in one call. Emails are grouped by inbound and
- applied with a single read-modify-write per inbound; the running Xray
- (local or remote node) is updated to add each user. Note that enabling
- a client whose quota is exhausted or whose expiry has passed only
- flips the flag — the traffic loop will disable it again on the next
- tick. Returns the changed count and per-email skip reasons.
- id: enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons
- - content: Disable many clients in one call. Emails are grouped by inbound and
- applied with a single read-modify-write per inbound; the running Xray
- (local or remote node) is updated to remove each user. Returns the
- changed count and per-email skip reasons.
- id: disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons
- - content: Delete many clients in one call. The server processes the list
- sequentially so each delete sees the committed state of the previous
- one — avoids the race the per-email fan-out had on the panel side.
- Pass keepTraffic=true to retain the xray_client_traffic rows after
- deletion.
- id: delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion
- - content: Create many clients in one call. Body is a JSON array of {client,
- inboundIds} payloads — the same shape /add accepts. Items are
- processed sequentially; per-email skip reasons are returned for items
- that fail (e.g., duplicate email). Triggers a single Xray restart at
- the end if any inbound was running.
- id: create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running
- - content: Add many clients to a group in one call. Updates clients.group_name and
- patches the matching client entry inside every owning inbound's
- settings JSON in a single transaction. If the group name does not yet
- exist (in client_groups or as a derived label), it is auto-created as
- a persistent group. To clear the group label, use /groups/bulkRemove
- instead.
- id: add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead
- - content: Clear the group label on many clients in one call. Inverse of
- /groups/bulkAdd. Clients themselves are kept — only the group label is
- cleared from clients.group_name and from each owning inbound's
- settings JSON. Groups become empty if all their members are removed.
- id: clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed
- - content: Attach many existing clients to many inbounds in one call. Each client
- keeps its identity (email/UUID/password/subId) and a shared traffic
- row; all clients are added to a target inbound in a single
- AddInboundClient call. Clients already present on a target are
- reported under skipped. Returns per-email attached/skipped/errors
- lists and triggers a single Xray restart if any target inbound was
- running.
- id: attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- - content: "Mirror of bulkAttach: detach many existing clients from many inbounds
- in one call. For each email, intersects the client's current inbounds
- with the requested set and detaches from those only; (email, inbound)
- pairs where the client is not currently attached are silently no-ops.
- Emails not attached to any of the requested inbounds are reported
- under skipped. Client records are kept even if they become orphaned —
- use bulkDel for full removal. Returns per-email
- detached/skipped/errors lists and triggers a single Xray restart if
- any target inbound was running."
- id: mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- - content: Zero up/down counters for many clients in one call. Loops the
- single-reset path so each client is re-enabled across its attached
- inbounds and pushed to Xray/remote nodes. Returns the count of
- successfully reset clients.
- id: zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients
- - content: List all client groups with their member counts. Merges persisted
- groups (rows in client_groups, including empty placeholders) with the
- distinct group_name values currently set on clients. Sorted
- alphabetically (case-insensitive).
- id: list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive
- - content: Return just the email list of clients that currently belong to the
- given group. Useful for fanning a single bulk action over an entire
- group without round-tripping the full client list.
- id: return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list
- - content: Create a new empty (placeholder) group. The group becomes selectable in
- client forms and the filter drawer even before any client is added to
- it. Errors if a group with the same name already exists.
- id: create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists
- - content: Rename a group. The new name is applied to the client_groups row AND
- propagated to every matching client (both clients.group_name and the
- client entry inside every owning inbound's settings JSON) in a single
- transaction. Returns the number of clients whose label was updated.
- id: rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated
- - content: Remove a group. Deletes the client_groups row and clears the group
- label from every matching client (both clients.group_name and the
- inbound settings JSON). The clients themselves are NOT deleted — use
- /bulkDel after filtering by group for that. Returns the count of
- clients whose label was cleared.
- id: remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared
- - content: Reset only the group-level traffic counter shown on the groups page.
- Snapshots the current up/down sum of the group's members as a baseline
- so the group total reads zero, while leaving each client's own
- counters (and their quotas) untouched. No Xray restart is triggered.
- Creates the client_groups row if the group exists only as a derived
- label.
- id: reset-only-the-group-level-traffic-counter-shown-on-the-groups-page-snapshots-the-current-updown-sum-of-the-groups-members-as-a-baseline-so-the-group-total-reads-zero-while-leaving-each-clients-own-counters-and-their-quotas-untouched-no-xray-restart-is-triggered-creates-the-client_groups-row-if-the-group-exists-only-as-a-derived-label
- - content: Zero out a single client’s up/down counters. Re-enables the client
- across every attached inbound and pushes the change to Xray (or the
- remote node) so depleted users can connect again immediately.
- id: zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately
- - content: Manually adjust a client’s upload + download counters. Useful for
- migrations from external accounting systems.
- id: manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems
- - content: List source IPs that have connected with the given client’s
- credentials. Returns an array of "ip (timestamp)" strings.
- id: list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings
- - content: Reset the recorded IP list for a client.
- id: reset-the-recorded-ip-list-for-a-client
- - content: List registered HWID devices for a client with a short fingerprint. Full hashes are not exposed.
- id: list-registered-hwid-devices-for-a-client-with-a-short-fingerprint-full-hashes-are-not-exposed
- - content: Clear all registered HWID devices for a client so new devices can
- register again.
- id: clear-all-registered-hwid-devices-for-a-client-so-new-devices-can-register-again
- - content: Remove a single registered HWID device by its id, freeing one slot
- under the HWID limit.
- id: remove-a-single-registered-hwid-device-by-its-id-freeing-one-slot-under-the-hwid-limit
- - content: List the emails of currently connected clients (last seen within the
- heartbeat window), deduped across every node.
- id: list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node
- - content: Online client emails grouped by the panelGuid of the node that
- physically hosts each client. The local panel uses its own GUID; each
- node (at any depth in a chain) uses its GUID. Lets the inbounds page
- attribute online status to the real node instead of the intermediate
- one it syncs through.
- id: online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through
- - content: Per-client source IPs grouped by the panelGuid of the node that
- observed them. Lets the central panel attribute and enforce per-client
- IP limits using the real visitor IPs each node sees, instead of the
- address of the intermediate panel it syncs through.
- id: per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through
- - content: Inbound tags that carried traffic within the heartbeat window, grouped
- by the hosting node's panelGuid. Pairs with onlinesByGuid so the
- inbounds page only marks a multi-inbound client online on the inbounds
- it actually used. Nodes that do not report per-inbound activity are
- absent.
- id: inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent
- - content: Map of client email → last-seen unix timestamp.
- id: map-of-client-email--last-seen-unix-timestamp
- - content: Traffic counters for a client identified by email.
- id: traffic-counters-for-a-client-identified-by-email
- - content: Return every protocol URL (vless://, vmess://, trojan://, ss://,
- hysteria://, hy2://) for clients matching the subscription ID. Same
- result set as the configured subPath endpoint, but as a JSON array —
- no base64. When an inbound has streamSettings.externalProxy set, one
- URL is emitted per external proxy. Empty array when the subId has no
- enabled clients.
- id: return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-the-configured-subpath-endpoint-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
- - content: 'Return every URL for one client across all attached inbounds, one per
- advertised endpoint: the managed hosts of the inbound, else its
- streamSettings.externalProxy entries, else its own address. Supported
- protocols: vmess, vless, trojan, shadowsocks, hysteria, mtproto.
- Protocols without a URL form (socks, http, mixed, wireguard, dokodemo,
- tunnel) contribute nothing.'
- id: return-every-url-for-one-client-across-all-attached-inbounds-one-per-advertised-endpoint-the-managed-hosts-of-the-inbound-else-its-streamsettingsexternalproxy-entries-else-its-own-address-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-mtproto-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
- contents:
- - content: >-
- Fields the server fills in when they are omitted — a valid value sent
- by the caller is never overwritten. Re-adding an email that already
- exists, with its stored `subId`, reuses the stored `id`, `password`,
- `auth` and `secret` instead of minting new ones, so the identity stays
- in sync across its inbounds.
- - **VLESS / VMess** — `id`, a fresh UUID
- - **Trojan** — `password`
- - **Shadowsocks** — `password`. On a `2022-blake3-*` inbound a
- supplied password that does not base64-decode to the key length of the
- cipher (16 or 32 bytes) is replaced by a generated key and the call
- still succeeds, so read the client back if you did not let the server
- pick. Legacy ciphers keep any non-empty password
- - **Hysteria** — `auth`
- - **mtproto** — `secret`, a FakeTLS secret derived from the fronting
- domain of the inbound, or from `www.cloudflare.com` when it has none
- - **WireGuard** — `privateKey` and `publicKey` when both are blank, or
- `publicKey` alone when only a `privateKey` was sent, plus
- `allowedIPs`: one free `/32` taken from the /24 the existing peers of
- that inbound already sit in, or from `10.0.0.0/24` when it has none
- Accepted on the same body but never generated: `preSharedKey` and
- `keepAlive` (WireGuard), `adTag` (mtproto).
- WireGuard is the only one of these that can fail. Allocation widens
- the search to the containing /16 before giving up with `inbound <id>:
- wireguard: no free address available in <scope>`, and an `allowedIPs`
- supplied by the caller is validated instead of allocated: `inbound
- <id>: wireguard: allowedIPs entry already used by another client:
- <address>` when a different client of that same inbound already holds
- it. The check is per inbound, so the same address on two different
- inbounds is accepted. The same validation runs on POST
- /panel/api/clients/{email}/attach, where a client that already carries
- an address brings it along.
- An `inboundIds` entry that names no existing inbound rejects the whole
- call before anything is written. Past that, the inbounds are applied
- concurrently and independently: one that fails no longer stops the
- others, so a `success:false` response can still have created the
- client on the rest. Every error names the inbound it came from
- (`inbound 7: <message>`), and several failures are reported together,
- one per line. `limitHwid` is applied only when every inbound
- succeeded, so re-run the call after fixing the failure.
- heading: create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- - content: 'The inbounds are applied concurrently and independently: one that
- fails no longer stops the others. Every inbound error names the
- inbound it came from (`inbound 7: <message>`), and several failures
- are reported together, one per line. So a `success:false` response can
- still have applied the edit to the remaining inbounds. The client
- record is written after the inbounds, so a failure there is reported
- without an `inbound <id>:` prefix and leaves the inbound edits in
- place.'
- heading: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- - content: 'The inbounds are applied concurrently and independently: one that
- fails no longer stops the others. Every inbound error names the
- inbound it came from (`inbound 7: <message>`), and several failures
- are reported together, one per line. So a `success:false` response can
- still have removed the client from the remaining inbounds; the client
- record is kept in that case, so re-running the call retries exactly
- the leftovers. The record and traffic rows are dropped after the
- inbounds, so a failure there is reported without an `inbound <id>:`
- prefix and leaves the client already removed from every inbound.'
- heading: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- - content: 'A WireGuard client brings its stored `allowedIPs` into the new inbound
- instead of being given a fresh address, so the call fails with
- `inbound <id>: wireguard: allowedIPs entry already used by another
- client: <address>` when a different client of the target inbound
- already holds it. Free the address on that inbound first — see POST
- /panel/api/clients/add for the full rule. Inbounds are applied
- independently, so the remaining ones are still attached and a
- `success:false` response can be partial.'
- heading: attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- - content: 'The inbounds are applied concurrently and independently: one that
- fails no longer stops the others. Every inbound error names the
- inbound it came from (`inbound 7: <message>`), and several failures
- are reported together, one per line. So a `success:false` response can
- still have detached the remaining inbounds. Detach writes nothing
- beyond the inbounds, so every error carries the prefix.'
- heading: detach-a-client-from-one-or-more-inbounds-without-deleting-the-client
- ---
- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
- export default function Layout(props) {
- const { APIPage, OpenAPIPage } = props.components ?? {};
- // "APIPage" is the old name from v10, this allows both for backward compatibility
- const Comp = OpenAPIPage ?? APIPage;
- return (
- <>
- {props.children}
- <Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/clients/list","method":"get"},{"path":"/panel/api/clients/list/paged","method":"get"},{"path":"/panel/api/clients/get/{email}","method":"get"},{"path":"/panel/api/clients/get/tgId/{tgId}","method":"get"},{"path":"/panel/api/clients/add","method":"post"},{"path":"/panel/api/clients/update/{email}","method":"post"},{"path":"/panel/api/clients/del/{email}","method":"post"},{"path":"/panel/api/clients/{email}/attach","method":"post"},{"path":"/panel/api/clients/{email}/detach","method":"post"},{"path":"/panel/api/clients/{email}/externalLinks","method":"post"},{"path":"/panel/api/clients/resetAllTraffics","method":"post"},{"path":"/panel/api/clients/delDepleted","method":"post"},{"path":"/panel/api/clients/delOrphans","method":"post"},{"path":"/panel/api/clients/export","method":"get"},{"path":"/panel/api/clients/import","method":"post"},{"path":"/panel/api/clients/bulkAdjust","method":"post"},{"path":"/panel/api/clients/bulkEnable","method":"post"},{"path":"/panel/api/clients/bulkDisable","method":"post"},{"path":"/panel/api/clients/bulkDel","method":"post"},{"path":"/panel/api/clients/bulkCreate","method":"post"},{"path":"/panel/api/clients/groups/bulkAdd","method":"post"},{"path":"/panel/api/clients/groups/bulkRemove","method":"post"},{"path":"/panel/api/clients/bulkAttach","method":"post"},{"path":"/panel/api/clients/bulkDetach","method":"post"},{"path":"/panel/api/clients/bulkResetTraffic","method":"post"},{"path":"/panel/api/clients/groups","method":"get"},{"path":"/panel/api/clients/groups/{name}/emails","method":"get"},{"path":"/panel/api/clients/groups/create","method":"post"},{"path":"/panel/api/clients/groups/rename","method":"post"},{"path":"/panel/api/clients/groups/delete","method":"post"},{"path":"/panel/api/clients/groups/resetTraffic","method":"post"},{"path":"/panel/api/clients/resetTraffic/{email}","method":"post"},{"path":"/panel/api/clients/updateTraffic/{email}","method":"post"},{"path":"/panel/api/clients/ips/{email}","method":"post"},{"path":"/panel/api/clients/clearIps/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"delete"},{"path":"/panel/api/clients/hwids/{email}/{id}","method":"delete"},{"path":"/panel/api/clients/onlines","method":"post"},{"path":"/panel/api/clients/onlinesByGuid","method":"post"},{"path":"/panel/api/clients/clientIpsByGuid","method":"post"},{"path":"/panel/api/clients/activeInbounds","method":"post"},{"path":"/panel/api/clients/lastOnline","method":"post"},{"path":"/panel/api/clients/traffic/{email}","method":"get"},{"path":"/panel/api/clients/subLinks/{subId}","method":"get"},{"path":"/panel/api/clients/links/{email}","method":"get"}]} showTitle />
- </>
- );
- }
|