Authentication

Get an API secret, set it for the right surface, and understand how it is exchanged for short-lived runtime tokens.

One credential, two names

bitHuman uses a single shared credential per account that authenticates every SDK and the REST API. There are two equivalent environment-variable names depending on which surface you’re using:

  • BITHUMAN_API_SECRET — Python SDK, REST API, LiveKit plugin, Kotlin SDK, and CLI.
  • BITHUMAN_API_KEY — Swift SDK on Apple platforms. Same value, different name to match Apple convention.

Tip You only need a key when an avatar is rendering. Audio-only voice agents (Swift VoiceChat with no config.avatar) run fully offline without one — see pricing for what’s free vs. metered.

Get a key

  1. Sign in at bithuman.ai (free tier, no credit card).
  2. Go to Developer → API Keys.
  3. Click Create new key, name it (e.g. production-mac), and copy the value. You won’t be able to view it again — store it somewhere durable.

Verify it works

curl -X POST https://api.bithuman.ai/v1/validate \
  -H "api-secret: YOUR_KEY"

A 200 with {"valid": true} means you’re good. If you have the CLI installed, bithuman doctor also checks the credential, brain selection, caches, and host capabilities.

Set it for each surface

REST APIapi-secret header on every request:

curl -X POST https://api.bithuman.ai/v1/agent/A78WKV4515/speak \
  -H "api-secret: $BITHUMAN_API_SECRET" \
  -H "content-type: application/json" \
  -d '{"message": "Hello"}'

Python SDK — env var, or pass directly:

runtime = await AsyncBithuman.create(
    model_path="avatar.imx",
    api_secret="your_key",
)

Swift SDK — env var or config; never hardcode in source:

// development: env var
config.apiKey = ProcessInfo.processInfo.environment["BITHUMAN_API_KEY"]
// production: fetch from your backend via Keychain
config.apiKey = await fetchFromBackend()

For DMG distribution, bake the key into Info.plist via a build script. For App Store, fetch from your own backend via Keychain on first launch — don’t bundle.

api-secret vs. runtime tokens

The long-lived api-secret is never sent to the avatar engine or any third party. It only ever travels to api.bithuman.ai over TLS. The streaming runtime is authorized by a separate, short-lived runtime token:

  1. Your code provides the API secret to the SDK or REST request.
  2. The SDK exchanges it for a short-lived runtime token at POST /v1/runtime-tokens/request.
  3. That token authorizes the avatar engine (heartbeat + frame production) for a single session.
  4. Tokens auto-renew roughly every 60 seconds via the heartbeat.
  5. Bad keys fail at step 2 — fast — before any user-visible work.

The runtime token is not an api-secret. It can’t mint other tokens; it just authorizes the runtime to compute frames for one specific session. It is HS256-signed with a short TTL and carries iss=bitHuman, sub=<user_id>, and aud=<fingerprint> claims. The SDKs and LiveKit plugin handle this loop for you — you rarely call /v1/runtime-tokens/request directly. For browser embeds, use the more constrained embed token flow instead.

Audio-only Swift mode is unmetered

If you only want on-device voice chat (no lip-synced avatar), skip the API key entirely:

var config = VoiceChatConfig()
config.systemPrompt = "You are a helpful assistant."
config.voice = .preset("Aiden")
// no config.avatar = ...

let chat = VoiceChat(config: config)
try await chat.start()  // does not authenticate

This mode runs fully offline (after first-launch weight downloads), bills nothing, and doesn’t require a key.

Rotating keys

Rotate from the Developer dashboard. Rotation invalidates the old key immediately — there’s no overlap window. Live sessions using the old key fail their next heartbeat (within ~60 s) and pause; restart with the new key to resume. Rotate during a maintenance window if you have production sessions running.

Common errors

ErrorCauseFix
401 from REST APIMissing or invalid api-secret headerAdd the header on every request; re-verify with /v1/validate.
Authentication failed (Python)Wrong/missing BITHUMAN_API_SECRETVerify with the curl /v1/validate recipe.
VoiceChatError.missingAPIKey (Swift)Avatar mode without apiKey setSet config.apiKey or export BITHUMAN_API_KEY.
Heartbeat silent after 5 minNetwork dropped on-deviceReconnect; the SDK pauses the avatar after the grace window and resumes when heartbeats succeed.

See the full error reference.