Audio
Text-to-speech, transcriptions, and realtime session minting
OpenAI-compatible audio surfaces on Hypery. All three endpoints require OAuth scope ai:audio (or a first-party API key / session). Chat scopes alone are not accepted.
Billing
Audio is not token-metered the same way as chat. Hypery always charges the billed team:
Also enforced on every call: DISABLE_AI_SPEND, rate limits, app + team spending caps, model permission spend caps, usageRecords.
Realtime sessions are billed by duration: nothing is charged at mint (the 25-minute worst case is only held), and the client reports the session length to POST /api/v1/realtime/sessions/{id}/settle when it disconnects. See Realtime sessions. A POST /api/v1/usage/charge with category=realtime is acknowledged and charges nothing.
Text-to-speech
POST /api/v1/audio/speech
Optional header: Idempotency-Key (prevents double-charge on retries).
Transcriptions
POST /api/v1/audio/transcriptions — multipart/form-data
Billing estimates minutes from file size (~32 kbps speech heuristic, capped at 45 min) × $0.006/min.
Realtime sessions
POST /api/v1/realtime/sessions — mints a single-use, short-lived Vercel AI Gateway client secret for a realtime voice session over WebSocket (the contract of gateway.experimental_realtime.getToken in @ai-sdk/gateway).
Voice, instructions, turn detection and tools are set by the client on the WebSocket (sessionConfig), not at mint; older OpenAI-style mint fields are accepted and ignored.
Response:
{
"id": "rts_…",
"token": "vcst_…",
"url": "wss://ai-gateway.vercel.sh/v4/ai/realtime-model?ai-model-id=openai%2Fgpt-realtime-2",
"model": "openai/gpt-realtime-2",
"expires_at": 1767225600,
"max_duration_ms": 1500000,
"usd_per_minute": 0.096,
"hypery": { "billing": "duration", "settle_url": "/api/v1/realtime/sessions/rts_…/settle" }
}Connect before expires_at (epoch seconds). In the browser, pass { token, url } to experimental_useRealtime from @ai-sdk/react with gateway.experimental_realtime(model) as the model:
import { experimental_useRealtime as useRealtime } from '@ai-sdk/react';
import { gateway } from '@ai-sdk/gateway';
const model = useMemo(() => gateway.experimental_realtime('openai/gpt-realtime-2'), []);
const realtime = useRealtime({
model,
// Your server route calls Hypery and returns { token, url }.
api: { token: '/api/realtime/token' },
sessionConfig: { voice: 'alloy', turnDetection: { type: 'server-vad' } },
});Gateway limits: a session lasts at most 25 minutes and closes after 5 minutes idle.
Billing and settle
A card on file is required — a team without one is refused with 402 card_required ("Realtime sessions require a card on file (metered billing)"). The gateway's Stripe meter does not cover a minted WebSocket session, so Hypery bills it by duration at the model's per-minute estimate (usd_per_minute: a minute of input audio plus a minute of output audio at the gateway's list prices; charged at the normal 2× media price):
- Mint — the 25-minute worst case is held (app grants, then purchased credits, then the card's unpaid-usage allowance). Nothing is charged.
- Settle — when the WebSocket closes,
POST /api/v1/realtime/sessions/{id}/settlewith{ "durationMs": 183000 }. The duration is capped at 25 minutes and at the time since mint. Purchased credits are drawn first; the rest is one Stripe invoice item. Idempotent: the first settle wins, retries return the same result. Only the team the session was minted for can settle it. - Never settled — about 30 minutes after mint the full 25-minute hold is charged.
Settle response:
{ "id": "rts_…", "status": "settled", "billed_ms": 183000, "credits": 59, "amount_usd": 0.59 }