Skip to main content

Bring Your Own Key

Store your own model-provider credentials, verify them, rotate them, and deactivate them — the secret is never returned.

Overview

Bring Your Own Key (BYOK) lets you store your own credential for a model provider so inference runs on your account with that provider instead of ours.

The stored secret is write-only. No endpoint on this page returns it, and there is no reveal route. You can see the provider, an optional label, the last four characters, whether it is active, and when it was last verified — nothing more. If you lose the original secret, delete the record and add a new one.

Authentication

Authorization: Bearer cm_your_api_key
OperationScope
Listprovider_keys:read
Create, update, delete, verifyprovider_keys:write

Supported providers

Provider ids are lowercase. The accepted set is intentionally small — only providers whose credentials the gateway can actually inject into inference — for example google and sarvam. An unsupported value returns 422 and lists the full accepted set.

The uniqueness rule

A credential occupies one slot per (provider, label). A record with no label is that provider's default slot. Adding a second key to an occupied slot returns 409:

{ "detail": "A default google key already exists. Delete it first to replace the secret." }

To hold several keys for one provider, give each a distinct label (for example eu, us, batch).

Rotation is delete-then-create. PATCH deliberately refuses a key field, so a secret can never be silently swapped under a record that other systems believe they know.

GET /api/v1/gateway/provider-keys

ParameterTypeRequiredConstraints
providerstringNoAt most 32 characters, case-insensitive, must be a supported provider
limitintegerNo1 <= limit <= 200, default 100
offsetintegerNo0 <= offset <= 100000, default 0
[
  {
    "id": "1a2b…",
    "provider": "google",
    "label": "eu",
    "key_last4": "9f3a",
    "is_active": true,
    "last_verified_at": "2026-08-17T09:12:00Z",
    "created_at": "2026-08-02T11:00:00Z",
    "updated_at": "2026-08-17T09:12:00Z"
  }
]

Newest first.

POST /api/v1/gateway/provider-keys

FieldTypeRequiredConstraints
providerstringYes1–32 characters, lowercased, must be supported
keystringYes8–512 characters, not blank. Write-only — stored encrypted, never returned
labelstringNoAt most 128 characters. Blank is stored as no label (the default slot)

Unknown fields are rejected with 422 rather than ignored, so a typo in a field name fails loudly instead of quietly dropping your secret.

curl -X POST https://api.callmissed.com/api/v1/gateway/provider-keys \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "google", "key": "AIza…", "label": "eu" }'

Returns 201 with the record — note the response has no key field.

PATCH /api/v1/gateway/provider-keys/{key_id}

FieldTypeRequiredConstraints
labelstringNoAt most 128 characters
is_activebooleanNofalse takes the credential out of use without deleting it

Sending key returns 422. Moving a label into an occupied slot returns 409.

Use is_active: false when you suspect a credential and want traffic to fall back immediately while you investigate.

DELETE /api/v1/gateway/provider-keys/{key_id}

Returns 204. 404 Provider key not found for an unknown or another tenant's id.

POST /api/v1/gateway/provider-keys/{key_id}/verify

Performs a live check against the provider. No request body.

{
  "id": "1a2b…",
  "provider": "google",
  "ok": true,
  "detail": "Credential accepted by the provider.",
  "last_verified_at": "2026-08-17T09:12:00Z"
}

detail is one of exactly two strings — Credential accepted by the provider. or The provider rejected this credential or could not be reached. The upstream status code and body are never passed through, so a verify call cannot be used to probe a provider. A successful check stamps last_verified_at.

StatusDetailCause
400Liveness verification is not available for {provider} keys.That provider has no cheap check
404Provider key not foundUnknown or another tenant's id
409This stored credential can no longer be read. Delete and re-add it.The stored secret is unreadable — re-add it

Errors

StatusWhen
403Key is missing provider_keys:read / provider_keys:write
404Record not found in your tenant
409Slot already occupied, or an unreadable stored credential
422Unsupported provider, blank/short secret, an unknown field, or a key sent to PATCH

Storing, verifying and deleting provider keys never consumes credits.