# List an organization's OIDC clients (admin)

`GET /v1/admin/orgs/{slug}/clients`

Returns one page of the OIDC clients that belong to `slug`'s organization,
using opaque cursor (keyset) pagination. Bound the page size with `limit`
and choose an ordering with `sort` (see `x-sort-fields` for what this
endpoint accepts; the registration id is appended so the ordering is
total). Then walk the listing by passing the previous response's
`page.next_cursor` back as `cursor` for as long as `page.has_more` is
true; `page.prev_cursor` steps back the same way. Defaults to client id
order; `display_name` orders by the name case-insensitively.

**Which clients belong to an organization.** Every client belongs to
exactly one organization, decided once, when the client is first
registered, and never moved by a later write. A client the server
provisioned itself (an organization's admin console and machine client)
or one registered dynamically (RFC 7591) belongs to the organization the
server recorded for it at registration. Any other client — one an
operator registered over the control plane — belongs to the organization
whose issuer it was registered under, whatever labels it carries, or to
the main organization when that issuer is no organization's.

`q` narrows the listing to the clients whose client id or display name
starts with it, case-insensitively. The filters compose as a
conjunction; a filter taking several values matches any of them. A
cursor is bound to the search and the filters it was issued for, so send
them with it; the order it carries itself.

`display_name_markers` names what about a client's display name is there
to be misread — a direction override, a control character, invisible
characters, padding, a name past the length the sign-in pages show, or
markup — and is empty for an ordinary name.

Requires the `nauthera.clients:read` scope and the `clients.read`
permission; the listing is confined to `slug`'s organization. Secrets,
secret hashes and registration access tokens are never returned.

## Authorization

- [Bearer token](https://www.nauthera.io/docs/v1/api#auth-bearerAuth) (`bearerAuth`) and [OAuth 2.0](https://www.nauthera.io/docs/v1/api#auth-oauth2) (`oauth2`) with scope `nauthera.clients:read`

Authorization header: The access token, as `Bearer <token>` (RFC 6750 §2.1) or, for a sender-constrained token, `DPoP <token>` (RFC 9449 §7.1). A token minted with a `cnf.jkt` confirmation is only accepted together with a `DPoP` proof signed by that key, whichever of the two schemes carries it.

Requires the permission [`clients.read`](https://www.nauthera.io/docs/v1/api#permission-clients.read): Read an organization's OIDC clients.

This endpoint is rate limited; it answers `429` when a limit is hit.

## Path parameters

- `slug` (string, required): The organization slug. It names the TENANT OF RECORD for the operation: the rows it reads and writes, the policy its secrets are derived under, and the organization its audit record is filed against all come from this organization. A token is admitted only through its own slug, except a main-org token, which may be admitted through any — so cross-tenant administration is performed through the TARGET tenant's slug, never by naming its resources through another. A token reaching for a slug it may not be admitted through is refused identically whether that organization exists or not. Constraints: 1–64 characters.

## Query parameters

- `limit` (integer, optional): Maximum number of items to return in one page (1–200; default 50). A value outside that range is rejected with a 400. It may be changed freely between pages of the same walk — a cursor marks a position, not a page number. Default: `50`. Constraints: between 1 and 200.
- `sort` (string, optional): Ordering for the listing: a comma-separated list of fields, most significant first, a leading `-` marking a descending term. For example `sort=last_name,-first_name` sorts by last name ascending, then by first name descending. Constraints: at most 256 characters; pattern `^-?[a-z][a-z0-9_]*(,-?[a-z][a-z0-9_]*)*$`. Sortable fields: `client_id`, `created_at`, `display_name`, `id`. Prefix a field with `-` to sort descending.

  Which fields a given endpoint accepts is listed in its `x-sort-fields`
  extension; naming anything else is a 400. A field may appear only once.

  The server always appends the resource's primary key as a final term, so
  the ordering is TOTAL — rows that tie on every field you named still have
  a defined relative order, without which a page could skip or repeat them.
  The full ordering, including that appended term, is echoed as `page.sort`.

  Send it on the FIRST request of a walk only: every cursor records the
  ordering it was issued under, so it carries forward automatically, and a
  `sort` that contradicts the supplied `cursor` is rejected with a 400
  rather than silently reordering mid-walk.
- `cursor` (string, optional): Opaque keyset cursor identifying where a page begins. Omit it for the first page; afterwards pass the `next_cursor` (or `prev_cursor`) value from the previous response verbatim — the token itself records which direction it steps in, so there is no separate direction parameter. Constraints: at most 1024 characters.

  The token is server-defined and MUST be treated as opaque: it is bound
  to the listing and sort order that issued it, and a cursor that is
  malformed, tampered with, or belongs to a different listing or order is
  rejected with a 400 rather than silently paging through the wrong set.
- `q` (string, optional): Narrow the listing to the clients whose client id or display name starts with this text, compared case-insensitively. Every character is matched literally. A cursor is bound to the search it was issued for. Constraints: 2–100 characters.
- `type` (enum, optional): Only public clients, which hold no credential, or only confidential ones. One of: `"public"`, `"confidential"`.
- `auth_method` (array of enums, optional): Token endpoint authentication methods, comma-separated. One of: `"none"`, `"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`. Constraints: at most 4 items.
- `grant_type` (array of enums, optional): Grant types, comma-separated: a client registering any of them matches. One of: `"authorization_code"`, `"refresh_token"`, `"client_credentials"`, `"urn:ietf:params:oauth:grant-type:device_code"`. Constraints: at most 4 items.
- `source` (array of enums, optional): How the clients came to be registered, comma-separated. One of: `"operator"`, `"dynamic"`, `"provisioner"`. Constraints: at most 3 items.

## Headers

- `DPoP` (string, optional): DPoP proof JWT (RFC 9449 §4). REQUIRED on a request presenting a DPoP-bound access token, and it must be signed by the key named in the token's `cnf.jkt` and cover this request's method and URI. The proof is read from the request itself rather than from this decoded parameter, so every protected operation is covered whether or not it declares it.

## Responses

### 200 OK

One page of the organization's clients.

Content type: `application/json`

Headers:
- `Cache-Control` = `no-store`

One page of an organization's clients under cursor (keyset)
pagination: `items` holds the page, ordered by the request's `sort`,
and `page` says where it sits in the listing. Follow `page.next_cursor`
while `page.has_more` is true.

- `items` (array of objects, required): The clients on this page.

  Each item: An OIDC client as the admin API lists it: who it is, how it authenticates and what it may do. No secret, secret hash or registration access token is ever included.
  - `id` (string, required): The registration id (UUID): the server's id for this registration, stable across updates and distinct from `client_id`.
  - `client_id` (string, required): The OAuth client identifier relying parties present.
  - `display_name` (string, required): The name the client is shown under, as registered; empty when it registered none.
  - `display_name_markers` (array of enums, required): What about the display name is there to be misread, in a fixed order; empty for an ordinary name. One of: `"bidi"`, `"control"`, `"invisible"`, `"padded"`, `"overlong"`, `"markup"`.

    Each item: What about a client's display name is there to be misread: a direction override, isolate or mark (`bidi`), a control character (`control`), invisible characters (`invisible`), surrounding or repeated whitespace (`padded`), a name longer than the sign-in pages show (`overlong`), or markup (`markup`).
  - `type` (enum, required): Whether a client authenticates at the token endpoint: a public client holds no credential, a confidential one holds a secret or a key. One of: `"public"`, `"confidential"`.
  - `token_endpoint_auth_method` (enum, required): How a client authenticates at the token endpoint (RFC 7591 §2). One of: `"none"`, `"client_secret_basic"`, `"client_secret_post"`, `"private_key_jwt"`.
  - `grant_types` (array of enums, required): The grant types the client is registered for. One of: `"authorization_code"`, `"refresh_token"`, `"client_credentials"`, `"urn:ietf:params:oauth:grant-type:device_code"`.

    Each item: A grant type a client may use at the token endpoint (RFC 7591 §2).
  - `source` (enum, required): How a client came to be registered: by an operator over the control plane, by dynamic registration (RFC 7591), or by the server itself, as an organization's admin console and machine client. One of: `"operator"`, `"dynamic"`, `"provisioner"`.
  - `created_at` (string (date-time), required)
  - `updated_at` (string (date-time), required)
- `page` (object, required): Where one page sits in a cursor (keyset) paginated list, returned beside that page's `items`.

  Walk a list by following `next_cursor` for as long as `has_more` is true,
  passing the token back verbatim as the `cursor` query parameter. Keep the
  listing and its filters the same for the whole walk; `limit` MAY change
  between pages (a cursor marks a position, not a page number), and `sort`
  travels in the cursor so it need not be resent. `has_more` is
  authoritative: it is derived from whether a further row actually exists,
  so a page that happens to be full is not mistaken for a page that has a
  successor, and a walk never costs a trailing empty request. `prev_cursor`
  steps back the same way.

  A cursor is opaque — server-defined, bound to this listing and sort
  order, and not parseable by clients. It stays valid across page-size
  changes but not across a change of sort order or filters; a cursor that
  does not belong to the request is rejected with a 400 rather than
  silently paging through the wrong set.

  Keyset paging is stable under concurrent writes, with one qualification.
  A row whose SORT KEY does not change is returned exactly once for the
  whole walk. Rows created or deleted mid-walk may or may not appear,
  depending on which side of the cursor they fall — and so may a row whose
  sort key is UPDATED mid-walk, since that moves it across the boundary: it
  can be seen twice or missed. Sorting by a field that does not change (the
  default id ordering, or `created_at`) avoids this entirely.
  - `limit` (integer, required): The page size in effect: the `limit` that was sent, or the server's default when it was omitted. Echoed so a client resuming from a stored cursor knows the page size without having to remember it. Example: `50`.
  - `sort` (string, required): The ordering this walk is pinned to, in the `sort` parameter's syntax and INCLUDING the primary-key term the server appends to make it total. Cursors carry it, so it need only be sent on the first request. Example: `"last_name,-first_name,id"`.
  - `has_more` (boolean, required): Whether a page follows this one and `next_cursor` can reach it. When false this is the last page and `next_cursor` is absent.
  - `has_prev` (boolean, required): Whether a page precedes this one and `prev_cursor` can reach it. False on the first page of a walk.

    Both flags report REACHABILITY, not bare existence. A cursor that overshoots the set — a stale bookmark, or rows deleted mid-walk — returns an empty page with both flags false even though rows precede it, because an empty page has no row to anchor a cursor on. Restart the walk if you land there; a client following `has_more` never does.
  - `next_cursor` (string, optional): Opaque cursor for the next page. Present exactly when `has_more` is true, and ABSENT (the field is omitted, not null) otherwise. Pass it back verbatim as the `cursor` query parameter; never parse it. Constraints: at most 512 characters.
  - `prev_cursor` (string, optional): Opaque cursor for the previous page. Present exactly when `has_prev` is true, and absent otherwise. Passed back as `cursor`, exactly like `next_cursor` — the token itself records which way it steps. Constraints: at most 512 characters.

### 400 Bad Request

The pagination parameters, the search or a filter were invalid — a malformed or foreign cursor, a cursor contradicting `sort`, a `sort` naming a field this endpoint does not accept or naming one twice, a `limit` outside its declared range, a `q` outside its declared length, or a filter value outside its vocabulary.

Content type: `application/problem+json`

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

### 401 Unauthorized

Problem details (RFC 9457) with an RFC 6750 / RFC 9449 challenge.

Content type: `application/problem+json`

Headers:
- `Cache-Control` = `no-store`
- `WWW-Authenticate` (string)
- `DPoP-Nonce` (string)

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

### 403 Forbidden

Problem details (RFC 9457) with an RFC 6750 / RFC 9449 challenge.

Content type: `application/problem+json`

Headers:
- `Cache-Control` = `no-store`
- `WWW-Authenticate` (string)
- `DPoP-Nonce` (string)

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

### 429 Too Many Requests

Too many requests.

Content type: `application/problem+json`

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

### Error

Problem details (RFC 9457) with an RFC 6750 / RFC 9449 challenge.

Content type: `application/problem+json`

Headers:
- `Cache-Control` = `no-store`
- `WWW-Authenticate` (string)
- `DPoP-Nonce` (string)

RFC 9457 (formerly RFC 7807) problem details (application/problem+json). `code` is a stable machine-readable slug for the problem kind (it mirrors the last path segment of `type`), so consumers can branch on it without parsing prose. `type` is `https://nauthera.io/problems/<code>`, which resolves to the code's runbook: why it happened, who is affected and what to do (RFC 9457 §3.1.1). A problem without a code has `about:blank`. `errors` is present on validation failures and lists every offending field.

- `title` (string, required): Example: `"Request validation failed"`.
- `status` (integer, required): Example: `400`.
- `type` (string (uri), optional): Example: `"https://nauthera.io/problems/validation_error"`.
- `detail` (string, optional): Example: `"One or more fields did not satisfy the API schema."`.
- `code` (enum, optional): The kind of problem, as a stable machine-readable slug a client branches on and translates rather than parsing `title` or `detail`, which are English prose for logs. A problem whose status says everything the server knows carries no `code`. One of: `"invalid_request"`, `"invalid_credentials"`, `"forbidden"`, `"unauthorized"`, `"insufficient_user_authentication"`, `"protected_account"`, `"password_held_by_directory"`, `"last_role_administrator"`, `"invalid_code"`, `"too_many_requests"`, `"too_many_attempts"`, `"account_locked"`, `"account_unavailable"`, `"already_enrolled"`, `"registration_disabled"`, `"registration_conflict"`, `"captcha_failed"`, `"invalid_reset_link"`, `"password_reused"`, `"password_too_short"`, `"password_too_long"`, `"password_compromised"`, `"invalid_verification_link"`, `"invalid_invitation_link"`, `"mail_relay_missing"`, `"email_unverified"`, `"not_found"`, `"conflict"`, `"unavailable"`, `"busy"`, `"window_too_large"`, `"too_many_series"`, `"internal_error"`, `"rate_limited"`, `"malformed"`, `"body_too_large"`, `"required"`, `"validation_error"`, `"unknown_org"`, `"invalid_token"`, `"invalid_dpop_proof"`, `"use_dpop_nonce"`, `"server_error"`.

  `validation_error` is the one code whose message is not a sentence about
  the code itself: the request failed the schema, and the specifics are
  the `errors` list — one entry per offending field — which a form renders
  on those fields. `required` and `malformed` are spelled like two of the
  per-field violation codes (`FieldError.code`) but mean something else;
  the two vocabularies are told apart by position, never by spelling.

  **Compatibility:** this is a CLOSED enum, with the same cost as
  `AuditAction`: a client generated against an older version of this
  document rejects a problem carrying a code added after it was built.
  Regenerate on upgrade, or decode the field as a plain string. It is
  enumerated anyway so that what a client must translate is knowable
  from the contract alone.
- `instance` (string, optional): Example: `"/introspect"`.
- `request_id` (string, optional): Example: `"8d94ed49-1caf-4ab3-9594-557142f2d023"`.
- `trace_id` (string, optional): Distributed-trace id (hex) for correlating this response with traces and logs. Present only when tracing is enabled and the request was recorded. Opaque and safe to log/share. Example: `"4bf92f3577b34da6a3ce929d0e0e4736"`.
- `errors` (array of objects, optional): Field-level violations (present for validation errors).

  Each item: A single field-level validation violation.
  - `field` (string, required): Offending field, dotted for nested bodies (e.g. child.id). Example: `"token_type_hint"`.
  - `code` (string, required): Machine-readable violation code: required, too_short, too_long, pattern, invalid_format, not_allowed, minimum, maximum, multiple_of, too_few, too_many, not_unique, malformed. Example: `"not_allowed"`.
  - `message` (string, required): Example: `"field token_type_hint must be one of [access_token, refresh_token]"`.

## Example request

```bash
curl -g 'https://auth.example.com/v1/admin/orgs/{slug}/clients' \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

## Example response (200)

```json
{
  "items": [
    {
      "id": "string",
      "client_id": "string",
      "display_name": "string",
      "display_name_markers": [
        "bidi"
      ],
      "type": "public",
      "token_endpoint_auth_method": "none",
      "grant_types": [
        "authorization_code"
      ],
      "source": "operator",
      "created_at": "2026-01-15T09:30:00Z",
      "updated_at": "2026-01-15T09:30:00Z"
    }
  ],
  "page": {
    "limit": 50,
    "sort": "last_name,-first_name,id",
    "has_more": false,
    "has_prev": false
  }
}
```
