---
title: "Originate a call"
method: POST
path: "/api/v1/outbound/calls"
tags: ["Outbound Calls"]
---

# Originate a call

`POST /api/v1/outbound/calls`

## Request

- Base URL: `https://api.callnode.io`
- URL: `https://api.callnode.io/api/v1/outbound/calls`
- Auth: API key in header `X-Api-Key` and API key in header `X-Timestamp` and API key in header `X-Signature`

Places an outbound call. Returns 202 once CallNode accepts the originate command.
The call lifecycle is then visible via GET on the same `callId`, or via the
optional status webhook.

The destination takes one of three mutually exclusive forms:

1. **PSTN** — `to` is E.164; the call is completed over the phone network.
2. **Direct SIP URI** — `to` is `sip:user@host[:port][;transport=udp|tcp]`;
   the call is delivered straight to your SIP endpoint.
3. **Saved trunk (BYOC)** — `sipTrunkId` selects a trunk created in the
   dashboard, and `to` is an E.164 number (terminated by your carrier) or an
   extension your host understands.

In every form `from` must be a CallNode number you own — it becomes the
caller ID presented to the called party or your SIP endpoint. SIP
destinations bill at your plan's SIP egress rate and must accept traffic
from 198.27.122.194 or 192.95.44.47 (audio G.711 PCMU/PCMA at 8 kHz, DTMF RFC 2833).

## Headers

- `X-Idempotency-Key` string, uuid

## Request body

- OriginateRequest: Three mutually exclusive destination forms: E.164 `to` (PSTN), a `sip:` URI `to` (direct SIP delivery), or `sipTrunkId` + an E.164/extension `to` (BYOC via your saved trunk). Passing `sipTrunkId` together with a `sip:` `to` is rejected with `invalid_request`.
  - `to` union, required: The destination. An E.164 number, a `sip:` URI, or — together with `sipTrunkId` — an E.164 number or a 1–64 character extension the trunk's host understands.
    - string: Plus sign followed by 7–15 digits.
    - string: A SIP destination URI: `sip:user@host[:port][;transport=udp|tcp]`. Port defaults to 5060 and transport to udp. TLS is not yet supported. The host must be a public hostname or IP.
    - string: Extension string. Only valid together with `sipTrunkId`.
  - `sipTrunkId` string: ID of a saved SIP trunk (Dashboard → SIP Trunks). Routes the call to the trunk's configured host (BYOC / PBX). Mutually exclusive with a `sip:` `to`.
  - `from` string, required: Plus sign followed by 7–15 digits.
  - `webhookUrl` string, uri: Where your AI agent runs. Overrides the webhook stored on the `from` number. Invoked once when the call connects (`call_started`), then once per turn — for every caller utterance (`user_speech`) and every completed keypad entry (`user_dtmf`, with the digit string in a `dtmf` field) — see the Conversational Webhook guide.
  - `webhookAuth` WebhookAuth: How CallNode authenticates to your webhook endpoint.
    - `type` 'none' | 'basic' | 'bearer' | 'header', required
    - `headerName` string: Header name when `type` is `header`.
    - `value` string: The secret, token, or `user:pass` pair, depending on `type`.
  - `realtime` object: Realtime WebSocket mode for this call (see /docs/realtime): instead of the per-turn webhook, CallNode opens a WebSocket to `url` when the call connects and streams transcripts (and, on request, caller audio) to it; you stream audio back, transfer or hang up. Overrides the from-number's realtime setting. The webhook stays the fallback if the socket cannot be reached. Billed per started minute of socket time on top of the call minute (`realtimePerMinuteRate` on GET /api/plans).
    - `url` string, uri, required: wss:// URL on a public host.
    - `auth` WebhookAuth: How CallNode authenticates to your webhook endpoint.
      - `type` 'none' | 'basic' | 'bearer' | 'header', required
      - `headerName` string: Header name when `type` is `header`.
      - `value` string: The secret, token, or `user:pass` pair, depending on `type`.
  - `metadata` object: Opaque JSON, echoed back on status webhooks. Max 4 KB.
  - `statusWebhookUrl` string, uri: URL we POST call lifecycle events to (answered, completed, failed). For SIP destinations, `call.failed` events carry the mapped `failureCode` and may also include `sipCause` — the raw hangup cause string (diagnostic passthrough; not enumerated).
  - `maxDurationSecs` integer: Hard cap on call duration.
  - `tcpaOverride` boolean: Bypass the 8am–9pm called-party-local-time check. Audited.

## Response `202`

Originate command accepted.

- OriginateResponse
  - `callId` string
  - `status` 'originating' | 'ringing' | 'answered' | 'completed' | 'failed' | 'canceled'
  - `createdAt` string, date-time

## Other responses

- `400`: Malformed request or failed validation. SIP-destination codes: `sip_egress_disabled` (SIP destinations not enabled for this account), `invalid_sip_uri` (`to` starts with `sip:` but does not parse), `invalid_request` (`sipTrunkId` together with a `sip:` `to` — the forms are mutually exclusive), and `blocked_destination` (the SIP host resolves to a private address or CallNode infrastructure).
- `401`: Missing, unknown, or badly signed credentials — check the HMAC and the timestamp skew.
- `403`: Blocked by a compliance gate. `error` is `tcpa_window_violation` when the called party's local time is outside the 8am–9pm window, `trunk_disabled` when the referenced SIP trunk is disabled or has no egress destination configured, `account_not_verified` before business verification, `destination_not_enabled` for a destination class not enabled on the account, or `policy_blocked` when a webhook, status webhook, realtime or SIP destination on the call (or configured on the from-number) points at a service CallNode identifies as fraud tooling, such as one-time-passcode interception.
- `404`: `trunk_not_found` — the `sipTrunkId` does not exist on this account.
- `429`: Rate limit exceeded. See the rate-limit response headers.

---

[API](https://skmtc.dev/callnode/apis/callnode-outbound-api.md) · [All operations](https://skmtc.dev/callnode/apis/callnode-outbound-api/llms.txt) · [OpenAPI document](https://skmtc.dev/callnode/apis/callnode-outbound-api/revisions/c7da6ad06509?raw)
