BYOK
Bring-your-own-key routing and attribution.
Bring-your-own-key (BYOK) lets you route requests through your own upstream provider credentials instead of AI Setu's platform key — no per-token markup on that traffic, and usage is billed by the provider directly to your account.
The three layers
BYOK is modeled as a Connection to a Provider, backed by a Credential:
| Layer | What it is | Holds | Scope |
|---|---|---|---|
| Provider | The vendor type (openai, anthropic, bedrock, …) | — | — |
| Credential | The secret | API key / AWS keys / GCP service-account JSON, base URL | Org-wide, reusable |
| Connection | The routable handle | A slug + a reference to one Credential | Org-wide or restricted to specific workspaces |
One Credential can back many Connections — reuse the same key under different slugs, default models, or workspace scopes. Rotating the Credential updates every Connection built on it. A Connection points at exactly one Credential.
Routing through a Connection — @<slug>/<model>
Put the Connection's slug in the model string, prefixed with @:
const res = await client.chat.completions.create({
model: '@my-openai/gpt-4o-mini',
messages: [{ role: 'user', content: 'Hello via my own OpenAI key' }],
});
console.log(client.lastRouting); // { provider: 'openai', byok: true, connectionSlug: 'my-openai' }curl https://gateway.aisetu.ai/v1/chat/completions \
-H "Authorization: Bearer $AI_SETU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "@my-openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello via my own OpenAI key"}]
}'The leading @ marks a Connection slug, so a slug can equal a provider name
without colliding with <provider>/<model> routing. One client can mix
Connections request-by-request — no re-initializing.
Unknown or out-of-scope slugs fail closed. A malformed @-string or a
slug that doesn't exist (or isn't enabled for your workspace) returns a 4xx
— it never silently falls back to the platform key. Always check the
response's X-AI-Setu-BYOK header (or client.lastRouting.byok) rather than
assuming a pin took effect; false on a request you expected to be BYOK
means the slug matched nothing.
Adding a credential
Credentials are created through the console (Settings → Providers & routing) or programmatically:
// @ai-setu/admin
await admin.providerCredentials.upsert({
provider: 'openai',
slug: 'my-openai',
apiKey: process.env.OPENAI_API_KEY,
});
// AWS Bedrock — AWS access keys, not a bearer key.
await admin.providerCredentials.upsert({
provider: 'bedrock',
slug: 'my-bedrock',
awsAccessKeyId,
awsSecretAccessKey,
awsRegion: 'us-west-2',
});
// Google Vertex AI — a GCP service-account JSON.
await admin.providerCredentials.upsert({
provider: 'vertex',
slug: 'my-vertex',
gcpServiceAccountJson: JSON.stringify(serviceAccount),
vertexRegion: 'us-central1',
});Secrets are envelope-encrypted at rest and never returned over the wire —
only a keyHint (last four characters) is shown for display. See
Providers for the credential shape each provider
kind expects, and Models for how a canonical model id
maps onto a provider once a Connection resolves it.
Workspace bindings — the default for bare-model requests
A Connection you add joins your org's connection pool. Separately, each
workspace enables at most one Connection per provider type — this is
what a bare provider/model or catalog-routed request uses by default (see
Routing). New workspaces auto-inherit the org pool's
default Connection per provider; you can enable a different one, or set a
precedence override, from Settings → Providers & routing.
Legacy header
X-AI-Setu-Provider-Credential: <slug> pins a Connection for every request
on a client instance. It still works, but new integrations should prefer
@<slug>/<model> per request, or a workspace binding for a standing default
— see BYOK governance in Routing.
Attribution
Every response carries X-AI-Setu-BYOK (true/false) and, when BYOK
served the request, X-AI-Setu-Credential-Id and
X-AI-Setu-Credential-Label. Some providers also support a daily spend
cap per credential — exceeding it returns 402 with code
wesence.credential_cap_exceeded, distinct from your platform credit
balance running out (wesence.insufficient_credits); other credentials on
the same tenant keep working. See Errors.