openapi: 3.2.0 info: title: KnoxCall Client Management Dynamic DB Credentials 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: Dynamic DB Credentials description: Just-in-time database credentials — register connections and roles, then mint short-lived leased users on demand. paths: /dyn-db-credentials: get: operationId: listDbConnections summary: List database connections description: Returns all registered database connections (not paginated). Admin passwords and SSH keys are never returned. tags: - Dynamic DB Credentials responses: '200': description: List of connections. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/DbConnection' meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' post: operationId: createDbConnection summary: Register a database connection description: 'Registers a database KnoxCall can mint short-lived credentials against. The admin credential is encrypted at rest and never returned. `execution_mode` determines how KnoxCall reaches the database: - `direct` — connect straight to `host:port` (requires `admin_username` + `admin_password`) - `agent_tunnel` — via a registered agent (`agent_id` required) - `ssh_tunnel` — via an SSH bastion (`ssh_host`, `ssh_username`, `ssh_private_key` required) - `iam` — AWS RDS IAM auth (`iam_region`, `iam_db_user` required; postgres + mysql only)' tags: - Dynamic DB Credentials requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDbConnectionRequest' example: name: orders-db engine: postgres host: db.internal.example.com port: 5432 database_name: orders admin_username: knoxcall_admin admin_password: '********' execution_mode: direct responses: '200': description: The registered connection. content: application/json: schema: type: object properties: data: type: object properties: id: type: string format: uuid name: type: string engine: type: string enum: - postgres - mysql - mongo execution_mode: type: string enum: - direct - agent_tunnel - ssh_tunnel - iam meta: $ref: '#/components/schemas/RequestMeta' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '409': $ref: '#/components/responses/Conflict' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/leases: get: operationId: listDbLeases summary: List credential leases description: 'Lists **live** credential leases for the account — those whose `status` is `active`, `renewing` or `errored`, i.e. every lease whose database user may still exist on your server. A lease that has `expired` or been `revoked` has had its user dropped, so it is not listed and is not counted in `total`; its history remains in the audit log. This matches the **Live leases** panel in the admin UI. `errored` is included deliberately: renewal was abandoned after five consecutive failures, so nothing is refreshing or expiring that lease and its database user is probably still live. It is also exactly the set counted by the `409 … has N active credential lease(s)` returned when you delete a connection or a role, so anything blocking a delete is listed here and can be revoked. `connection_name`, `role_name` and `engine` are read from the connection and role the lease was minted from, so a lease whose role row has since been removed returns `role_name: null`. Unlike other list endpoints, this one uses `limit`/`offset` query pagination and returns the pagination fields **inside** `data`.' tags: - Dynamic DB Credentials parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 500 default: 100 - name: offset in: query schema: type: integer minimum: 0 default: 0 - name: connection in: query schema: type: string description: 'Filter by connection name — an exact match on the connection''s `name`, scoped to the caller''s Live/Test space. ' responses: '200': description: Leases with in-data pagination. content: application/json: schema: type: object properties: data: type: object properties: leases: type: array items: $ref: '#/components/schemas/DbLease' total: type: integer limit: type: integer offset: type: integer meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/leases/{lease_id}/revoke: parameters: - name: lease_id in: path required: true schema: type: integer minimum: 1 description: The lease ID (integer). post: operationId: revokeDbLease summary: Revoke a credential lease description: Immediately revokes a minted credential — the database user is dropped via the role's revocation SQL. tags: - Dynamic DB Credentials responses: '200': description: Lease revoked. `revoked` echoes the lease ID (integer). content: application/json: schema: type: object properties: data: type: object properties: revoked: type: integer example: 42 meta: $ref: '#/components/schemas/RequestMeta' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/{name}: parameters: - $ref: '#/components/parameters/DbConnectionName' get: operationId: getDbConnection summary: Get connection details tags: - Dynamic DB Credentials responses: '200': description: Connection details. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/DbConnection' meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' patch: operationId: updateDbConnection summary: Update a connection description: 'Updates any subset of: `host`, `port`, `database_name`, `admin_username`, `admin_password`, `default_ttl_seconds`, `max_ttl_seconds`, `connect_options`, `agent_id`, `enabled`.' tags: - Dynamic DB Credentials requestBody: required: true content: application/json: schema: type: object properties: host: type: string port: type: - integer - 'null' minimum: 1 maximum: 65535 database_name: type: - string - 'null' admin_username: type: string admin_password: type: string description: Re-encrypted at rest; never returned. default_ttl_seconds: type: integer minimum: 1 max_ttl_seconds: type: integer minimum: 1 connect_options: type: object additionalProperties: true agent_id: type: - string - 'null' description: 'Must name an agent registered to your tenant in the same environment as the API key making this call; an id that does not resolve is rejected with `400 validation_error`. `null` clears the binding. ' enabled: type: boolean responses: '200': description: Update acknowledged. `updated` echoes the connection name. content: application/json: schema: type: object properties: data: type: object properties: updated: type: string example: orders-db meta: $ref: '#/components/schemas/RequestMeta' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteDbConnection summary: Delete a connection description: Deletes a connection and its roles. `deleted` echoes the connection name (string). tags: - Dynamic DB Credentials responses: '200': description: Connection deleted. content: application/json: schema: type: object properties: data: type: object properties: deleted: type: string example: orders-db meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/{name}/roles: parameters: - $ref: '#/components/parameters/DbConnectionName' get: operationId: listDbRoles summary: List roles on a connection tags: - Dynamic DB Credentials responses: '200': description: List of roles (not paginated). content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/DbRole' meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' post: operationId: createDbRole summary: Register a role description: 'Registers a role — the SQL templates KnoxCall runs to create and drop a leased user. Supply either a built-in `template` (`readonly` / `readwrite`) or both `creation_sql` and `revocation_sql`.' tags: - Dynamic DB Credentials requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string description: Role name (slug). example: readonly template: type: string enum: - readonly - readwrite description: Built-in template for the connection's engine. Mutually exclusive with custom SQL. creation_sql: type: string description: Custom SQL run to create the leased user. Required with `revocation_sql` when no `template` is given. revocation_sql: type: string description: Custom SQL run to drop the leased user. default_ttl_seconds: type: integer minimum: 1 max_ttl_seconds: type: integer minimum: 1 responses: '200': description: The registered role. content: application/json: schema: type: object properties: data: type: object properties: id: type: string format: uuid name: type: string connection: type: string meta: $ref: '#/components/schemas/RequestMeta' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/{name}/roles/{role}: parameters: - $ref: '#/components/parameters/DbConnectionName' - name: role in: path required: true schema: type: string description: The role name. patch: operationId: updateDbRole summary: Update a role description: Updates any subset of `creation_sql`, `revocation_sql`, `default_ttl_seconds`, `max_ttl_seconds`. tags: - Dynamic DB Credentials requestBody: required: true content: application/json: schema: type: object properties: creation_sql: type: string revocation_sql: type: string default_ttl_seconds: type: - integer - 'null' minimum: 1 max_ttl_seconds: type: - integer - 'null' minimum: 1 responses: '200': description: Update acknowledged. `updated` echoes the role name. content: application/json: schema: type: object properties: data: type: object properties: updated: type: string example: readonly meta: $ref: '#/components/schemas/RequestMeta' '400': $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' delete: operationId: deleteDbRole summary: Delete a role description: Removes a role from a connection. `deleted` echoes the role name (string). tags: - Dynamic DB Credentials responses: '200': description: Role deleted. content: application/json: schema: type: object properties: data: type: object properties: deleted: type: string example: readonly meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /dyn-db-credentials/{name}/creds/{role}: parameters: - $ref: '#/components/parameters/DbConnectionName' - name: role in: path required: true schema: type: string description: The role name. post: operationId: mintDbCredential summary: Mint a database credential description: 'Creates a short-lived database user under the role and returns its credentials. **The `password` is returned only in this response** — it cannot be retrieved again. The lease auto-expires at `expires_at`; revoke early via `POST /dyn-db-credentials/leases/{lease_id}/revoke`.' tags: - Dynamic DB Credentials requestBody: required: false content: application/json: schema: type: object properties: ttl_seconds: type: integer minimum: 1 description: Requested lease TTL. Defaults to the role/connection default; capped at the max TTL. responses: '200': description: The minted credential. Store the password now — it is never shown again. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/MintedDbCredential' meta: $ref: '#/components/schemas/RequestMeta' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' '502': description: The database rejected the credential-creation SQL. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /dyn-db-credentials/{name}/rotate-ssh-key: parameters: - $ref: '#/components/parameters/DbConnectionName' post: operationId: rotateDbSshKey summary: Rotate the SSH key description: Replaces the SSH private key (and optionally the host fingerprint) of an `ssh_tunnel` connection. tags: - Dynamic DB Credentials requestBody: required: true content: application/json: schema: type: object required: - ssh_private_key properties: ssh_private_key: type: string description: PEM-encoded private key. ssh_passphrase: type: string ssh_host_fingerprint: type: string description: '`SHA256:` format.' responses: '200': description: Rotation result. content: application/json: schema: type: object properties: data: type: object properties: rotated: type: string description: The connection name. fingerprint_updated: type: boolean meta: $ref: '#/components/schemas/RequestMeta' '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 Conflict: description: A resource with the same unique identifier already exists, or the resource is in use. 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: conflict message: A route with this name already exists. 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 schemas: MintedDbCredential: type: object description: A freshly minted short-lived database credential. properties: username: type: string description: The minted database username. password: type: string description: '**Returned only in this response — it cannot be retrieved again.**' expires_at: type: string format: date-time description: When the lease auto-expires and the user is dropped. lease_id: type: integer description: Lease ID (integer) — use it to revoke early. example: 42 connection_name: type: string example: orders-db role_name: type: string example: readonly DbRole: type: object description: A role — the SQL templates KnoxCall runs to create and drop a leased database user. properties: id: type: string format: uuid name: type: string example: readonly creation_sql_template: type: string description: SQL run to create the leased user. revocation_sql_template: type: string description: SQL run to drop the leased user. default_ttl_seconds: type: - integer - 'null' description: Role-level default lease TTL. Null falls back to the connection default. max_ttl_seconds: type: - integer - 'null' description: Role-level TTL cap. Null falls back to the connection cap. created_at: type: string format: date-time updated_at: type: string format: date-time RequestMeta: type: object description: Metadata included with every API response. properties: request_id: type: string format: uuid description: Unique identifier for this API request, useful for support and debugging. example: 550e8400-e29b-41d4-a716-446655440000 required: - request_id CreateDbConnectionRequest: type: object required: - name - engine - host - execution_mode properties: name: type: string description: Connection name (slug, 1-64 chars). `leases` is reserved — it is a route on this API (`/dyn-db-credentials/leases`), so a connection using it would be unreachable by name. Rejected with 400. example: orders-db engine: type: string enum: - postgres - mysql - mongo host: type: string example: db.internal.example.com port: type: integer minimum: 1 maximum: 65535 database_name: type: string admin_username: type: string description: Required for `direct`, `agent_tunnel`, and `ssh_tunnel` modes. admin_password: type: string description: Required for `direct`, `agent_tunnel`, and `ssh_tunnel` modes. **Encrypted with the tenant master key at rest and never returned.** execution_mode: type: string enum: - direct - agent_tunnel - ssh_tunnel - iam agent_id: type: string description: 'Required when `execution_mode` is `agent_tunnel`. Must name an agent registered to your tenant **in the same environment as the API key making this call** — a Test key cannot bind a connection to a Live agent, and vice versa. An id that does not resolve is rejected with `400 validation_error`. ' default_ttl_seconds: type: integer minimum: 1 default: 3600 description: Default lease TTL for minted credentials. max_ttl_seconds: type: integer minimum: 1 default: 86400 description: Upper bound on lease TTLs. Must be >= `default_ttl_seconds`. connect_options: type: object additionalProperties: true description: Engine-specific connection options. ssh_host: type: string description: Required when `execution_mode` is `ssh_tunnel`. ssh_port: type: integer minimum: 1 maximum: 65535 ssh_username: type: string description: Required when `execution_mode` is `ssh_tunnel`. ssh_private_key: type: string description: PEM-encoded SSH private key. Required when `execution_mode` is `ssh_tunnel`. **Encrypted at rest and never returned.** ssh_passphrase: type: string description: Passphrase for the SSH key, if any. Encrypted at rest and never returned. ssh_host_fingerprint: type: string description: Expected bastion host key fingerprint in `SHA256:` format. Verified on connect when set. iam_region: type: string description: AWS region. Required when `execution_mode` is `iam` (postgres and mysql on RDS only). example: us-east-1 iam_db_user: type: string description: RDS IAM database user. Required when `execution_mode` is `iam`. DbLease: type: object description: A credential lease. properties: id: type: integer description: The lease ID (integer, not a UUID). example: 42 status: type: string description: 'Only the LIVE values — `active`, `renewing` and `errored` — are returned by `GET /dyn-db-credentials/leases`; the terminal values `expired` and `revoked` appear on leases read through other surfaces. ' enum: - active - renewing - expired - revoked - errored expires_at: type: string format: date-time issued_at: type: string format: date-time username: type: - string - 'null' description: The minted database username. connection_name: type: - string - 'null' description: The name of the connection the credential was minted from. role_name: type: - string - 'null' description: 'The name of the role the credential was minted from. `null` only if the role row no longer exists. ' engine: type: - string - 'null' description: The connection's database engine. example: postgres DbConnection: type: object description: A registered database connection. Admin passwords and SSH private keys are never returned. properties: id: type: string format: uuid example: 5e4d3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b name: type: string example: orders-db engine: type: string enum: - postgres - mysql - mongo host: type: string example: db.internal.example.com port: type: - integer - 'null' example: 5432 database_name: type: - string - 'null' example: orders admin_username: type: string description: The admin account KnoxCall uses to mint leased users. Its password is encrypted at rest and never returned. execution_mode: type: string enum: - direct - agent_tunnel - ssh_tunnel - iam agent_id: type: - string - 'null' description: The registered agent used for `agent_tunnel` connections. default_ttl_seconds: type: integer example: 3600 max_ttl_seconds: type: integer example: 86400 connect_options: type: object additionalProperties: true description: Engine-specific connection options. enabled: type: boolean created_at: type: string format: date-time example: '2025-03-15T10:30:00.000Z' updated_at: type: string format: date-time ssh_host: type: - string - 'null' description: SSH bastion host (`ssh_tunnel` mode). ssh_port: type: - integer - 'null' ssh_username: type: - string - 'null' iam_region: type: - string - 'null' description: AWS region (`iam` mode). example: us-east-1 iam_db_user: type: - string - 'null' description: RDS IAM database user (`iam` mode). 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 parameters: DbConnectionName: name: name in: path required: true schema: type: string description: The database connection name. example: orders-db 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 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. '