BYOK Providers#
Use one Supafone API key, or bring your own keys for the speaking model, the Supervisor, or both. BYOK means “bring your own key.”
| Choice | Speaking model | Supervisor |
|---|---|---|
| One Supafone key | Supafone's configured provider key | Supafone's managed reasoning |
| Your keys | Your Ultravox, OpenAI, Gemini, Grok or Hydra key | Your supported reasoning-provider key |
| Mix them | Your key or Supafone's key | Choose independently of the speaking model |
Bring both keys: a short example#
This example uses your OpenAI key for speech and your Anthropic key for Supervisor. Your Supafone account key still authenticates both configuration requests.
import os
from supafone_labs import Supafone, SupafoneS2S
client = Supafone(api_key=os.environ["SUPAFONE_API_KEY"])
client.labs.runtime.configure(
provider="openai", mode="byok",
credentials={"api_key": os.environ["OPENAI_API_KEY"]},
)
agent = SupafoneS2S(client, provider="openai").create(
name="Front desk",
supervisor={"enabled": True, "mode": "byok", "provider": "anthropic",
"api_key": os.environ["ANTHROPIC_API_KEY"]},
)import { Supafone, SupafoneS2S } from "supafone-labs";
const client = new Supafone({ apiKey: process.env.SUPAFONE_API_KEY! });
await client.labs.runtime.configure({
provider: "openai", mode: "byok", credentials: { apiKey: process.env.OPENAI_API_KEY! },
});
const agent = await new SupafoneS2S(client, { provider: "openai" }).create({
name: "Front desk",
supervisor: { enabled: true, mode: "byok", provider: "anthropic",
apiKey: process.env.ANTHROPIC_API_KEY! },
});To use Supafone-managed Supervisor with your speaking key, replace the Supervisor object with {enabled: true, mode: "managed"} (Python: {"enabled": True, "mode": "managed"}). To use Supafone's speaking key with your Supervisor key, omit the runtime configuration request on an account without a speaking-key override.
The managed path needs configured platform credentials. A saved speaking key takes priority across the account; Supervisor BYOK belongs to the agent. Runtime changes require account-admin permission and apply to future calls. Usage is billed according to the selected provider and Supafone services. Supervisor providers and models lists the supported reasoning choices.
Choose speaking keys for all five S2S families#
SupafoneS2S uses the account's saved speaking-provider key when one exists; otherwise it uses Supafone's configured platform key. Configure keys through client.labs.runtime, then create or switch an agent with SupafoneS2S. Vendor keys belong in account runtime configuration, not the S2S constructor or the agent's realtime selection.
| Speaking family | Runtime provider ID | Your key's environment variable |
|---|---|---|
| Ultravox | ultravox | ULTRAVOX_API_KEY |
| OpenAI | openai | OPENAI_API_KEY |
| Gemini | google | GEMINI_API_KEY or GOOGLE_API_KEY |
| Grok | xai | XAI_API_KEY |
| Smallest AI Hydra | smallest | SMALLEST_API_KEY |
Environment names are conventions: the SDK sends the key you explicitly read. The CLI's --api-key-env can read any named variable. SUPAFONE_API_KEY authenticates your Supafone account separately. Keep keys in trusted server code or your local secret store.
Use Supafone's platform keys#
Without an account override, no key setup request is needed. Create the agent using your Supafone key. To remove an existing override and return to platform defaults, select managed mode:
import os
from supafone_labs import Supafone, SupafoneS2S
client = Supafone(api_key=os.environ["SUPAFONE_API_KEY"])
provider = "openai" # Any runtime provider ID from the table above.
client.labs.runtime.configure(provider=provider, mode="supafone_managed")
engine = SupafoneS2S(client, provider=provider)
agent = engine.create(name="Front desk", supervisor=True)import { Supafone, SupafoneS2S } from "supafone-labs";
const client = new Supafone({ apiKey: process.env.SUPAFONE_API_KEY! });
const provider = "openai";
await client.labs.runtime.configure({ provider, mode: "supafone_managed" });
const engine = new SupafoneS2S(client, { provider });
const agent = await engine.create({ name: "Front desk", supervisor: true });Managed mode removes only the selected provider's encrypted account override. It requires account-admin permission and affects future calls for every agent in that account using that provider. It does not change other provider keys, speaking selections, carrier settings or Supervisor profiles. Do not include credentials with managed mode. Without a configured platform key, status reports source: "none"; choosing managed mode does not provision a key.
Bring your own speaking key#
Use the same route for any of the five provider IDs:
client.labs.runtime.configure(
provider="openai", mode="byok",
credentials={"api_key": os.environ["OPENAI_API_KEY"]},
)
status = client.labs.runtime.get(provider="openai")await client.labs.runtime.configure({
provider: "openai", mode: "byok",
credentials: { apiKey: process.env.OPENAI_API_KEY! },
});
const status = await client.labs.runtime.get({ provider: "openai" });Substitute the table's provider ID and matching key for Ultravox, Gemini, Grok or Hydra. The key is encrypted on the account and takes priority over the platform key. An unreadable override reports source: "invalid"; reconnect it or explicitly return to managed mode. This setting is account-wide, not a per-agent credential override.
CLI#
supafone runtime update --provider openai --mode byok --api-key-env OPENAI_API_KEY
supafone runtime update --provider gemini --mode byok --api-key-env GEMINI_API_KEY
supafone runtime update --provider grok --mode byok --api-key-env XAI_API_KEY
supafone runtime update --provider hydra --mode byok --api-key-env SMALLEST_API_KEY
supafone runtime update --provider ultravox --mode byok --api-key-env ULTRAVOX_API_KEY
# Inspect configuration, then explicitly restore this provider's platform key.
supafone runtime get --provider openai
supafone runtime update --provider openai --mode supafone_managed--credentials-file remains available for a JSON object containing api_key (and optionally base_url for Ultravox). Use it instead of --api-key-env. Do not put key values in command arguments. Credentials supplied through these inputs are scrubbed from CLI responses and error messages.
Readiness and compatibility#
runtime.get returns masked status. configured means an account override exists; connected means a usable key resolves. source is account, platform, none or invalid. These fields do not establish model permissions or successful calls. Earlier Ultravox responses use managed and byok_connected; updated responses retain these alongside the shared fields.
Omitting mode retains existing configure behavior. A blank key preserves an Ultravox override; native key updates require a nonempty key. Use explicit managed mode to remove an override.
Release and rollout: explicit managed reset, CLI environment-key input and TypeScript provider readiness are part of 0.7.2 and need the corresponding hosted backend. A configured key does not verify model access or call quality. See SDK installation and readiness.
Speaking-key selection does not select Supervisor's reasoning key. supervisor=True / true enables the default or saved coaching profile; supervisor={"enabled": True, "mode": "managed"} explicitly chooses platform reasoning. Supervisor BYOK has its own provider and key. See Supervisor Models: Managed and BYOK.
Managed compatibility defaults#
{
"labs": {
"enabled": true,
"mode": "supafone_managed",
"managedInfrastructure": true,
"model": "gemma"
},
"telephony": {
"mode": "supafone_managed",
"provider": "supafone"
}
}Use this when the developer wants to launch quickly and bill usage through Supafone.
Independent provider domains#
Do not collapse BYOK into one generic "provider keys" bucket. Hosted delivery has three independent provisioning lanes; Supervisor deployments add independent STT and supervisor-LLM credentials. These are five independent credential lanes:
| Lane | What it means | Common providers |
|---|---|---|
| Agent/provider stack | The realtime agent, orchestration, or model runtime the customer already runs | Any of the 14 audited runtime adapters |
| Telephony | The carrier, trunk, SIP, and phone-network layer | Twilio, Telnyx, Plivo, SignalWire, SIP/custom trunks |
| TTS | The voice-rendering provider | Cartesia, ElevenLabs, Inworld, Deepgram, custom TTS |
| STT | The transcript and language-authority provider | Deepgram or provider-native streams |
| Supervisor LLM | The model that forms Supervisor directives | Supafone managed, Claude, OpenAI, Gemini, OpenRouter, Groq, Cerebras |
These independent lanes do not imply fourteen hosted runtime choices. They describe the adapter and credential boundaries around a speaking runtime.
Each domain can be managed by Supafone or brought by the customer. For example, a customer can bring Telnyx telephony and Cartesia TTS while still using Supafone's managed supervisor, or bring an entire Ultravox stack and use Supafone only for self-healing directives and logs.
Managed compatibility and native S2S runtime#
Hosted Agent Factory has two direct speaking-runtime lanes. The managed Ultravox-compatible lane retains external TTS and language/voice profiles. The native realtime lane selects among six native catalog S2S models. Both share the custom stage planner, Manager, specialists and Supervisor, while recording, carrier controls and live model handoff have explicit limits. Telephony and credentials stay server-side.
Managed Ultravox-compatible runtime#
The hosted-agent managed compatibility runtime uses Supafone's platform key by default (managed billing). You can instead run agents on your own Ultravox account: your key, your billing. The agent is then both placed and monitored on your key, and runtime_mode becomes "byok".
Two ways to connect it:
1. At agent create, in the byok block:
{
"byok": {
"ultravox": {
"api_key": "uvx_...",
"base_url": "https://api.ultravox.ai/api"
}
}
}base_url is optional. A byok.credentials object is also accepted as the key holder. The key is stored encrypted on your account, never in the agent doc.
2. Later or standalone, via PUT /api/v1/labs/runtime:
curl https://api.supafone.ai/api/v1/labs/runtime \
-X PUT \
-H "Authorization: Bearer $SUPAFONE_LABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "ultravox",
"credentials": { "api_key": "uvx_...", "base_url": "https://api.ultravox.ai/api" }
}'With mode omitted, a blank Ultravox api_key keeps the stored key. Native provider updates require a nonempty key. Use the shared examples above to connect any speaking family or explicitly return to platform defaults. Earlier Ultravox deployments return this compatibility status shape:
{
"account_id": "...",
"provider": "ultravox",
"managed": false,
"byok_connected": true,
"base_url": "https://api.ultravox.ai/api",
"updated_at": "2026-07-11T00:00:00Z"
}This compatibility lane is distinct from native realtime and from the supervisor provider keys below: those bring your own STT/LLM/TTS for supervision, while this runs the agent itself on your Ultravox account. See Hosted Agents API for the full create/runtime contract and the runtime block returned on agent create.
Native realtime Agent Factory#
Native realtime uses realtime: { provider, model, voice } with gpt-realtime-2.1, gpt-live-1, gemini-3.1-flash-live-preview, grok-voice-latest, hydra-v1.0, or hydra-v1.1. Use a configured platform key or optionally connect an OpenAI, Google, xAI, or Smallest AI account key through PUT /api/v1/labs/runtime, then use Supafone-managed, Twilio, Telnyx, Plivo, or SIP phone transport. The native path shares the custom stage planner, Manager, specialist consultations and Supervisor, with opt-in recording, widgets and configured carrier controls. Keys and model access still need verification. See Shared runtime, Manager and teams.
All five Agent Factory speaking families support Supervisor coaching when enabled and configured. The native check_guidance tool returns guidance; Hydra uses model-reported context rather than transcripts. Speaking-model credentials and Supervisor credentials are separate readiness checks.
BYOK Supervisor Providers#
Supervisor BYOK is a per-agent supervisor object. It is separate from the speaking runtime, telephony, STT, and TTS lanes:
{
"supervisor": {
"enabled": true,
"mode": "byok",
"provider": "openai",
"model": "gpt-5-mini",
"api_key": "$OPENAI_API_KEY"
}
}The current first-class providers are anthropic, openai, gemini, openrouter, groq, and cerebras. Supafone uses each provider's fixed official endpoint, encrypts the submitted key, and never returns it. Use Supervisor Models: Managed and BYOK for complete Python, TypeScript, REST, and CLI examples for all six.
Supported agent/provider-stack fields include:
| Provider | Field |
|---|---|
| Ultravox | ultravoxApiKey |
| Retell | retellApiKey |
| Vapi | vapiApiKey |
| Bland | blandApiKey |
| LiveKit | livekitApiKey, livekitApiSecret |
| Pipecat | pipecatApiKey |
| OpenAI Realtime | openaiApiKey |
| Grok/xAI | xaiApiKey |
| Gemini Live | geminiApiKey or Google Cloud credentials |
| Inworld Realtime | inworldApiKey |
Supported TTS/STT fields include:
| Provider | Field |
|---|---|
| Deepgram | deepgramApiKey |
| Cartesia | cartesiaApiKey |
| ElevenLabs | elevenlabsApiKey |
| Inworld | inworldApiKey |
BYOK Telephony#
await supafone.labs.telephony.configure({
mode: "byok",
provider: "twilio",
credentials: {
accountSid: process.env.TWILIO_ACCOUNT_SID!,
apiKey: process.env.TWILIO_API_KEY_SID!,
apiSecret: process.env.TWILIO_API_KEY_SECRET!,
fromNumber: "+14155550123"
}
});The telephony BYOK provider can be twilio, telnyx, plivo, sip, or any provider label the hosted API supports for that account. The UI should show the common carriers but the SDK should pass through custom provider labels.
Common carrier credential fields:
| Provider | Common fields |
|---|---|
| Twilio | accountSid, authToken, apiKey, apiSecret, fromNumber |
| Telnyx | apiKey, connectionId, fromNumber |
| Plivo | authId, authToken, fromNumber |
| SignalWire | projectId, token, signalwireSpaceUrl, fromNumber |
| SIP/custom | sipTrunkUri, sipHost, username, password, headers |
Custom SIP:
await supafone.labs.telephony.configure({
mode: "byok",
provider: "sip",
customSip: {
sipTrunkUri: process.env.SIP_TRUNK_URI!,
username: process.env.SIP_USERNAME!,
password: process.env.SIP_PASSWORD!,
headers: { "X-Customer": "northline" }
}
});UI Credential Rules#
- Keep Supafone-managed selected by default.
- Store BYOK keys only through secure backend/account endpoints.
- Mask stored values on readback.
- Treat blank fields on update as "keep existing value."
- Never put provider secrets in exported code unless the user explicitly asks
- Export env var names, not raw secrets.
for env var placeholders.
Good exported code:
byok: {
agentProvider: {
provider: "ultravox",
apiKey: process.env.ULTRAVOX_API_KEY!
},
telephony: {
mode: "byok",
provider: "telnyx",
credentials: { apiKey: process.env.TELNYX_API_KEY! }
},
tts: {
provider: "cartesia",
apiKey: process.env.CARTESIA_API_KEY!
}
}Bad exported code:
providerKeys: {
cartesiaApiKey: "real-secret-here"
}When BYOK Is Worth It#
Use BYOK when the customer:
- already has a negotiated vendor contract,
- needs vendor-specific voice/model controls,
- has existing telephony compliance infrastructure,
- wants invoices to remain with the provider,
- needs migration from an existing voice stack.
Otherwise, use Supafone-managed.