Concepts / BYOK

# Bring your own keys

Use your provider agreements through the gateway and keep routing and evidence, priced by each BYOK endpoint's own published price.

## How BYOK works

Store a provider secret once with `POST /api/v1/credentials` (`credential:write` — owner and security_admin; developers hold `credential:read`). It is encrypted at rest, decrypted just-in-time at dispatch, and never returned by any endpoint, audit row, event or log line. Every response carries only the summary: a `fingerprint` — the first 16 hex characters of `sha256(secret)`, so you can check which key is stored — the `last4` characters, the `state`, timestamps and the last provider error. A credential applies to every endpoint of that provider for the organization; there are no per-endpoint bindings.

```
# POST /api/v1/credentials                                  (credential:write)
{ "provider": "anthropic", "name": "prod", "secret": "sk-ant-api03-…" }

# 201 CredentialOut — no field can hold the secret
{ "id": "cred_01J…", "provider": "anthropic", "name": "prod",
  "provider_display_name": "Anthropic",
  "fingerprint": "8f4e2a1b9c0d7e6f", "last4": "Q7xg", "state": "active",
  "last_used_at": null, "last_error": null, "rotated_from_id": null, … }
```

Routing follows the policy: `allow_byok` admits your credentials, and a request may narrow itself to them with `yelno.credential_sources`. A BYOK endpoint is eligible only while the organization holds an `active` credential for its provider — otherwise it is eliminated as `byok_credential_missing` (or `credential_source_ineligible` when BYOK is switched off). Every attempt in `yelno.attempts` names the `credential_source` it used, `platform` or `byok`.

```
// organization policy — PUT /api/v1/organizations/{id}/policy
{ "allow_byok": true }

// per request, optional — only your own credentials for this call
"yelno": { "credential_sources": ["byok"] }

// response: the credential source each attempt used
"attempts": [{ "sequence": 1, "provider": "openai", "region": "eu-west",
               "credential_source": "byok", "state": "provider_completed" }]
```

## Rotation, testing and states

`POST /api/v1/credentials/{id}/rotate` with the new `secret` inserts a new `active` row (`rotated_from_id` = the old id) and revokes the old one in the same transaction — there is no overlap window; the next catalog snapshot binds the new credential. `POST /api/v1/credentials/{id}/test` is a write-only liveness probe: it never returns the secret, records `last_used_at` on success or `last_error` on failure, and never changes the state (`method: "provider_probe"` makes one authenticated model-list call against a fixed provider host; `"format"` checks the key shape in mock deployments). `PATCH` renames, disables, re-enables or marks a credential `compromised`; `DELETE` revokes it.

| State | Meaning |
| --- | --- |
| active | Binds to every endpoint of its provider at the next catalog snapshot; the newest active credential per provider wins. |
| disabled | Kept, never dispatched. Set by you (PATCH), or by the platform after a provider 401/403 at dispatch. |
| compromised | Kept, never dispatched; can only be rotated or revoked. Emits credential.compromised for your incident process. |
| revoked | Terminal (DELETE, or the old row of a rotation). The row stays so historical attempts still resolve; its name is free again. |

## What you pay

BYOK requests are billed by the provider on your own account. Yelno rates them against the BYOK endpoint's own published customer price book — the price of routing, metering and evidence for that endpoint, shown on every request and invoice — with nothing added on top of the provider's own bill. Shared-pool requests are rated against the shared endpoint's published price book, which is the whole price.

## Quota and health

Providers whose resale rights are `byok_only` are reachable only through your credentials; those with `shared_capacity` can also serve from the shared pool, and the source is labelled on each attempt; `excluded` providers cannot hold a credential at all. A provider `401` or `403` at dispatch disables the credential: the row moves from `active` to `disabled`, `last_error` records the provider's message (scrubbed of anything key-shaped), the audit row is `credential.auth_failed` and the `credential.auth_failed` event is emitted. Endpoint health and the circuit are untouched — the endpoint was not at fault. Re-enable the credential once the key is fixed, or rotate it.

Credential custody Credentials are encrypted per tenant with envelope encryption bound to the organization and credential id, decrypted only at dispatch, and never returned by any API. Rotation is immediate: the old secret is revoked in the same transaction, not kept for an overlap window.

Source: https://yelno.ai/docs/byok
