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-xxxor with the API key header:
x-api-key: sk-gptr2-xxxDo not expose API keys in public client-side code unless you fully trust that environment.
Model reference
| Model value | Best for | Endpoint |
|---|---|---|
starter-voice | Simple text/audio request cycles | POST /api/realtime/pipeline |
realtime-mini | Lower-cost live WebRTC voice | POST /api/realtime/session and POST /api/realtime/charge |
realtime-pro | Higher-quality live WebRTC voice | POST /api/realtime/session and POST /api/realtime/charge |
Supported voices:
marin, cedar, coral, sage, ash, verseStarter 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:
| Field | Required | Notes |
|---|---|---|
model | Yes | Must be starter-voice for this endpoint. |
text | No | Text prompt. Provide text, audio, or both. |
audio | No | Audio file up to 25 MB. |
durationSeconds | No | Audio duration hint when audio is supplied. |
messages | No | Recent context as JSON, such as [{"role":"user","text":"Hello"}]. |
instructions | No | Assistant behavior instructions, capped at 4,000 characters. |
voice | No | Defaults 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 status | Code | What to check |
|---|---|---|
400 | unsupported_model | The selected endpoint does not accept that model. |
400 | invalid_sdp | WebRTC session requests require a valid SDP offer. |
401 | invalid_authorization | The Authorization header format is invalid. |
401 | invalid_api_key | The provided key is missing, deleted, or inactive. |
401 | unauthorized | No signed-in session or API key was provided. |
402 | insufficient_credits | Add credits or choose a lower-cost model. |
500 | api_key_lookup_failed | Retry after the API key database is available. |