Authentication
API key authentication
Authenticate server-side requests directly with your API key.
API key authentication sends your key directly in the Authorization header. It is the simplest way to call Inworld APIs and the right choice for anything that runs on your servers.
The header
Use the Base64 credentials you copy from Inworld Portal or the Inworld CLI as-is:
Authorization: Basic $INWORLD_API_KEYINWORLD_API_KEY means the complete encoded credential, with no Basic prefix. Portal's Base64 copy action returns base64(key_id:secret). The CLI's inworld auth print-api-key prints that same representation for the selected key (or echoes INWORLD_API_KEY if it is already set). Neither output needs another encoding step.
- The key ID identifies the key; it cannot authenticate by itself.
- The secret proves ownership. If an SDK explicitly asks for separate key and secret fields, supply those separate values.
- The Base64 credential combines the ID and secret. Encoding is reversible; treat the whole string as a secret.
- The CLI’s
inworld auth print-access-tokenreturns its signed-in user access token. It is distinct fromprint-api-keyand from the client tokens minted below; do not substitute it into these runtime examples. - A minted token is a different credential, returned as
accessTokenortokenby a token endpoint. Use it with Bearer, without Base64 encoding it.
Only when you have separate ID and secret values, construct the combined credential once on your server:
const apiKey = Buffer.from(`${keyId}:${secret}`, 'utf8').toString('base64');Do not encode a copied Base64 credential again, use a key ID alone, or pass the combined credential to a username/password helper that encodes it again.
For example, after setting INWORLD_API_KEY to the copied Base64 value:
curl https://api.inworld.ai/tts/v1/voices \
--header "Authorization: Basic $INWORLD_API_KEY"Basic versus Bearer
Use Authorization: Basic $INWORLD_API_KEY for direct server requests. Keep the copied credential unchanged and on your server. For SDK requests, follow the complete OpenAI SDK or Anthropic SDK configuration.
Use Bearer for a backend-minted client token. Changing an API key's prefix to Bearer does not turn it into a short-lived token or make it safe for client code.
Where it works
The documented platform endpoints accept direct API key authentication, subject to the key’s permissions: TTS, STT, LLM, Voices, Realtime, and the one-time token mint. WebSocket endpoints accept the same header on the connection request. The one exception is the session token mint, which authenticates with a signed request instead of the plain header.
Store the key as an environment variable or in a secret manager, and read it at runtime — see Security best practices for handling rules and what to do if a key leaks.
Recover from authentication failures
Read the response body as well as the HTTP status. Invalid keys can return 403, and a 403 can also mean a valid credential lacks permission.
| Failure | What to do |
|---|---|
| Missing or malformed authorization; invalid credentials; key deleted or not found (401 or 403) | Check that the environment variable is nonempty in the process making the request. Copy the full Base64 credential again, remove quotes/whitespace accidentally included in its value, and send exactly one Basic prefix. Check the key is active and belongs to the intended environment. Do not double encode. |
| Invalid, expired, or already-used token | Obtain a fresh token from your backend. Mint a new one-time token for every request or connection attempt, including retries after a later request failure. |
| Required scopes or workspace access denied (403) | Check the selected workspace and key type. A Realtime-only key cannot call TTS or Router directly. Use a Standard key for those APIs; use a key with access to the workspace containing the requested resource. |
| Voice or Router write operation denied (403) | Enable the relevant write permission. Calling TTS or chat completions does not require these write toggles; creating a router or cloning a voice does. Mint a fresh token after changing permissions. |
| Token mint refuses Bearer (403) | Call /auth/v1/tokens from your backend with the Base64 API credential under Basic, even if Bearer works for chat completions. |
| Single-use token cannot open Realtime (403) | Use a backend-minted session token, or connect through a server proxy using Basic. |
| Session-token signature rejected | Check the server's UTC clock, key ID/secret pair, signed host and method. Generate a fresh timestamp, nonce, and signature for each attempt; use the session mint example. |
| Credit/plan failure (402), rate/concurrency limit (429), or server error (5xx) | Follow the response's billing, limit, or retry guidance. These statuses do not establish that your key is invalid. Back off on retryable failures; obtain a fresh one-time token for the next attempt. |
If the problem persists, share the endpoint, status, redacted error message, and request ID with support. Never include the authorization header or token.