opboxDocs
Sign inBook a demo
DocsBYOK CredentialsAI - Foundations

BYOK Credentials

Opbox uses bring-your-own-key (BYOK) for AI credentials. Every server-side AI call - chat, agent worker, workflow AI step, extraction, doc-gen detection - resolves a key through a four-tier chain in priority order.

Five providers are supported: Anthropic (Claude), OpenAI (GPT/o-series), Groq, OpenClaw (a long-lived stateful AI runtime exposed as an OpenAI-compatible gateway with per-agent routing - see OpenClaw Provider), and Hermes (per-tenant onyx-prod runtime exposed as an OpenAI-compatible gateway - see Hermes Provider).

OpenClaw takes precedence. Once OpenClaw is fully configured (bearer + endpoint + agent ID at any tier), the resolver returns it as the active provider regardless of chatProvider. To opt out, pin chatProvider to anthropic or openai explicitly. This is deliberate - configuring OpenClaw is itself a deliberate org-level act, so it's implicitly active.

The Four Tiers

#TierModelScopeSets Cost Source
1PersonalUserAiConfigOne user, one workspaceUSER_KEY
2WorkspaceWorkspaceAiConfigAll users in one workspaceWORKSPACE_KEY
3OrganisationOrganizationAiConfigAll workspaces in one orgORG_KEY
4Server envANTHROPIC_API_KEY, OPENAI_API_KEYServer-level fallbackSERVER_KEY

Resolution rule: walk top to bottom, first non-empty key wins, per field. The tier that supplied the key is recorded as keySource and flows into the cost ledger so spend can be attributed.

Field-level inheritance is the non-obvious bit. Filling the Anthropic key on Personal but leaving OpenAI fields blank means only Anthropic calls use your personal key - your OpenAI calls still draw from a lower tier.

Where to Configure

Settings > AI is a tabbed page. Tabs are ordered by resolver priority, left = highest:

TabVisible toSaves to
PersonalEvery memberUserAiConfig (you, this workspace)
WorkspaceOWNER / ADMINWorkspaceAiConfig (this workspace)
OrganisationOWNER / ADMINOrganizationAiConfig (this org)

Members see only the Personal tab. Admins/owners see all three plus the admin-only Doc Gen / Cost Control / Activity Timeline / Tool Catalogue sections below.

Configurable Fields per Tier

FieldPurpose
anthropicApiKeyClaude models (chat, workflow steps, extraction, doc-gen detection)
anthropicModelDefault Claude model. Blank uses the resolver default (currently claude-sonnet-4-5-20250929).
openaiApiKeyGPT / o-series models + Whisper transcription API
openaiModelDefault GPT model. Blank uses the resolver default (gpt-4o).
groqApiKeyGroq-hosted chat/transcription models.
groqModelDefault Groq model. Blank uses the resolver default.
hermesBearerTokenTenant Hermes API bearer. AES-256-GCM encrypted at rest.
hermesEndpointUrlTenant base URL, for example https://gateway.opbox.app/tenant/classical-visas. Opbox appends /v1/chat/completions.
chatProviderauto / anthropic / openai / groq / hermes / openclaw. Explicit selections fall back if the key isn't available.
systemPromptCustom instructions prepended to the assistant's built-in system prompt (max 2000 chars on UI; 8000 on API).
responseDetailconcise / standard / detailed - controls assistant verbosity.
monthlyTokenCapInformational soft ceiling. Hard enforcement lives in Cost Control.

All API keys are AES-256-GCM encrypted at rest and masked (****last4) on reads.

Storage & Encryption

  • Key ciphertext is stored directly in the database column.
  • The encryption secret is held on the server, never exposed to the client.
  • Key rotation: enter a new value in the field; the old ciphertext is overwritten. keyVerifiedAt is reset; the nightly verify-ai-keys cron re-probes.
  • A masked summary (****abcd) is shown in the UI. The full plaintext is never returned to the client.

Key Verification

A nightly cron (/api/cron/verify-ai-keys) probes every configured key against /v1/models?limit=1 (the cheapest authenticated provider endpoint). Outcome:

Probe ResultAction
200 OKkeyVerifiedAt = now()
401 / 403keyVerifiedAt = null (re-enter to re-verify)
Network error / 5xxNo change (transient)

The Settings page renders a green "Verified DD-MM-YYYY" chip when valid and a "Key rejected by provider - re-enter to re-verify" warning when the verification stamp is null but a key is configured.

Org Policy: Disable Personal Keys

Orgs that need cost control, compliance gates, or strict audit attribution can disable the personal tier entirely.

OrganizationAiConfig.allowPersonalKeys is a boolean (default true). Toggle on the Organisation tab in Settings > AI:

Allow members to override with personal AI keys When off, the resolver skips the user tier and forces every AI call onto workspace -> organisation -> server credentials. Useful for cost-control, compliance, and audit-attribution. Existing personal keys are preserved (read-only) so toggling back on restores each member's setup.

What happens when you turn it off:

BehaviourResult
ResolverSkips the user tier entirely - even if UserAiConfig rows exist.
Existing rowsPreserved on disk. Toggle back on and they take effect again.
Personal pageRenders read-only with a "Personal keys are disabled by your organisation" banner.
Personal API (PATCH /api/settings/ai-config/personal)Rejects with 403 PERSONAL_KEYS_DISABLED (defense-in-depth at the write boundary).
Cost ledgerNew calls bill the next-tier-down key source. Historical USER_KEY rows remain.

When to use it:

  • Cost control - all spend must flow through org-billed keys for chargeback/budgeting.
  • Compliance - the org has a vetted enterprise contract with DPA + zero-retention; personal keys would have unknown terms.
  • Audit attribution - "all our AI usage went through these audited keys" must be true at the policy level, not the observability level.

API: Tier Endpoints

Every tier has its own endpoint. CSRF-protected on writes. Schema-validated on input. Audit-logged on all writes.

TierEndpointMethodsRequired Role
Personal/api/settings/ai-config/personalGET / PATCH / DELETEMember
Workspace/api/settings/ai-configGET / PATCH / DELETEOWNER / ADMIN
Organisation/api/organizations/[orgId]/ai-configGET / PUT / DELETEOWNER / ADMIN

Every endpoint returns:

  • config - the masked tier row (or null if not configured)
  • summary - quick-glance booleans (anthropicConfigured, openaiConfigured, model + chatProvider, etc.)
  • allowPersonalKeys (Personal + Organisation only) - the active org policy

Live Model Catalogue

/api/ai/models proxies the provider's /v1/models endpoint live, using the stored BYOK key. Five-minute in-memory cache keyed by provider:sha256(key). Falls back to a curated whitelist if the live call fails or no key is configured.

This is what powers the model dropdowns in Settings > AI. Means you can pick any model your account has access to, including ones released after the last Opbox deploy.

Resolver Output

For any given workspace and (optional) user, the resolver returns:

  • provider - the chosen provider (anthropic, openai, groq, hermes, or openclaw)
  • apiKey - plaintext key (server-only, never sent to the client)
  • model - the default model for that provider (e.g. claude-sonnet-4-5-20250929)
  • systemPrompt - custom org/workspace/user prompt prefix, or null
  • responseDetail - concise / standard / detailed, or null
  • monthlyTokenCap - informational soft ceiling, or null
  • chatProvider - auto, anthropic, openai, groq, hermes, or openclaw
  • keySource - which tier supplied the key (user / workspace / org / server)

Provider-specific lookups (used for transcription, OCR, embeddings, integrations) bypass chatProvider and return null if that provider isn't configured at any tier.

Cross-Tenant Defence

When authorityWorkspaceId differs from workspaceId, the resolver runs a second authorisation check on top of the MCP router's primary check:

  • Authority must hold an ACTIVE oversight relationship over the target, OR
  • Authority's org must be a super-org managing the target's org.

A bug in the MCP router would otherwise silently let an overseer key spend the target's credentials. This is the second wall.

See Also

We use cookies

Strictly necessary cookies keep you signed in and protect requests. We also use optional cookies for preferences and (when enabled) analytics. Learn more.