Bring your own key

Route a provider through your own account — your quota, the vendor’s bill, and no Onepin credits.

Onepin synthesizes on its own provider accounts by default and charges you credits for it. Connect your own key for a provider and that flips: every line routed to that provider goes through your account, the provider bills you directly, and Onepin charges 0 credits for it.

Connect a key

Provider keys live in the dashboard: app.onepin.aiSettings → API → BYOK providers.

This one is dashboard-only. The provider-key endpoints take a dashboard session, not an API key, so there is no SDK or CLI equivalent — connecting a key is the one part of BYOK you cannot script. Everything downstream of it (voices, runs, usage) is fully programmatic.

Which providers you can connect is derived from the live catalog rather than a fixed list, so what the dashboard offers is the answer for your workspace.

Two things gate it:

  • Your plan. BYOK is a plan feature. Read the flag instead of hardcoding tier names, which change:

    curl https://api.onepin.ai/api/v1/users/me/limits \
    -H "Authorization: Bearer $ONEPIN_API_KEY"
    # → {"data": {"byok_enabled": true, "auto_fix_enabled": …, …}}
  • Your role. Adding or replacing a key needs workspace admin. Everyone in the workspace synthesizes through a connected key; only an admin can connect one.

The credential is verified against the provider before it is stored. A key the provider rejects never reaches “Connected” — it fails at save time rather than at run time.

What changes once it’s connected

Platform defaultYour key
Who pays the providerOnepinYou
Credits chargedThe model’s per-character rate0
Counted in usageYesYes

Four consequences worth knowing before you connect one:

  • Routing is per provider, not per voice. Every line whose voice belongs to that provider uses your key — platform catalog voices included. There is no per-workflow or per-voice opt-in.
  • There is no silent fallback. If your key fails, the line fails. Onepin will not quietly re-synthesize it on its own account and bill you for it.
  • Auto-routing keeps your providers in play. Auto-route normally skips a model that carries no platform credit rate. For a provider you hold a valid key for that filter is relaxed — you’re paying the vendor, so the model is usable.
  • Usage still counts the volume. A node’s processed_units counts BYOK characters while its credits_fractional stays 0. That gap is by design, and it’s one reason units × rate doesn’t reproduce the credits on a run — see Check usage.

Imported voices

Some providers bring more than synthesis. For those, connecting the key also imports the voices you cloned in that provider account into your workspace catalog; the dashboard marks them with an Imports voices badge. The rest only unlock synthesis on your own quota.

An imported voice reads as source: "provider_imported" on the voice object, and unlike a platform voice it carries an import lifecycle that can go wrong:

v = client.voices.get(voice_id="...").data
if v.source == "provider_imported" and v.availability == "unavailable":
print("can't use this one:", v.unavailable_reason)
unavailable_reasonWhat happened
reconciliation_pendingThe import hasn’t caught up with your provider account yet
provider_key_unavailableThe key behind the import is gone or no longer valid
provider_voice_missingThe voice was deleted in your provider account
provider_import_unavailableThe voice can’t be synthesized as imported — typically the provider never says which locales it speaks

Unavailable voices stay listed and readable, but a workflow that references one is rejected at save, at run start, and at synthesis. See Browse voices.

Pin an imported voice by its catalog id

A Generator’s voice_map normally pins a voice by the provider’s own voice id. That is not enough for an imported voice: a provider wire id is unique per workspace, not globally, so it cannot say whose import you mean. The assignment must also carry catalog_voice_id, the Onepin catalog UUID:

node["config"] = {"voice_map": {"en-us": [
{"voice_id": v.provider_voice_id,
"catalog_voice_id": v.id, # required for source: "provider_imported"
"provider": "elevenlabs",
"model": "eleven_multilingual_v2"}
]}}

Without it the definition is rejected with rule voice_imported_needs_catalog_id, and a catalog_voice_id naming a different voice than the wire id is rejected as voice_catalog_id_mismatch. Neither is a permission problem — the voice is present and usable, the reference just doesn’t identify it.

When a key fails mid-run

A provider answers 401/403 both for a dead key and for a voice your provider plan doesn’t include, so Onepin re-runs its credential probe before deciding which happened:

  • The probe rejects the credential — the key is marked invalid, you get a “Your provider API key failed” email, and imported voices behind it go provider_key_unavailable. Reconnect by replacing the key in Settings → API.
  • The probe passes — only that line fails, and the key stays valid. Pick a voice your provider plan covers.

Lines that were already synthesized are unaffected, and lines routed to providers you have no key for keep running on the platform default. A BYOK failure narrows to the provider it belongs to.

  • Check usage — what BYOK volume does and doesn’t charge
  • Browse voices — imported voices and availability
  • Auto-route — how a connected key widens the candidate set
  • Generatorvoice_map and its identifier traps