Realtime API Key Guide

Authenticate with user API keys and call GPT Realtime voice endpoints.

Getting started

Create a key from Settings -> API Keys, then use it when calling the Realtime API from a backend service or another trusted runtime. Each key is tied to the user who created it, so credits are checked and charged against that user's account.

You can pass the key as a bearer token:

Authorization: Bearer sk-gptr2-xxx

or with the API key header:

x-api-key: sk-gptr2-xxx

Do not expose API keys in public client-side code unless you fully trust that environment.

Model reference

Model valueBest forEndpoint
starter-voiceSimple text/audio request cyclesPOST /api/realtime/pipeline
realtime-miniLower-cost live WebRTC voicePOST /api/realtime/session and POST /api/realtime/charge
realtime-proHigher-quality live WebRTC voicePOST /api/realtime/session and POST /api/realtime/charge

Supported voices:

marin, cedar, coral, sage, ash, verse

Starter voice pipeline

Use the pipeline endpoint when you want one HTTP request to handle speech-to-text, assistant response generation, and text-to-speech.

Text request

curl "$APP_URL/api/realtime/pipeline" \
  -H "Authorization: Bearer $GPTREALTIME_API_KEY" \
  -F "model=starter-voice" \
  -F "voice=marin" \
  -F "text=Give me a 20-second product update." \
  -F "instructions=Sound natural and concise."

The response includes the assistant text plus an MP3 payload encoded as base64:

{
  "transcript": "",
  "assistantText": "Here is the short version...",
  "audioBase64": "...",
  "audioContentType": "audio/mpeg",
  "model": "gpt-4o-mini",
  "modelId": "starter-voice",
  "voice": "marin"
}

Audio request

curl "$APP_URL/api/realtime/pipeline" \
  -H "x-api-key: $GPTREALTIME_API_KEY" \
  -F "model=starter-voice" \
  -F "voice=cedar" \
  -F "durationSeconds=10" \
  -F "audio=@./message.webm;type=audio/webm" \
  -F "instructions=Reply in one or two sentences."

Pipeline fields:

FieldRequiredNotes
modelYesMust be starter-voice for this endpoint.
textNoText prompt. Provide text, audio, or both.
audioNoAudio file up to 25 MB.
durationSecondsNoAudio duration hint when audio is supplied.
messagesNoRecent context as JSON, such as [{"role":"user","text":"Hello"}].
instructionsNoAssistant behavior instructions, capped at 4,000 characters.
voiceNoDefaults to marin when omitted.

Live WebRTC sessions

Use the session endpoint for low-latency voice conversations. Your client creates an SDP offer, sends it to the API, and receives an SDP answer.

const appUrl = process.env.APP_URL!;
const apiKey = process.env.GPTREALTIME_API_KEY!;

const peer = new RTCPeerConnection();
peer.addTransceiver('audio', { direction: 'sendrecv' });

const offer = await peer.createOffer();
await peer.setLocalDescription(offer);

const sessionResponse = await fetch(`${appUrl}/api/realtime/session`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'realtime-mini',
    voice: 'marin',
    instructions: 'Keep answers short and conversational.',
    sdp: offer.sdp,
  }),
});

if (!sessionResponse.ok) {
  throw new Error(await sessionResponse.text());
}

const answer = await sessionResponse.text();
const callId = sessionResponse.headers.get('x-openai-call-id') || '';

await peer.setRemoteDescription({
  type: 'answer',
  sdp: answer,
});

For GPT Realtime 2 quality, send realtime-pro instead of realtime-mini:

{
  "model": "realtime-pro",
  "voice": "marin",
  "instructions": "You are a premium realtime voice assistant.",
  "sdp": "v=0..."
}

Charging realtime calls

After the realtime response completes, call the charge endpoint with the same key and model so the session can be finalized.

curl "$APP_URL/api/realtime/charge" \
  -H "Authorization: Bearer $GPTREALTIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"realtime-mini","callId":"call_abc123"}'

Use realtime-pro in the payload when the session was started with the pro model.

Error responses

Errors are returned as JSON for API routes that use JSON responses:

{
  "code": "invalid_api_key",
  "message": "API key is invalid or has been deleted."
}

Common cases:

HTTP statusCodeWhat to check
400unsupported_modelThe selected endpoint does not accept that model.
400invalid_sdpWebRTC session requests require a valid SDP offer.
401invalid_authorizationThe Authorization header format is invalid.
401invalid_api_keyThe provided key is missing, deleted, or inactive.
401unauthorizedNo signed-in session or API key was provided.
402insufficient_creditsAdd credits or choose a lower-cost model.
500api_key_lookup_failedRetry after the API key database is available.