openapi: 3.2.0 info: title: KnoxCall Client Management Ephemeral Proxy 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: Ephemeral Proxy description: One-shot proxy that resolves vault-token template expressions on the wire — no pre-configured route required. paths: /proxy: description: "One-shot proxy: forward a request to any HTTPS upstream while KnoxCall\nresolves `{{ token: ... }}` template expressions (vault tokens) in the\nbody, query string, and forwarded headers on the wire. Accepts any HTTP\nmethod — GET, POST, PUT, PATCH, and DELETE all behave identically apart\nfrom the forwarded method.\n\n**Request headers:**\n- `X-Knox-Proxy-URL` (required) — the upstream URL. Must be `https://`\n with a DNS hostname (IP literals are rejected).\n- `X-Knox-Timeout-Ms` (optional) — upstream timeout, capped at 30000\n (default 25000).\n- `X-Knox-Encrypted` (optional) — base64-encoded JSON body (v1 scope;\n not real JWE).\n- `X-Knox-Proxy-Mode: transparent` (optional) — forward the request body\n and `Content-Type` byte-verbatim and skip `{{ token }}` templating. Use\n this to proxy a third-party SDK's own request format (e.g. Stripe's\n `application/x-www-form-urlencoded`). Omit for the default JSON +\n template behaviour.\n- `X-Knox-Upstream-Authorization` (optional) — value mapped to the\n UPSTREAM `Authorization` header (the provider's own credential). Never\n logged or stored; distinct from the KnoxCall API credential that\n authenticates the proxy call itself. Validated as a single line of\n printable characters (≤ 8192 bytes).\n- `X-Knox-Upstream-Auth-Secret` (optional) — the NAME of an escrowed wrap\n credential (see POST /wrap/credentials). KnoxCall resolves + decrypts it\n and injects it as the upstream `Authorization` header, but only if the\n upstream host is in the credential's `allowed_hosts` (else `403\n wrap_host_not_allowed`). Mutually exclusive with\n `X-Knox-Upstream-Authorization`.\n- `X-Knox-Upstream-Auth-Scheme` (optional) — auth scheme for the resolved\n secret (default `Bearer`; `none` injects the raw value).\n\nAll other headers are forwarded to the upstream except hop-by-hop\nheaders, the reserved `x-knox-*` / `authorization` / `host` /\n`content-length` headers, `cookie` (your browser's KnoxCall session is\nnever forwarded), the control headers KnoxCall reads itself\n(`x-knoxcall-key`, `x-knoxcall-route`, `x-knoxcall-environment`,\n`x-knoxcall-signature`, `x-knoxcall-agent-id`, `x-knoxcall-agent-token`,\n`x-knoxcall-client-assertion`, `x-knoxcall-origin` and `x-knoxcall-env`),\nthe headers a reverse proxy adds to describe the connection to KnoxCall\nrather than your request (`x-forwarded-for`, `x-forwarded-host`,\n`x-forwarded-proto`, `x-forwarded-server`, `x-real-ip`, `true-client-ip`,\n`x-client-cert-verify`, `x-client-cert-thumbprint` and\n`x-client-cert-subject`), the request headers Cloudflare adds\n(`cf-connecting-ip`, `cf-ray`, `cf-ipcountry` and the rest of the exact\nnames listed at\nhttps://docs.knoxcall.com/api-reference/request-headers), and `x-api-key`\nWHEN its value is a KnoxCall credential\n(`tk_`, `kc_`, `kr_` or `AKE…`) — that is the key you authenticated with,\nand it is not for your upstream. An `x-api-key` holding your upstream's\nown key (`sk-ant-…`, and so on) is forwarded unchanged.\n\nEvery name above is matched exactly, in any letter case; apart from\n`x-knox-` there is no prefix rule. A header that only resembles one of\nthem is forwarded, including the `cf-access-client-id` /\n`cf-access-client-secret` / `cf-access-token` credentials for an upstream\nof yours that sits behind Cloudflare Access.\n\n**Response:** a passthrough of the upstream's status, headers (minus\nhop-by-hop), and body — not the KnoxCall JSON envelope.\n\nEvery response also carries the **KnoxCall response block**: the `X-Knox-*`\nheaders that describe KnoxCall's own half of the call, distinct from\nanything your upstream sent. The whole `x-knox-` response namespace is\nreserved — an upstream header in it is dropped, never relayed — so these\nvalues are always KnoxCall speaking.\n\n| header | meaning |\n|---|---|\n| `X-Knox-Request-Id` | the call id; quote it to support |\n| `X-Knox-Origin` | `upstream` or `knoxcall` — who produced this status and body |\n| `X-Knox-Upstream-Status` | the status your upstream returned. **Present only on a genuine forward** |\n| `X-Knox-Error` | KnoxCall's error code, on a KnoxCall-originated refusal |\n| `X-Knox-Latency-Ms` | total time inside KnoxCall, in milliseconds |\n| `X-Knox-Latency-Phase` | `complete`, or `first-byte` on a streamed response |\n| `X-Knox-Upstream-Ms` / `X-Knox-Overhead-Ms` | the split: time in your provider vs time in KnoxCall. Omitted when unmeasured |\n| `X-Knox-Sandbox` | whether the call ran in the Test data space |\n| `X-Knox-RateLimit-Route` / `-Tenant` / `-Monthly` | `limit=…, remaining=…, reset=…` per limiter |\n| `Server-Timing` | `knoxcall;dur=…, knoxcall_upstream;dur=…`, appended to any your upstream sent |\n\n**To tell a KnoxCall error from a provider error, branch on the ABSENCE of\n`X-Knox-Upstream-Status`.** It is present if and only if a real upstream\nresponse was received, so \"no `X-Knox-Upstream-Status`\" means the gateway\nanswered and the call never reached your provider — the check a wrapped\nSDK needs so it does not retry a KnoxCall 429 against a provider limit\nthat is not the one refusing it. A KnoxCall-originated refusal (plan gate,\nvalidation, SSRF/PAN refusal, upstream failure) additionally carries\n`X-Knox-Error` and repeats the whole block as a `knoxcall` object beside\n`error` in the JSON body. `X-Knox-Destination-Status` is the older spelling\nof `X-Knox-Upstream-Status` and is still sent. When a durable route now covers the\nupstream host (you promoted this traffic — see POST /opportunities/{id}/accept),\nthe response also carries `X-Knox-Promoted-Route: ` so a wrapper can\nswitch off the ephemeral path.\n\n**PCI:** requests to known raw-card endpoints (`api.stripe.com/v1/tokens`,\n`/v1/sources`) are refused with `403 pan_endpoint_refused` — tokenize card\ndata with a KnoxCall vault or `@knoxcall/browser` and send the token.\n\n**Test-mode test cards.** In the Test data space four documented card\nnumbers behave in documented ways so a failure path can be exercised\nwithout a processor account. `4242 4242 4242 4242` forwards normally;\n`4000 0000 0000 0002` is NOT forwarded and answers `402\nsandbox_test_card_declined`; `4000 0000 0000 3220` is NOT forwarded and\nanswers `402 sandbox_test_card_requires_action`; `4000 0000 0000 0069`\nforwards but tokenizes with a past `card_expires_on`. Both refusals are\nKnoxCall's own simulated outcome and not any processor's — nothing is sent\nupstream — and both are recognised ONLY for a value a `pan` vault\nRELEASED, never for a card number in your own request body (that is still\n`403`). In the Live data space all four are ordinary card numbers. See\n/essentials/vaults/overview#test-cards.\n\n**Responses are re-tokenized when a card number was detokenized.** If the\nrequest resolved a `{{ token: ... }}` from a `pan`-format vault, the\nupstream's reply is scanned for that exact number — however the upstream\nspaced it — and each occurrence is replaced with the token before the\nresponse reaches you, in the body (JSON at any depth, form-encoded, text)\nand in header values such as `Location`. Only the values THIS request\nopened, and only `pan` vaults: a different card number the upstream\nmentions, and any `generic`/`ssn`/`email` value, are untouched. Two\nconsequences: KnoxCall sends `Accept-Encoding: identity` upstream on such a\nrequest and WITHHOLDS the reply with `502 response_not_retokenizable` if it\ncomes back compressed or binary (it cannot be scanned, and an unscanned\nreply is not forwarded); and a request that both detokenizes a `pan` token\nand asks for a streamed response is refused with\n`409 pan_streaming_unsupported`, because a card number can straddle any\nchunk boundary the upstream picks. Each re-tokenized response writes a\n`vault.retokenize` audit entry with the vault id and the occurrence count —\nnever the number, never the token.\n\n**Scope: `proxy:invoke`, on every method.** If the access token you call\nwith was deliberately narrowed, its grant must include `proxy:invoke` (or\n`proxy:*`); `proxy:read` and `proxy:write` are refused with `403\ninsufficient_scope`. Calling the proxy is not a read of a resource and not\na write to one — it resolves and decrypts an escrowed credential and spends\nit against the upstream you name — and because one handler serves every\nverb, a bodyless `GET` does exactly what a `POST` does. This mirrors\n`routes:invoke` on the route-configured data plane. An un-narrowed token\n(and a raw API key) is unaffected.\n" get: operationId: ephemeralProxyGet summary: Proxy a GET request tags: - Ephemeral Proxy parameters: - $ref: '#/components/parameters/KnoxProxyUrlHeader' - $ref: '#/components/parameters/KnoxTimeoutHeader' responses: '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '402': description: 'Ephemeral Proxy requires a Starter plan or above; the vault detokenize meter is exhausted (`plan_limit`); or, in the Test data space only, the request released a documented KnoxCall test card (`sandbox_test_card_declined`, `sandbox_test_card_requires_action`) and was not forwarded. Branch on `error.type`, never on the status. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' default: description: Passthrough of the upstream response (status, headers, and body). post: operationId: ephemeralProxyPost summary: Proxy a POST request tags: - Ephemeral Proxy parameters: - $ref: '#/components/parameters/KnoxProxyUrlHeader' - $ref: '#/components/parameters/KnoxTimeoutHeader' requestBody: description: 'Forwarded verbatim after `{{ token: ... }}` expressions are resolved.' content: application/json: schema: description: Any JSON body. responses: '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '402': description: 'Ephemeral Proxy requires a Starter plan or above; the vault detokenize meter is exhausted (`plan_limit`); or, in the Test data space only, the request released a documented KnoxCall test card (`sandbox_test_card_declined`, `sandbox_test_card_requires_action`) and was not forwarded. Branch on `error.type`, never on the status. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' default: description: Passthrough of the upstream response (status, headers, and body). put: operationId: ephemeralProxyPut summary: Proxy a PUT request tags: - Ephemeral Proxy parameters: - $ref: '#/components/parameters/KnoxProxyUrlHeader' - $ref: '#/components/parameters/KnoxTimeoutHeader' requestBody: description: 'Forwarded verbatim after `{{ token: ... }}` expressions are resolved.' content: application/json: schema: description: Any JSON body. responses: '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' default: description: Passthrough of the upstream response (status, headers, and body). patch: operationId: ephemeralProxyPatch summary: Proxy a PATCH request tags: - Ephemeral Proxy parameters: - $ref: '#/components/parameters/KnoxProxyUrlHeader' - $ref: '#/components/parameters/KnoxTimeoutHeader' requestBody: description: 'Forwarded verbatim after `{{ token: ... }}` expressions are resolved.' content: application/json: schema: description: Any JSON body. responses: '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' default: description: Passthrough of the upstream response (status, headers, and body). delete: operationId: ephemeralProxyDelete summary: Proxy a DELETE request tags: - Ephemeral Proxy parameters: - $ref: '#/components/parameters/KnoxProxyUrlHeader' - $ref: '#/components/parameters/KnoxTimeoutHeader' responses: '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' default: description: Passthrough of the upstream response (status, headers, and body). components: responses: 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 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 parameters: KnoxProxyUrlHeader: name: X-Knox-Proxy-URL in: header required: true schema: type: string format: uri description: The HTTPS upstream URL to forward the request to. Must use a DNS hostname (no IP literals). example: https://api.stripe.com/v1/charges KnoxTimeoutHeader: name: X-Knox-Timeout-Ms in: header required: false schema: type: integer maximum: 30000 default: 25000 description: Upstream timeout in milliseconds (max 30000). headers: 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 schemas: 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. '