openapi: 3.2.0 info: title: KnoxCall Client Management Request Logs API version: '1.0' description: 'The KnoxCall Client Management API provides programmatic access to manage your API gateway resources including routes, secrets, clients, environments, webhooks, and API keys. ## Authentication All requests must include an OAuth 2.1 access token **or** a legacy API key. The recommended path for new integrations is the first-party SDKs, which mint, cache, and refresh OAuth tokens for you (start with `knoxcall login` on a developer machine, or `KNOXCALL_CLIENT_ID` / `KNOXCALL_CLIENT_SECRET` in CI). You can authenticate using any of: - **Authorization header (OAuth 2.1 bearer token — recommended)**: `Authorization: Bearer ` - **Authorization header (legacy API key)**: `Authorization: Bearer tk_xxx_yyy` - **x-api-key header (legacy API key)**: `x-api-key: tk_xxx_yyy` OAuth 2.1 access tokens (`kc_` prefix) are minted at the root-host token endpoint `https://api.knoxcall.com/oauth/token` (not under `/v1`) using the `client_credentials` or `authorization_code` grant. See the `OAuth2` security scheme and the `/oauth/*` endpoints. Some resources that are managed exclusively through OAuth reject API-key auth with a `403 use_oauth` error. Long-lived API keys remain fully supported. They come in three types: - **Standard keys** (`tk_` prefix) are used on the production API (`api.knoxcall.com`). - **Test keys** (`tk_` prefix, type=test) are used on the sandbox API (`sandbox.knoxcall.com`). - **Enterprise Access Keys** (`AKE` prefix) follow the format `AKE[16chars]:[40chars]`. Using a test key on the production API (or vice versa) will return a `403 wrong_key_type` error. ## Request IDs Every response — success or error — includes an `X-Request-Id` response header (a UUID). Its value is identical to the `request_id` field in the response body (`meta.request_id` on success, `error.request_id` on error). Quote it when contacting support. ## API Versioning The API is versioned on two axes: - **Major version — the `/v1` path prefix.** Breaking changes ship under a new major (`/v2`). `/v1` never receives a breaking change. - **Minor version — the `KnoxCall-Version` header (dated, `YYYY-MM-DD`).** Send `KnoxCall-Version: 2026-08-05` to pin the behaviour of a specific dated release. Omit the header to get the newest minor version. Every response echoes the resolved version back in a `KnoxCall-Version` response header. Within a major version, **additive changes are not breaking** and may appear without a new dated version: new endpoints, new optional request fields, new response fields, new `error.type` values, and new enum members. Clients must tolerate unknown response fields and unknown `error.type` values (see the `ErrorResponse` schema). An **unknown or malformed** `KnoxCall-Version` value returns `400` with `error.type: invalid_api_version`. ## Rate Limiting API keys can have optional rate limits configured. When a limit is configured, the following headers are emitted on **every** response (not only `429`s): - `X-RateLimit-Limit` -- maximum requests allowed per window - `X-RateLimit-Remaining` -- remaining requests in the current window - `X-RateLimit-Reset` -- epoch seconds at which the window resets When the limit is exceeded the API returns `429` (`rate_limit_exceeded` / `rate_limited`) and additionally sets `Retry-After` (seconds until the window resets). ## DPoP sender-constrained tokens, and the server nonce A token minted with a `cnf.jkt` binding (DPoP, RFC 9449) requires a `DPoP` proof header on every request, signed over the request''s method and canonical public URL. **Every response to a request that carried a `DPoP` header also carries a `DPoP-Nonce` response header** -- mints, refusals and successful calls alike, on `POST /oauth/token`, `/v1`, the tenant data plane, the self-hosted proxy and the AI gateway. The value is stateless and changes every minute; the server accepts the current and the previous minute''s, so a nonce is good for 60-120 seconds.' contact: name: KnoxCall Support url: https://knoxcall.com email: support@knoxcall.com license: name: Proprietary url: https://knoxcall.com/terms servers: - url: https://api.knoxcall.com/v1 description: Production - url: https://sandbox.knoxcall.com/v1 description: Sandbox (test keys only) security: - OAuth2: [] - BearerAuth: [] - ApiKeyAuth: [] tags: - name: Request Logs description: The per-call proxy request log, and Merkle inclusion proofs that make an anchored entry provable to a third party. paths: /logs: get: operationId: listRequestLogs summary: Request log feed (cursor) description: 'A keyset-cursor feed of proxied API requests — the per-call log, as opposed to `/audit-logs`, which records configuration CHANGES. Ordered by the monotonic row id and resumed from an opaque cursor, for the same reason the audit event feed is: offset pagination over a table that is being written to skips and repeats rows with no way to tell which. **Contract** - **Ordering** — ascending `cursor`, stable across calls. - **Delivery** — AT LEAST ONCE. Dedupe on `request_id`. - **Freshness** — trails real time by `meta.watermark_seconds`. - **Termination** — `next_cursor` is `null` when you have drained everything outside the watermark. Poll again later with your last non-null cursor. **What this endpoint does not return.** Captured request and response BODIES are never on this surface at any permission level. They are available only from the audited admin route, which gates them on `log:read_payload`. **Identity fields.** `src_ip`, `matched_client_id` and `identification_method` require the `log:read_identity` permission. When it is denied the fields are ABSENT from each row — not null — and `meta._redacted` contains `identity`.' tags: - Request Logs parameters: - name: cursor in: query schema: type: string description: The opaque `meta.next_cursor` from a previous response. Omit to start at the beginning. - name: limit in: query schema: type: integer minimum: 1 maximum: 1000 description: Rows per page (default 100). - name: route_id in: query schema: type: string format: uuid description: Only requests handled by this route. - name: status_code in: query schema: type: integer minimum: 100 maximum: 599 description: Only requests that returned this status. responses: '200': description: A page of request log rows, oldest first. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/RequestLog' meta: type: object properties: next_cursor: type: - string - 'null' description: Pass as `cursor` on the next call. `null` means you have drained the feed to the watermark. limit: type: integer delivery: type: string example: at_least_once dedupe_on: type: string example: request_id watermark_seconds: type: integer _redacted: type: array items: type: string description: Tiers withheld from every row in this response. `identity` means the identity fields were omitted. '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /logs/{request_id}: get: operationId: getRequestLog summary: Get one request log entry description: 'Returns a single proxied request by its `request_id` — the same value KnoxCall returns in the `X-Request-Id` response header.' tags: - Request Logs parameters: - name: request_id in: path required: true schema: type: string format: uuid responses: '200': description: The request log entry. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/RequestLog' meta: type: object properties: _redacted: type: array items: type: string '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /logs/{request_id}/proof: get: operationId: getRequestLogProof summary: Merkle inclusion proof for a request description: 'Returns cryptographic evidence that a request log entry existed, in the form it is returned in, at the time it was anchored. **How the anchoring works.** On a schedule, KnoxCall takes a contiguous range of request log rows, hashes them into an RFC 6962-style Merkle tree, and appends the root to its hash-chained critical audit log. That chain is verified daily, so the root is evidence that is expensive to alter after the fact. This endpoint hands you the sibling hashes needed to walk your own row up to that root. **Verify it yourself.** Recompute the leaf hash from the returned `leaf_fields` using the scheme in `verification.note`, then fold in each `proof` step (`right: true` means the sibling goes on the right) and compare with `anchor.merkle_root`. `anchor.chain_row_hash` ties that root to its row in the audit chain. **Outcomes.** Always `200` when the request exists and is yours; read `anchored` and `verified` rather than the status code. | State | Meaning | |---|---| | `anchored: false`, `reason: not_yet_anchored` | Too recent. Retry later. | | `verified: true` | `proof` is present and reaches the anchored root. | | `verified: false`, `reason: range_incomplete` | Rows the anchor covered have since been deleted by retention, so the tree can no longer be recomputed and no proof can be produced. Expected on old entries; not a sign of tampering. | | `verified: false`, `reason: range_grew` | The range now holds more rows than the anchor counted. What that means depends on how the anchor cut its range, and `detail` says which case applies. An anchor that sealed its range after every write in it had finished can only have gained a row by something other than ordinary traffic, either an insert that named its id or an id sequence that was set backwards: escalate, as for `root_mismatch`. An older anchor, one that records no cut rule, cut its range by timestamp and could leave a committed row out; it stays valid for the set it read, and the extra row is not covered by any anchor today. | | `verified: false`, `reason: root_mismatch` | The range reproduces the anchor''s leaf count but not its root — a row in it was ALTERED after anchoring. This is a tamper indication. Escalate. | A proof is never returned alongside a failed verification. **Retention caveat, stated plainly.** An anchor''s tree spans every tenant''s rows in its range, so retention deletion — including another customer''s — can make a specific proof unreproducible. The anchor itself is permanent and still attests the root it committed; what decays is the ability to demonstrate membership in it.' tags: - Request Logs parameters: - name: request_id in: path required: true schema: type: string format: uuid responses: '200': description: The proof, or a named reason why one cannot be produced. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/RequestLogProof' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' components: responses: NotFound: description: The requested resource was not found. headers: X-Request-Id: $ref: '#/components/headers/X-Request-Id' KnoxCall-Version: $ref: '#/components/headers/KnoxCall-Version' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: not_found message: Route not found. request_id: 550e8400-e29b-41d4-a716-446655440000 ValidationError: description: The request failed validation (always `400 validation_error`). A malformed idempotency key returns `400 invalid_idempotency_key`. headers: X-Request-Id: $ref: '#/components/headers/X-Request-Id' KnoxCall-Version: $ref: '#/components/headers/KnoxCall-Version' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: validation_error: summary: Request body failed validation value: error: type: validation_error message: name and target_base_url are required. request_id: 550e8400-e29b-41d4-a716-446655440000 invalid_idempotency_key: summary: Malformed idempotency key value: error: type: invalid_idempotency_key message: X-Idempotency-Key must be a non-empty string of at most 255 characters. request_id: 550e8400-e29b-41d4-a716-446655440000 InternalError: description: An unexpected server error occurred. headers: X-Request-Id: $ref: '#/components/headers/X-Request-Id' KnoxCall-Version: $ref: '#/components/headers/KnoxCall-Version' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: internal_error message: An unexpected error occurred. request_id: 550e8400-e29b-41d4-a716-446655440000 Unauthorized: description: Authentication is required or the provided API key is invalid. headers: X-Request-Id: $ref: '#/components/headers/X-Request-Id' KnoxCall-Version: $ref: '#/components/headers/KnoxCall-Version' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: missing_key: summary: No API key provided value: error: type: authentication_required message: 'API key is required. Use Authorization: Bearer or x-api-key header.' request_id: 550e8400-e29b-41d4-a716-446655440000 invalid_key: summary: Invalid API key value: error: type: invalid_api_key message: Invalid API key. request_id: 550e8400-e29b-41d4-a716-446655440000 RateLimited: description: 'Too many requests. Retry after the indicated time. The `X-RateLimit-*` headers are also present on non-429 responses whenever a limit is configured. ' headers: X-Request-Id: $ref: '#/components/headers/X-Request-Id' KnoxCall-Version: $ref: '#/components/headers/KnoxCall-Version' X-RateLimit-Limit: $ref: '#/components/headers/X-RateLimit-Limit' X-RateLimit-Remaining: $ref: '#/components/headers/X-RateLimit-Remaining' X-RateLimit-Reset: $ref: '#/components/headers/X-RateLimit-Reset' Retry-After: $ref: '#/components/headers/Retry-After' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: rate_limit_exceeded message: API rate limit exceeded. Please retry later. request_id: 550e8400-e29b-41d4-a716-446655440000 headers: X-RateLimit-Remaining: description: 'Remaining requests in the current window. Emitted on every response whenever a rate limit is configured for the authenticated key. ' schema: type: integer example: 999 KnoxCall-Version: description: 'The dated API version (`YYYY-MM-DD`) that served this response. Equals the value of the `KnoxCall-Version` request header when supplied, otherwise the newest version. ' schema: type: string pattern: ^\d{4}-\d{2}-\d{2}$ example: '2026-08-05' X-Request-Id: description: 'Unique identifier for this request (UUID). Present on **every** response and equal to the `request_id` field in the response body. Quote it when contacting support. ' schema: type: string format: uuid example: 550e8400-e29b-41d4-a716-446655440000 X-RateLimit-Limit: description: 'Maximum requests allowed per window. Emitted on every response whenever a rate limit is configured for the authenticated key. ' schema: type: integer example: 1000 X-RateLimit-Reset: description: 'Epoch seconds at which the current rate-limit window resets. Emitted on every response whenever a rate limit is configured for the authenticated key. ' schema: type: integer example: 1735689600 Retry-After: description: Seconds to wait before retrying. Set on `429` responses. schema: type: integer example: 30 schemas: RequestLogProof: type: object description: 'A Merkle inclusion proof for one request log row, or a named reason why one cannot be produced. Carries every field of `RequestLog` in addition to those below. ' properties: anchored: type: boolean description: Whether any anchor covers this row yet. verified: type: boolean description: Whether the anchored range still recomputes to the root the anchor recorded. Absent when `anchored` is false. reason: type: - string - 'null' enum: - not_yet_anchored - range_incomplete - range_grew - root_mismatch - row_not_in_range - anchor_range_too_large - null description: Present only when no proof is returned. See the endpoint description for what each value means. detail: type: string description: A sentence explaining `reason` in context. observed_leaf_count: type: integer description: Rows the range holds now, when that differs from what the anchor counted. recomputed_root: type: - string - 'null' description: The root the range produces now. Present only on `root_mismatch`. anchor: type: object description: The anchor row this proof stands on. properties: id: type: string format: uuid sequence_number: type: string description: Position in the hash-chained critical audit log, as a decimal string. anchored_at: type: string format: date-time algo: type: string example: sha256-rfc6962-merkle-v1 merkle_root: type: string description: Hex-encoded root committed by the anchor. leaf_count: type: integer description: Rows the anchor covered. Platform-wide for the window, attributable to no one; the proof's own length already reveals its order of magnitude. from_id: type: string to_id: type: string chain_row_hash: type: - string - 'null' description: Hex row hash of the anchor's entry in the audit chain. Ties the root to the chain that is verified daily. leaf_index: type: integer description: Position of this row among the anchor's leaves. leaf_hash: type: string description: Hex SHA-256 of this row's canonical leaf bytes. proof: type: array description: Sibling hashes from leaf to root. Absent whenever `verified` is not true. items: type: object properties: hash: type: string description: Hex sibling hash. right: type: boolean description: True when the sibling is the RIGHT operand, i.e. concatenate as (accumulator, sibling). verification: type: object description: Everything needed to redo this computation without trusting KnoxCall. properties: algo: type: string leaf_fields: type: array items: type: string description: Field order the leaf was serialised in. Fixed forever — an anchor written today is verified by re-deriving these bytes years later. note: type: string description: The canonicalisation and domain-separation scheme in prose. RequestLog: type: object description: 'A record of a proxied API request. On `GET /logs` the fields `id`, `request_id`, `tenant_id`, `route_id`, `matched_client_id`, `identification_method`, `method`, `status_code`, `src_ip`, `environment`, `sandbox` and `ts` are exactly what the Merkle anchor commits to, in that order - see `GET /logs/{request_id}/proof`. Every other field is operational detail and is NOT part of the leaf. ' properties: id: type: string description: Row id as a decimal string. This is `api_requests.id`, a bigint - NOT a uuid, which earlier revisions of this schema incorrectly declared. It is a string rather than a JSON number because a JSON number is a double and cannot hold a bigint exactly past 2^53. request_id: type: string format: uuid description: Correlation ID for the proxied request. ts: type: string format: date-time description: Timestamp of the request. example: '2025-03-15T10:30:00.000Z' src_ip: type: string description: 'Source IP address of the caller, host form without a prefix length. Identity tier on `GET /logs`: requires `log:read_identity`, and is ABSENT (not null) when denied.' example: 203.0.113.42 method: type: string description: HTTP method used. example: POST path: type: string description: Request path. example: /v1/charges status_code: type: integer description: HTTP status code returned by the upstream. example: 200 latency_ms: type: integer description: Round-trip latency in milliseconds. example: 145 upstream_host: type: - string - 'null' description: Upstream host the request was forwarded to. example: api.stripe.com error: type: - string - 'null' description: Error message if the request failed. environment: type: - string - 'null' description: Environment the request was resolved against. example: production rate_limited: type: - boolean - 'null' description: Whether this request was rate-limited. signature_valid: type: - boolean - 'null' description: Whether the request signature was valid (if required). source_ip_country: type: - string - 'null' description: Country of the source IP (GeoIP lookup). example: US source_ip_city: type: - string - 'null' description: City of the source IP (GeoIP lookup). example: San Francisco tenant_id: type: string format: uuid description: Owning tenant. Returned by `GET /logs`; omitted by `GET /routes/{id}/logs`. route_id: type: - string - 'null' format: uuid matched_client_id: type: - string - 'null' format: uuid description: 'Which client the request was attributed to. Kept when that client is later deleted, so it may name a client that no longer exists: it is a committed field of the row''s Merkle leaf and is never rewritten. Identity tier on `GET /logs`: requires `log:read_identity`, and is ABSENT (not null) when denied.' identification_method: type: - string - 'null' description: How that attribution was made (e.g. `ip`, `mtls_thumbprint`). Identity tier on `GET /logs`. sandbox: type: - boolean - 'null' description: Live/Test partition. `null` on rows written before the partition existed, which are treated as Live. Null, false and true are three distinct facts and the Merkle anchor keeps them apart. proxy_mode: type: - string - 'null' cursor: type: string description: Opaque resume token, returned by `GET /logs` only. Pass the last row's value as `cursor` on the next call. client_origin: type: string enum: - direct - sdk_intercept description: 'How the call arrived at the Route. `sdk_intercept`: a KnoxCall SDK''s route-aware interceptor rerouted a third-party SDK''s request onto the Route (the SDK sent `x-knoxcall-origin: sdk-intercept`). `direct`: a plain `call()` / bound-route request, and every row written before the marker existed. Informational only - it never influences authentication, routing, rate limits or the response block.' ErrorResponse: type: object description: Standard error response envelope. properties: error: type: object properties: type: type: string description: 'Machine-readable error type. The set is OPEN — endpoints define specific types beyond the common ones below, so clients should branch on the types they know and fall back to the HTTP status class for anything unrecognized. Common values: authentication_required, invalid_api_key, wrong_key_type, subscription_inactive, rate_limit_exceeded, validation_error, forbidden, not_found, method_not_allowed (405, carries Allow), conflict, in_use, plan_limit, plan_feature, internal_error, dependency_unavailable (503, carries Retry-After), invalid_request, invalid_definition, not_cancellable, invalid_idempotency_key, idempotency_key_reuse, request_in_progress, system_client_protected, use_oauth, use_dpop_nonce (401 on /v1 and the data plane, 400 on POST /oauth/token; see "DPoP sender-constrained tokens").' example: validation_error message: type: string description: Human-readable error message. example: name and target_base_url are required. request_id: type: string format: uuid description: Unique identifier for this request. example: 550e8400-e29b-41d4-a716-446655440000 required: - type - message - request_id required: - error securitySchemes: OAuth2: type: oauth2 description: 'OAuth 2.1 authentication — recommended for new integrations. Access tokens (`kc_` prefix) are minted at the root-host token endpoint `https://api.knoxcall.com/oauth/token` and passed as `Authorization: Bearer `. Public clients must use PKCE with the `authorization_code` grant; confidential clients may use `client_credentials`. The first-party SDKs and the `knoxcall login` CLI handle token minting, caching, refresh, and DPoP for you. ' flows: clientCredentials: tokenUrl: https://api.knoxcall.com/oauth/token refreshUrl: https://api.knoxcall.com/oauth/token scopes: routes:read: Read routes. routes:write: Create, update, and delete routes. secrets:read: Read secret metadata. Does NOT include retrieving a live OAuth2 access token. secrets:oauth_token: Retrieve a live upstream OAuth2 access token (GET /v1/secrets/{id}/oauth2/token). Distinct from secrets:read because the call refreshes the credential at the provider. secrets:write: Create, update, and delete secrets. vaults:detokenize: Turn a vault token back into its original value. Required by GET /v1/vaults/{vault}/tokens/{token}, by a token template reference in a /v1/proxy body, and by creating a `detokenize` route action. Distinct from vaults:read, which lists vaults and token metadata and never returns a value. transit:decrypt: Open a portable `kc:` ciphertext with a tenant transit key. Required by creating a `decrypt` route action, which stores a standing instruction to open every matching field on every later request through that route. It is the same capability name the policy engine uses for POST /v1/decrypt. No routes scope satisfies it — managing a route is not permission to open the data flowing through it. proxy:invoke: Call the one-shot ephemeral proxy (any method on /v1/proxy). Required for EVERY verb — the proxy is one capability behind one handler, and a bodyless GET spends an escrowed credential exactly as a POST does. Neither proxy:read nor proxy:write satisfies it. clients:read: Read clients. clients:write: Manage clients. webhooks:write: Manage webhooks. workflows:write: Manage and execute workflows. '*:*': Full access (all scopes). authorizationCode: authorizationUrl: https://api.knoxcall.com/oauth/authorize tokenUrl: https://api.knoxcall.com/oauth/token refreshUrl: https://api.knoxcall.com/oauth/token scopes: routes:read: Read routes. routes:write: Create, update, and delete routes. secrets:read: Read secret metadata. Does NOT include retrieving a live OAuth2 access token. secrets:oauth_token: Retrieve a live upstream OAuth2 access token (GET /v1/secrets/{id}/oauth2/token). Distinct from secrets:read because the call refreshes the credential at the provider. secrets:write: Create, update, and delete secrets. vaults:detokenize: Turn a vault token back into its original value. Required by GET /v1/vaults/{vault}/tokens/{token}, by a token template reference in a /v1/proxy body, and by creating a `detokenize` route action. Distinct from vaults:read, which lists vaults and token metadata and never returns a value. transit:decrypt: Open a portable `kc:` ciphertext with a tenant transit key. Required by creating a `decrypt` route action, which stores a standing instruction to open every matching field on every later request through that route. It is the same capability name the policy engine uses for POST /v1/decrypt. No routes scope satisfies it — managing a route is not permission to open the data flowing through it. proxy:invoke: Call the one-shot ephemeral proxy (any method on /v1/proxy). Required for EVERY verb — the proxy is one capability behind one handler, and a bodyless GET spends an escrowed credential exactly as a POST does. Neither proxy:read nor proxy:write satisfies it. clients:read: Read clients. clients:write: Manage clients. webhooks:write: Manage webhooks. workflows:write: Manage and execute workflows. '*:*': Full access (all scopes). PhantomToken: type: http scheme: bearer description: "The AI **data plane** credential — a `kp_`-prefixed capability token, not a\nManagement API credential. It is minted per agent (or per MCP resource) at\n`POST /v1/ai-gateway/agents/{agentId}/tokens`, or exchanged from a CI workload's\nOIDC token at `POST /v1/oauth/token`, and it is the ONLY credential `/v1/ai/*`\naccepts: an OAuth `kc_` access token or a `tk_` API key is refused there, and a\n`kp_` token is refused on `api.knoxcall.com`.\n\nThree header spellings are accepted, so an existing provider SDK can be pointed at\nthe agent URL without rewriting its auth:\n\n Authorization: Bearer kp_live_a_...\n x-api-key: kp_live_a_...\n x-knox-ai-key: kp_live_a_...\n\n`kp_live_` is refused on the sandbox host and `kp_test_` on the Live host — the env\nsegment is enforced, not cosmetic. DPoP-bound tokens additionally require a valid\n`DPoP` proof header on every request, signed over the canonical public URL rather\nthan a rewritten `Host`.\n\nA rejected credential answers `401`/`403` in the data-plane error envelope with the\ncause in `code` and in the `X-Auth-Failure` response header.\n" BearerAuth: type: http scheme: bearer description: 'Legacy long-lived API key authentication via the Authorization header. Pass your API key as: `Authorization: Bearer tk_xxx_yyy`. Standard keys (`tk_` prefix) are accepted on `api.knoxcall.com`. Test keys (type=test) are accepted on `sandbox.knoxcall.com`. Enterprise Access Keys (`AKE` prefix) are accepted on both. Fully supported, but prefer the `OAuth2` scheme (or the SDKs, which handle OAuth for you) for new integrations. ' ApiKeyAuth: type: apiKey in: header name: x-api-key description: 'Legacy API key authentication via the `x-api-key` header. This is an alternative to Bearer token authentication for clients that cannot set the `Authorization` header. Prefer the `OAuth2` scheme for new integrations. ' CapabilityTokenAuth: type: http scheme: bearer description: 'Single-use client capability token (`kct_` prefix), passed as `Authorization: Bearer kct_...`. Minted server-side via `POST /client-tokens` and bound either to one exact payload + action (`decrypt`, `detokenize`) or to one vault + a closed set of page origins (`tokenize`). This is NOT an API key — it authenticates only the `POST /client/decrypt`, `POST /client/detokenize` and `POST /client/tokenize` consume endpoints and is invalidated after its first use. '