Place an outbound call
Dial a number. Open the audio WebSocket. Hang up by closing it.
Place the call
curl -X POST https://agentnumber.really.com/voice/dial \
-H "authorization: Bearer <token>" \
-H "content-type: application/json" \
-d '{"phone_number": "+15555550123", "to": "+15555550199"}'
# → 200
# {"call_id": "call_...", "stream_url": "wss://agentnumber.really.com/voice/stream/call_...", "direction": "outbound", "caller": "+15555550199", "phone_number": "+15555550123"}
phone_number is the bearer-owned number you're calling
FROM. to is the destination.
Open the stream WebSocket
Use any WS client. The bearer goes in the Authorization
header on the upgrade request. Audio is binary frames, 16 kHz mono
PCM in both directions. Voice quality + cellular bridging is handled
server-side.
Hang up
Close the stream WebSocket. The server detects the close and tears down the carrier leg.
Common errors
| Status | Error | Meaning |
|---|---|---|
400 | invalid_request | Body missing phone_number or to |
401 | missing/invalid bearer token | Bearer missing or invalid |
403 | not_owner | Bearer doesn't own phone_number |
404 | phone_number_not_found | phone_number not on an active subscription |
409 | phone_busy | Number already on a call (single-active-call constraint) |
409 | subscription_not_bound | Subscription has no slot binding |
502 | mac_unreachable / mac_dial_failed | Hardware adapter returned non-2xx or was unreachable |
Receiving incoming calls
Open /voice/presence/<phone>
and keep the WebSocket open. The server pushes JSON text frames
for three event types over the call lifecycle:
{event: "ringing", call_id, caller, stream_url} on incoming,
{event: "answered", call_id} when picked up, and
{event: "ended", call_id, missed} on hangup.
Where to go next
- Voice overview — both channels in detail
- Dial reference
- Presence reference