MethodPathSummaryAuth
GET/v1/admin/usersList tenant users in the customer control planeSession
POST/v1/admin/usersCreate an isolated tenant userSession
PATCH/v1/admin/usersAtomically update tenant usersSession
GET/v1/admin/users/{id}Get one tenant userSession
PATCH/v1/admin/users/{id}Update tenant user profile, status, and roleSession
GET/v1/admin/users/{id}/login-securityRead the selected tenant user's login security policySession
PUT/v1/admin/users/{id}/login-securityReplace a tenant user's login security policySession
GET/v1/admin/users/{id}/secondary-verificationRead the selected tenant user's secondary identity verification requestSession
PUT/v1/admin/users/{id}/secondary-verificationReplace a tenant user's secondary identity verification requestSession
GET/v1/admin/users/{user_id}/api-keysList a tenant user's API key metadataSession
POST/v1/admin/users/{user_id}/api-keysCreate pending API key metadata for a tenant userSession
POST/v1/admin/users/{user_id}/api-keys/{key_id}/revokeRevoke a tenant user's API keySession

Contract file:api/openapi/v1/control.yaml

Operation details

GET /v1/admin/users

List tenant users in the customer control plane

operationId
listManagedUsers
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires identity.users.manage in a platform scope. Platform identities are never returned.

Parameters

listManagedUsers Parameters
NameInTypeRequiredDescription
includequeryarray<string: user_metadata / user_verification / platform_admins / reseller>NoOptional comma-separated unique projections. user_metadata adds remark and QQ; user_verification adds only current personal/company verification flags; platform_admins also lists platform-scope administrators (tenant_id null); Omission preserves the original fifteen-field representation. Empty, unknown, duplicate items and repeated parameters are rejected. user_verification, platform_admins and reseller are accepted only on this list endpoint.
pagequeryintegerNo—
limitqueryintegerNo—
searchquerystringNo—
display_idquerystringNoExact positive-decimal user display ID. Internal UUID identity and write paths are unchanged.
usernamequerystringNoCase-insensitive literal substring of username only. Trim boundary whitespace, reject raw C0/C1 controls, and allow at most 128 Unicode code points after trimming. Empty means no filter; all supplied filters intersect using AND.
display_namequerystringNoCase-insensitive literal substring of display name only, with the same trimming, control-character rejection, length and AND semantics as username. Percent and underscore are literal characters.
emailquerystringNoCase-insensitive literal substring of email only, with the same trimming, control-character rejection, length and AND semantics as username. Partial addresses are allowed; NULL email does not match a nonempty filter.
phonequerystringNoCase-insensitive literal substring of phone only, with the same trimming, control-character rejection, length and AND semantics as username. Leading zeroes and plus signs are significant; NULL phone does not match a nonempty filter.
remarkquerystringNoTrimmed case-insensitive literal substring of the administrator remark. Empty means no filter; combined with every other filter using AND.
qqquerystringNoTrimmed case-insensitive literal substring of the QQ contact text. Leading zeroes are significant; empty means no filter and all filters intersect.
statusquerystring: active / disabledNo—
real_name_statusquerystring: verified / unverifiedNoOptional current verification filter, intersected with all other filters before pagination in the same snapshot as the returned flags. verified means personal_verified OR company_verified; unverified means neither. Omit for all users. Empty or unknown values are invalid. Each flag requires the latest application of that kind to be approved, its authoritative identity binding to match, and its evidence settlement to be settled. Reads never create or approve identity records.
rolequerystring: tenant_owner / tenant_viewerNo—
group_idquerystring(uuid)No—
typequerystring: reseller / customer / directNoreseller = the tenant has a reseller profile (active or suspended); customer = the tenant belongs to a reseller; direct = neither. Any value excludes platform administrators. Omit for all users.
parentquerystringNoOwning reseller filter, applied before pagination and intersected with type. none = tenants without a reseller (platform customers, including resellers themselves); a lowercase reseller scope UUID = that reseller's customers. Excludes platform administrators. Omit for all users.

Responses

listManagedUsers Responses
StatusDescription
200Stable tenant user page ordered newest first.

Fields:items: array<ManagedUser> page: integer limit: integer total: integer(int64)

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/admin/users

Create an isolated tenant user

operationId
createManagedUser
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Creates the tenant, tenant scope, system roles, membership, and Argon2id credential atomically.

Parameters

createManagedUser Parameters
NameInTypeRequiredDescription
includequerystring: user_metadataNoSet to user_metadata to include administrator-only remark and QQ fields. Omission preserves the original fifteen-field representation. Unknown or repeated values are rejected. This representation choice does not change mutation idempotency; a historical receipt may omit metadata, in which case read the current resource before editing these fields.
Idempotency-KeyheaderstringYes—
X-Request-IDheaderstringNoCaller-stable write attempt identifier. Reuse it only with the same idempotency key and body.
traceparentheaderstringNoW3C trace context preserved across an exact retry.

Request body

application/json · Required:Yes

createManagedUser Request body
NameTypeRequiredDescription
usernamestringYes—
passwordstring(password)Yes8 to 1024 printable ASCII characters (no space) with at least two of upper case, lower case, digits and symbols; otherwise password_policy_unmet.
display_namestringYes—
emailstring(email) | null(email)No—
phonestring | nullNo—
remarkstring | nullNoAdministrator-only remark, trimmed at both ends. Internal tabs and line breaks are preserved; other control characters are rejected. Null or whitespace-only input clears the stored value. Length counts Unicode code points.
qqstring | nullNoTrimmed QQ contact text, preserving leading zeroes. Not a login identifier and not unique. Control characters are rejected; null or whitespace-only input clears the stored value. Length counts Unicode code points.
rolestring: tenant_owner / tenant_viewerYes—
group_idstring(uuid) | null(uuid)No—

Responses

createManagedUser Responses
StatusDescription
201Tenant user created, or an identical idempotent request replayed.

Fields:id: string(uuid) display_id: string scope_id: string(uuid) tenant_id: string(uuid) username: string display_name: string email: string(email) | null(email) phone: string | null status: string: active / disabled role: string: tenant_owner / tenant_viewer group_id: string(uuid) | null(uuid) group_name: string | null metadata?: ManagedUserMetadata verification?: ManagedUserVerification reseller?: ManagedUserReseller revision: integer(int64) created_at: string(date-time) updated_at: string(date-time)

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
409The requested state conflicts with an existing resource or idempotency fact.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

PATCH /v1/admin/users

Atomically update tenant users

operationId
batchUpdateManagedUsers
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Applies the complete array or no changes. Disabling a user revokes every refresh family and invalidates existing access sessions immediately.

Parameters

batchUpdateManagedUsers Parameters
NameInTypeRequiredDescription
includequerystring: user_metadataNoSet to user_metadata to include administrator-only remark and QQ fields. Omission preserves the original fifteen-field representation. Unknown or repeated values are rejected. This representation choice does not change mutation idempotency; a historical receipt may omit metadata, in which case read the current resource before editing these fields.
Idempotency-KeyheaderstringYes—
X-Request-IDheaderstringNoCaller-stable write attempt identifier. Reuse it only with the same idempotency key and body.
traceparentheaderstringNoW3C trace context preserved across an exact retry.

Request body

application/json · Required:Yes

Responses

batchUpdateManagedUsers Responses
StatusDescription
200Users updated in request order, or an identical idempotent request replayed.

Fields:items: array<ManagedUser>

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/admin/users/{id}

Get one tenant user

operationId
getManagedUser
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

A platform identity or an unknown tenant user produces the same 404 response.

Parameters

getManagedUser Parameters
NameInTypeRequiredDescription
includequerystring: user_metadataNoSet to user_metadata to include administrator-only remark and QQ fields. Omission preserves the original fifteen-field representation. Unknown or repeated values are rejected. This representation choice does not change mutation idempotency; a historical receipt may omit metadata, in which case read the current resource before editing these fields.
idpathstring(uuid)Yes—

Responses

getManagedUser Responses
StatusDescription
200Tenant user details.

Fields:id: string(uuid) display_id: string scope_id: string(uuid) tenant_id: string(uuid) username: string display_name: string email: string(email) | null(email) phone: string | null status: string: active / disabled role: string: tenant_owner / tenant_viewer group_id: string(uuid) | null(uuid) group_name: string | null metadata?: ManagedUserMetadata verification?: ManagedUserVerification reseller?: ManagedUserReseller revision: integer(int64) created_at: string(date-time) updated_at: string(date-time)

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

PATCH /v1/admin/users/{id}

Update tenant user profile, status, and role

operationId
updateManagedUser
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Disabling a user revokes every refresh family and invalidates existing access sessions immediately.

Parameters

updateManagedUser Parameters
NameInTypeRequiredDescription
includequerystring: user_metadataNoSet to user_metadata to include administrator-only remark and QQ fields. Omission preserves the original fifteen-field representation. Unknown or repeated values are rejected. This representation choice does not change mutation idempotency; a historical receipt may omit metadata, in which case read the current resource before editing these fields.
idpathstring(uuid)Yes—
Idempotency-KeyheaderstringYes—
X-Request-IDheaderstringNoCaller-stable write attempt identifier. Reuse it only with the same idempotency key and body.
traceparentheaderstringNoW3C trace context preserved across an exact retry.

Request body

application/json · Required:Yes

updateManagedUser Request body
NameTypeRequiredDescription
expected_revisioninteger(int64)Yes—
display_namestringYes—
emailstring(email) | null(email)Yes—
phonestring | nullYes—
statusstring: active / disabledYes—
remarkstring | nullNoAdministrator-only remark, trimmed at both ends. Internal tabs and line breaks are preserved; other control characters are rejected. Null or whitespace-only input clears the stored value. Length counts Unicode code points.
qqstring | nullNoTrimmed QQ contact text, preserving leading zeroes. Not a login identifier and not unique. Control characters are rejected; null or whitespace-only input clears the stored value. Length counts Unicode code points.
rolestring: tenant_owner / tenant_viewerYes—
group_idstring(uuid) | null(uuid)No—

Responses

updateManagedUser Responses
StatusDescription
200User updated, or an identical idempotent request replayed.

Fields:id: string(uuid) display_id: string scope_id: string(uuid) tenant_id: string(uuid) username: string display_name: string email: string(email) | null(email) phone: string | null status: string: active / disabled role: string: tenant_owner / tenant_viewer group_id: string(uuid) | null(uuid) group_name: string | null metadata?: ManagedUserMetadata verification?: ManagedUserVerification reseller?: ManagedUserReseller revision: integer(int64) created_at: string(date-time) updated_at: string(date-time)

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

GET /v1/admin/users/{id}/login-security

Read the selected tenant user's login security policy

operationId
getManagedUserLoginSecurity
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Requires an active primary platform bearer session and identity.users.manage. API keys and impersonation sessions are rejected. A missing policy returns revision 0, none, and an empty allowlist.

Parameters

getManagedUserLoginSecurity Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant membership scope. Duplicate or unknown query parameters are rejected.

Responses

getManagedUserLoginSecurity Responses
StatusDescription
200Independent policy, without user profile or contact information.

Fields:user_id: string(uuid) tenant_scope_id: string(uuid) revision: integer(int64) login_verification: string: none / sms / email login_allowlist: array<string>

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
503A required dependency is unavailable.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

PUT /v1/admin/users/{id}/login-security

Replace a tenant user's login security policy

operationId
updateManagedUserLoginSecurity
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Same primary-session authorization as GET. The policy uses its own revision, receipt and audit; it does not change users.revision or existing user-write receipts. All fields are required. Empty allowlist disables the source restriction; none disables the additional login code. Email/SMS require a bound contact and a configured enabled channel. Source restrictions apply to new password and code logins, not existing sessions, refresh or API keys. Once a policy is enabled, rolling back to a binary without the login gate is unsafe. The service never silently clears a policy to permit rollback.

Parameters

updateManagedUserLoginSecurity Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant membership scope. Duplicate or unknown query parameters are rejected.
Idempotency-KeyheaderstringYes—
X-Request-IDheaderstringNoCaller-stable write attempt identifier. Reuse it only with the same idempotency key and body.
traceparentheaderstringNoW3C trace context preserved across an exact retry.

Request body

application/json · Required:Yes

updateManagedUserLoginSecurity Request body
NameTypeRequiredDescription
expected_revisioninteger(int64)Yes—
login_verificationstring: none / sms / emailYes—
login_allowlistarray<string>YesIPv4/IPv6 addresses or CIDR prefixes (for example 203.0.113.0/24). Ports, zones and empty entries are rejected. The service unmaps IPv4-mapped IPv6, masks prefixes to their network, collapses full-length prefixes to the address, deduplicates and sorts. Empty clears the restriction.

Responses

updateManagedUserLoginSecurity Responses
StatusDescription
200Saved policy or exact original receipt on replay. Clearing retains and increments its revision.

Fields:user_id: string(uuid) tenant_scope_id: string(uuid) revision: integer(int64) login_verification: string: none / sms / email login_allowlist: array<string>

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
422login_security_contact_required; the selected channel has no bound contact.
503A required dependency is unavailable.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

GET /v1/admin/users/{id}/secondary-verification

Read the selected tenant user's secondary identity verification request

operationId
getManagedUserSecondaryVerification
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Same primary-session authorization as login-security. A missing request returns revision 0, disabled, expiry_action none.

Parameters

getManagedUserSecondaryVerification Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant membership scope. Duplicate or unknown query parameters are rejected.

Responses

getManagedUserSecondaryVerification Responses
StatusDescription
200Request with derived completion state.

Fields:user_id: string(uuid) tenant_scope_id: string(uuid) revision: integer(int64) enabled: boolean deadline: string(date-time) | null expiry_action: string: none / lock_sites requested_at: string(date-time) | null completed: boolean enforced_at: string(date-time) | null

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
503A required dependency is unavailable.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

PUT /v1/admin/users/{id}/secondary-verification

Replace a tenant user's secondary identity verification request

operationId
updateManagedUserSecondaryVerification
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Own revision, receipt and audit; users.revision is unchanged. Switching it on records requested_at and enqueues the identity.secondary_verification email/SMS notice in the same transaction; editing an active request does not notify again. The user completes it with an approved personal_reverification created after requested_at. expiry_action lock_sites requires a deadline; when the deadline passes without completion the control plane stops the user's sites (disables and locks them, then republishes so the nodes stop serving them). Once the reverification is approved, or the request is switched off or its deadline moved into the future, exactly the changes it made are undone and the scope is republished; sites stopped or locked for other reasons are left as they are. Disabling requires deadline null and expiry_action none.

Parameters

updateManagedUserSecondaryVerification Parameters
NameInTypeRequiredDescription
idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant membership scope. Duplicate or unknown query parameters are rejected.
Idempotency-KeyheaderstringYes—
X-Request-IDheaderstringNoCaller-stable write attempt identifier. Reuse it only with the same idempotency key and body.
traceparentheaderstringNoW3C trace context preserved across an exact retry.

Request body

application/json · Required:Yes

updateManagedUserSecondaryVerification Request body
NameTypeRequiredDescription
expected_revisioninteger(int64)Yes—
enabledbooleanYes—
deadlinestring(date-time) | nullNo—
expiry_actionstring: none / lock_sitesYes—

Responses

updateManagedUserSecondaryVerification Responses
StatusDescription
200Saved request or exact original receipt on replay.

Fields:user_id: string(uuid) tenant_scope_id: string(uuid) revision: integer(int64) enabled: boolean deadline: string(date-time) | null expiry_action: string: none / lock_sites requested_at: string(date-time) | null completed: boolean enforced_at: string(date-time) | null

400The request body or parameters are invalid.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
503A required dependency is unavailable.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.

↑ Back to list

GET /v1/admin/users/{user_id}/api-keys

List a tenant user's API key metadata

operationId
listManagedUserAPIKeys
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Platform session-only endpoint requiring api_keys.admin.manage. Each item includes the exact persisted IP allowlist; secrets are never returned.

Parameters

listManagedUserAPIKeys Parameters
NameInTypeRequiredDescription
user_idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant scope selected by the platform administrator.
limitqueryintegerNo—
statusquerystring: pending_activation / active / revokedNo—
namequerystringNo—
key_idquerystringNo—
cursorquerystringNo—
offsetqueryintegerNoPage-number access (canonical non-negative integer, 0-10000). Cannot be combined with cursor; an offset past the end returns empty items with total.
usablequerystring: trueNoOnly `true` is accepted. Keeps keys that can authenticate at the page snapshot: status active and expires_at absent or later than snapshot_at. An expired key keeps its active lifecycle status as history, so status=active alone does not mean usable. Combinable only with status=active or no status. Clients judge expiry against the response Date header (server clock), not their own clock.

Responses

listManagedUserAPIKeys Responses
StatusDescription
200Target user's API key metadata.

Fields:items: array<APIKey> next_cursor: string has_more: boolean total?: integer

400Malformed JSON, UUID, revision, CIDR, duplicate or overlapping prefix, or more than 32 prefixes. Validation params expose only field indexes and counts, never any submitted CIDR, secret, digest, or matching prefix.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/admin/users/{user_id}/api-keys

Create pending API key metadata for a tenant user

operationId
createPendingManagedUserAPIKey
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Platform session-only endpoint requiring api_keys.admin.manage. No secret is created or returned. The target user must activate the key with their own bearer session before it can authenticate. An unknown result must be retried with the unchanged body, If-Match revision, and Idempotency-Key.

Parameters

createPendingManagedUserAPIKey Parameters
NameInTypeRequiredDescription
user_idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant scope selected by the platform administrator.
Idempotency-KeyheaderstringYes—
If-MatchheaderstringYesCollection creation precondition. Must be the quoted revision zero value.

Request body

application/json · Required:Yes

createPendingManagedUserAPIKey Request body
NameTypeRequiredDescription
namestringYes—
scopesarray<string>Yes—
ip_allowlistarray<string>NoCanonical network CIDRs only: no host bits, zones, IPv4-mapped IPv6, duplicate prefixes, or overlaps. Empty means unrestricted.
expires_atstring(date-time)NoMust be in the future and no more than 366 days from the server clock.
pending_ttl_secondsinteger(int64)No—

Responses

createPendingManagedUserAPIKey Responses
StatusDescription
201Pending API key metadata without secret material.

Fields:id: string(uuid) key_id: string key_prefix: string scope_id: string(uuid) tenant_id: string(uuid) user_id: string(uuid) name: string scopes: array<string> unavailable_scopes?: array<string> ip_allowlist: array<string> status: string: pending_activation / active / revoked pending_expires_at?: string(date-time) expires_at?: string(date-time) last_used_at?: string(date-time) activated_at?: string(date-time) revoked_at?: string(date-time) revision: integer(int64) created_at: string(date-time) updated_at: string(date-time)

400Malformed JSON, UUID, revision, CIDR, duplicate or overlapping prefix, or more than 32 prefixes. Validation params expose only field indexes and counts, never any submitted CIDR, secret, digest, or matching prefix.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
503A required dependency is unavailable.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list

POST /v1/admin/users/{user_id}/api-keys/{key_id}/revoke

Revoke a tenant user's API key

operationId
revokeManagedUserAPIKey
Auth
  • Session: the Bearer session of a signed-in control plane user, used by the customer in their own control plane; a plugin must never ask for it.
Required permissions

The contract has no separate permission annotation; see the description below and the 403 response.

Description (from the contract)

Platform session-only endpoint. Administrators cannot activate, rotate, or read key secrets. The body carries the exact persisted IP allowlist. An unknown result must be retried with the unchanged body, If-Match revision, and Idempotency-Key.

Parameters

revokeManagedUserAPIKey Parameters
NameInTypeRequiredDescription
user_idpathstring(uuid)Yes—
key_idpathstring(uuid)Yes—
tenant_scope_idquerystring(uuid)YesExact tenant scope selected by the platform administrator.
Idempotency-KeyheaderstringYes—
If-MatchheaderstringYes—

Request body

application/json · Required:Yes

revokeManagedUserAPIKey Request body
NameTypeRequiredDescription
ip_allowlistarray<string>YesCanonical network CIDRs only: no host bits, zones, IPv4-mapped IPv6, duplicate prefixes, or overlaps. Empty means unrestricted.
grant_all_scopesbooleanNoRotate only. When true, the rotation also replaces the key scopes with every permission the current session may grant to an API key (the simple-mode "reset key"). It is part of the idempotency binding. Other operations reject true with 400 invalid_request.

Responses

revokeManagedUserAPIKey Responses
StatusDescription
200Revoked key metadata.

Fields:id: string(uuid) key_id: string key_prefix: string scope_id: string(uuid) tenant_id: string(uuid) user_id: string(uuid) name: string scopes: array<string> unavailable_scopes?: array<string> ip_allowlist: array<string> status: string: pending_activation / active / revoked pending_expires_at?: string(date-time) expires_at?: string(date-time) last_used_at?: string(date-time) activated_at?: string(date-time) revoked_at?: string(date-time) revision: integer(int64) created_at: string(date-time) updated_at: string(date-time)

400Malformed JSON, UUID, revision, CIDR, duplicate or overlapping prefix, or more than 32 prefixes. Validation params expose only field indexes and counts, never any submitted CIDR, secret, digest, or matching prefix.
401Authentication failed or the session is invalid.
403The authenticated principal is not allowed to perform the action.
404The requested resource was not found.
409The requested state conflicts with an existing resource or idempotency fact.
503A required dependency is unavailable.
500The request could not be completed because of an internal failure.

What to do on failure

  • 400 Fix the parameters or body per the field list; do not retry unchanged.
  • 401 Check the credential format and whether it expired or was rotated.
  • 403 Check the key scopes, the owner’s current permissions and the tenant scope; never switch to a more privileged account.
  • 404 The resource does not exist or belongs to another tenant.
  • 409 Read the current state first; a retry of the same operation keeps the original Idempotency-Key and body.
  • 503 A dependency is unavailable: retry later with the original Idempotency-Key.
  • 500 Outcome unknown: read back by ID or list first, then decide whether to retry with the original Idempotency-Key.

↑ Back to list