Skip to main content

Overview

Client secret APIs handle the creation of secure, ephemeral tokens for authenticating with the OpenAI Realtime API. These tokens have configurable TTL and support session configuration.

createRealtimeClientSecret

Function Signature

async function createRealtimeClientSecret(
  opts: NavaiVoiceBackendOptions,
  req?: CreateClientSecretRequest
): Promise<OpenAIRealtimeClientSecretResponse>
Source: packages/voice-backend/src/index.ts:160

Description

Creates an ephemeral client secret by calling OpenAI’s Realtime API. Validates options, resolves API key based on configuration policy, builds session instructions with language/accent/tone preferences, and returns the client secret with expiration.

Parameters

opts
NavaiVoiceBackendOptions
required
Backend configuration options
req
CreateClientSecretRequest
Per-request overrides for session configuration

Return Value

OpenAIRealtimeClientSecretResponse
Promise<OpenAIRealtimeClientSecretResponse>

API Key Resolution

API key is resolved with strict priority:
  1. Backend key wins: If opts.openaiApiKey is set, it is always used
  2. Request key fallback: If backend key is missing, req.apiKey is used only if opts.allowApiKeyFromRequest is true
  3. Error: If no key is available, throws an error

Validation Rules

  • Throws if openaiApiKey is missing and allowApiKeyFromRequest is false
  • Throws if clientSecretTtlSeconds is not between 10 and 7200
  • Throws if OpenAI API call fails (network error, invalid credentials, etc.)

Session Instructions

Final instructions are built by combining:
  1. Base instructions from req.instructions or opts.defaultInstructions
  2. Optional language directive: "Always reply in {language}."
  3. Optional accent directive: "Use a {voiceAccent} accent while speaking."
  4. Optional tone directive: "Use a {voiceTone} tone while speaking."

Usage Example

import { createRealtimeClientSecret } from "@navai/voice-backend";

const options = {
  openaiApiKey: process.env.OPENAI_API_KEY,
  defaultModel: "gpt-realtime",
  defaultVoice: "marin",
  clientSecretTtlSeconds: 600
};

const request = {
  instructions: "You are a friendly travel assistant.",
  language: "Spanish",
  voiceAccent: "neutral Latin American Spanish",
  voiceTone: "warm and enthusiastic"
};

const secret = await createRealtimeClientSecret(options, request);
console.log(secret.value); // "ek_..."
console.log(secret.expires_at); // 1730000000

createExpressClientSecretHandler

Function Signature

function createExpressClientSecretHandler(
  opts: NavaiVoiceBackendOptions
): (req: Request, res: Response, next: NextFunction) => Promise<void>
Source: packages/voice-backend/src/index.ts:207

Description

Creates an Express middleware handler for the client secret endpoint. Validates options on creation, then handles incoming requests by calling createRealtimeClientSecret with the request body.

Parameters

opts
NavaiVoiceBackendOptions
required
Backend configuration options (same as createRealtimeClientSecret)

Return Value

handler
(req: Request, res: Response, next: NextFunction) => Promise<void>
Express middleware handler that:
  • Reads CreateClientSecretRequest from req.body
  • Calls createRealtimeClientSecret(opts, req.body)
  • Responds with { value, expires_at }
  • Passes errors to next(error)

Usage Example

import express from "express";
import { createExpressClientSecretHandler } from "@navai/voice-backend";

const app = express();
app.use(express.json());

const handler = createExpressClientSecretHandler({
  openaiApiKey: process.env.OPENAI_API_KEY,
  defaultModel: "gpt-realtime",
  defaultVoice: "marin",
  clientSecretTtlSeconds: 600
});

app.post("/api/realtime-token", handler);

app.listen(3000);

getNavaiVoiceBackendOptionsFromEnv

Function Signature

function getNavaiVoiceBackendOptionsFromEnv(
  env?: Record<string, string | undefined>
): NavaiVoiceBackendOptions
Source: packages/voice-backend/src/index.ts:114

Description

Loads backend options from environment variables with smart defaults for API key policy.

Parameters

env
Record<string, string | undefined>
default:"process.env"
Environment variables object

Return Value

NavaiVoiceBackendOptions
NavaiVoiceBackendOptions
Backend options populated from environment variables

Environment Variables

VariableOptionDefault
OPENAI_API_KEYopenaiApiKey-
OPENAI_REALTIME_MODELdefaultModel-
OPENAI_REALTIME_VOICEdefaultVoice-
OPENAI_REALTIME_INSTRUCTIONSdefaultInstructions-
OPENAI_REALTIME_LANGUAGEdefaultLanguage-
OPENAI_REALTIME_VOICE_ACCENTdefaultVoiceAccent-
OPENAI_REALTIME_VOICE_TONEdefaultVoiceTone-
OPENAI_REALTIME_CLIENT_SECRET_TTLclientSecretTtlSeconds600
NAVAI_ALLOW_FRONTEND_API_KEYallowApiKeyFromRequestSee below

API Key Policy Logic

if (OPENAI_API_KEY exists) {
  allowApiKeyFromRequest = NAVAI_ALLOW_FRONTEND_API_KEY === "true"
} else {
  allowApiKeyFromRequest = true // Fallback mode
}

Usage Example

import { getNavaiVoiceBackendOptionsFromEnv } from "@navai/voice-backend";

// Load from process.env
const options = getNavaiVoiceBackendOptionsFromEnv();

// Or provide custom env
const customOptions = getNavaiVoiceBackendOptionsFromEnv({
  OPENAI_API_KEY: "sk-...",
  OPENAI_REALTIME_MODEL: "gpt-realtime",
  OPENAI_REALTIME_VOICE: "marin",
  OPENAI_REALTIME_CLIENT_SECRET_TTL: "600"
});

Common Errors

Missing API Key

Missing openaiApiKey in NavaiVoiceBackendOptions.
Cause: Neither openaiApiKey nor allowApiKeyFromRequest is configured. Solution: Set OPENAI_API_KEY or enable allowApiKeyFromRequest.

Request API Key Disabled

Passing apiKey from request is disabled. Set allowApiKeyFromRequest=true to enable it.
Cause: Client sent apiKey in request body but allowApiKeyFromRequest is false. Solution: Set NAVAI_ALLOW_FRONTEND_API_KEY=true or configure backend API key.

Invalid TTL

clientSecretTtlSeconds must be between 10 and 7200. Received: 8000
Cause: TTL value is outside the valid range. Solution: Set clientSecretTtlSeconds between 10 and 7200 seconds.

OpenAI API Failure

OpenAI client_secrets failed (401): Invalid API key
Cause: OpenAI API rejected the request. Solution: Verify your API key is valid and has Realtime API access.

Build docs developers (and LLMs) love