BYOK — bring your own key
The framework runs LLM-driven features (agents, page-chat, HTML generation, the Pulse) against a default credential pool, but if you want unlimited use, your own model choice, or your own data governance, you bring your own key. Eight providers supported, account-scoped, AES-256-GCM-encrypted at rest.
BYOK calls don't burn your daily ZEQ quota for LLM tokens — you pay your provider directly. The framework still charges its own action costs (75 ZEQ for a spawn, 25 for page-chat, 100 for HTML generation) because they cover the entangled state write + audit envelope work, not the LLM tokens themselves.
Providers
| ID | Provider | Default model | API style |
|---|---|---|---|
openai | OpenAI | gpt-4o-mini | OpenAI chat |
anthropic | Anthropic Claude | claude-3-5-haiku-20241022 | Anthropic Messages |
deepseek | DeepSeek | deepseek-chat | OpenAI chat |
ollama | Ollama (self-hosted) | (provider default) | Ollama generate |
openrouter | OpenRouter | (provider default) | OpenAI chat |
together | Together AI | (provider default) | OpenAI chat |
groq | Groq | (provider default) | OpenAI chat |
fireworks | Fireworks AI | accounts/fireworks/models/llama-v3p3-70b-instruct | OpenAI chat |
Source: shared/api-core/src/lib/llmProviders.ts. The framework's free
tier (/api/chat/free) uses a system-default Fireworks credential —
that's the only credential the foundation seeds for you.
For ollama, base_url is required (you're pointing at your own
self-hosted instance). For all other providers, base_url is optional;
defaults are baked into the provider definition.
Where credentials live
/portal/settings/ → LLM Credentials · Bring your own key card.
The card lists your active credentials (label + prefix only — full keys
are shown ONCE on creation), and lets you add or revoke. The same card
also appears (in pointer form) on /state/admin/ai/ so power-users
spawning agents can jump to it without leaving the entangled state context.
API:
| Method | Path | Use |
|---|---|---|
POST | /api/zeq/llm/credentials | Create — full key echoed once in response |
GET | /api/zeq/llm/credentials | List caller's credentials (prefix only) |
GET | /api/zeq/llm/credentials/:id | Show one (prefix only) |
DELETE | /api/zeq/llm/credentials/:id | Soft-disable (active=false) |
POST | /api/zeq/llm/credentials/:id/system-default | Foundation-only — promote to system default |
All routes are paid-tier gated (requirePaid middleware). Free-tier
users see an upgrade banner instead of the credentials list.
How keys are encrypted
Each credential row stores three encrypted fields:
api_key_encrypted bytea AES-256-GCM ciphertext
api_key_iv bytea 12-byte IV per row
api_key_prefix text first 4 chars + "…" + last 4 (for UI)
The encryption key is the framework's ZEQ_FIELD_KEY env var (32 bytes,
base64). It's not stored anywhere on disk that's checked into the repo
— it's only in the running process's memory, loaded at boot from a
secret manager or env file. If ZEQ_FIELD_KEY rotates, all credentials
become un-decryptable; rotation requires a re-paste.
The full key is echoed exactly once in the create response. After that, only the prefix is ever returned. Same posture as GitHub / Stripe — copy it now or re-create.
How agents use them
Pass a credential_id to any of the agent endpoints that take an LLM:
import { ZeqClient } from "@zeq-os/sdk";
const z = new ZeqClient({ origin: "https://YOUR-FRAMEWORK", apiKey: "zeq_ak_..." });
// Spawn an agent that uses your OpenAI credential for per-tick enrichment
const run = await z.agent.spawn({
problem: "shielding for Mars transit",
population: 4,
generations: 3,
precision: 0.001,
credential_id: "5b7a9c12-..." // your OpenAI BYOK
});
If you omit credential_id, the agent runs in deterministic-only mode
(no LLM enrichment) and the spawn cost stays 75 ZEQ. With a BYOK
credential the framework charge is identical; the LLM tokens hit your
provider's bill.
Free tier (no BYOK needed)
The framework's free tier uses Fireworks via the system-default
credential the foundation seeds. Limit: ~10 chats/day per visitor IP,
applied to /api/chat/free. Good enough for the Pulse's guest mode and
orientation; not enough to run a real workload.
If you need more, two paths:
- Upgrade your tier — Starter ($29/mo) raises your daily ZEQ to 500, which buys ~20 page-chat messages or ~5 HTML generations on the framework's pool.
- Add a BYOK credential — bypass the daily ZEQ cap entirely for LLM token cost; pay your provider directly.
Credential rotation
# Test a key without saving (paid-tier only)
curl -X POST https://YOUR-FRAMEWORK/api/zeq/llm/credentials \
-H "Authorization: Bearer zeq_ak_..." \
-H "Content-Type: application/json" \
-d '{
"provider": "openai",
"label": "prod-key-2026-q2",
"api_key": "sk-...",
"default_model": "gpt-4o"
}'
# Echoes the full key once in the response. Save it.
# Then revoke the old one:
curl -X DELETE https://YOUR-FRAMEWORK/api/zeq/llm/credentials/<old-id> \
-H "Authorization: Bearer zeq_ak_..."
Related
- Agents — what BYOK keys feed
- Pulse — guest mode uses the framework's Fireworks; signed-in mode uses BYOK if available
- ZEQ economy — what BYOK saves you
- API:
/api/zeq/llm/credentials/*— full CRUD reference - Design doc:
audits/2026-04-29-byok/_BYOK-DESIGN.md— the security posture