---
title: Place an outbound call — Guide
description: Dial a number, open the audio WebSocket, hang up by closing it.
url: https://agentnumber.really.com/docs/guides/place-call
doc_version: "1.0.0"
last_updated: "2026-05-15"
---

> ## Documentation index
> Fetch the complete documentation index at: https://agentnumber.really.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Place an outbound call

> Dial a number. Open the audio WebSocket. Hang up by closing it.

## Place the call

```bash
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>`](/docs/reference/voice-presence) 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](/docs/voice) — both channels in detail
- [Dial reference](/docs/reference/voice-dial)
- [Presence reference](/docs/reference/voice-presence)

## Sitemap

- [Overview](/docs/)
- [Quickstart](/docs/quickstart)
- [Authentication](/docs/auth)
- [SMS](/docs/sms)
- [Voice](/docs/voice)
- [MCP](/docs/mcp)
- [Payment](/docs/payment)

See the full [sitemap.md](/sitemap.md) for the complete index of docs pages.

---

← Previous: [Guides](/docs/guides) · Next: [Recover a lost token](/docs/guides/recover-token) →
