---
title: "Place an AI voice call"
method: POST
path: "/api/v1/calls"
tags: ["calls"]
---

# Place an AI voice call

`POST /api/v1/calls`

Places an outbound voice call handled by an AI voice agent using the supplied instruction. Supports idempotent retries via the optional `Idempotency-Key` header: replaying the same key returns the original call (`200`) instead of dialing again, and a duplicate that arrives while the original is still processing waits for it. A non-2xx response guarantees no live call: if the call already fired when the failure happened, Dial cancels it before responding. Without the header the request is not idempotent — retrying can place a duplicate call; on an ambiguous failure, confirm via List calls before retrying. Choose the from-number with exactly one of `fromNumber` (phone-number ID, one of your numbers in E.164 format, or a nickname) or the legacy `fromNumberId` (ID only) — both, or neither, is rejected with `400`.

## Headers

- `Authorization` string, required
- `Idempotency-Key` string

## Request body

- object
  - `to` string, required — Recipient phone number in E.164 format.
  - `fromNumber` string — The Dial number to call from, referenced flexibly: a phone-number ID, one of your numbers in E.164 format, or a number's nickname. A nickname shared by more than one of your numbers is rejected with `400`. Provide exactly one of `fromNumber` or `fromNumberId`.
  - `fromNumberId` string — ID of the Dial number to call from. Legacy alternative to `fromNumber` — provide exactly one of the two.
  - `outboundInstruction` string, required — System prompt for the AI voice agent during the call.
  - `language` string — BCP-47 language tag for the voice agent. Optional — when omitted, Dial detects the language from the destination number's country prefix and the agent handles both that language and `en-US`. Pass an explicit tag to pin the call to a single language.
  - `maxCallDurationSeconds` integer — Optional per-call cap on this call's length, in seconds. Highest priority: when set it is the effective cap, overriding the number and account caps (it can raise or lower the limit). Must be between 60 and 3600 seconds (1 minute to 1 hour); a value outside that range returns 400. Omit to fall back to the number cap, then the account cap, then the global default. Free accounts — accounts that have never added credit and never subscribed — are capped at 300 seconds (5 minutes), reported as `limits.maxCallDurationSeconds` on the account: a higher value sent here returns 400, and a cap inherited from the number or account is clamped to 300. When a cap is active, Dial automatically injects a warning to the agent ~40 seconds before the hard cut, prompting it to wrap up naturally.
  - `voiceGender` 'male' | 'female' — Gender of the AI voice agent for this call. Optional — when omitted, the voice is female (the default for every language). Pass `male` or `female` to choose explicitly; the choice also tells the agent how to refer to itself in gendered languages.
  - `transferTo` string — Forward-to number in E.164 format. Optional — when set, the agent waits for a real human (riding out hold music and IVR menus) and then cold-transfers the call to this number. Must differ from both `to` and the call's from number. When the hand-off occurs, the call's `transferredAt` is stamped.

## Response `200`

A call with this `Idempotency-Key` was already placed — returns the original call instead of dialing again.

- CallsMakeCallResponse200
  - `call` Call
    - `id` string
    - `phoneNumberId` string
    - `from` string
    - `to` string
    - `direction` 'inbound' | 'outbound'
    - `status` string
    - `duration` integer — Call duration in seconds.
    - `transcript` string, nullable — Transcript text, available after the call ends.
    - `voiceRuntime` 'managed' | 'self-hosted-audio' — Which voice runtime served this call. `managed` — Dial's voice agent ran the call; this includes Self-Hosted's LLM mode, where Dial still handles the audio and only the LLM is yours. `self-hosted-audio` — the call's raw audio was streamed to your own server, so Dial never heard the conversation and produced no transcript or recording for it — `transcript` is always `null`. See the [Self-Hosted guide](/documentation/platform/self-hosted). Null on calls that predate this field.
    - `instruction` string, nullable — The system prompt the AI voice agent ran with for this call. For outbound calls, this is the `outboundInstruction` passed to `POST /api/v1/calls`. For inbound calls, this is a snapshot of the destination number's `inboundInstruction` at the moment the call was answered — later edits to the number do not retroactively change it.
    - `transferTo` string, nullable — Forward-to number (E.164) requested when the call was placed, or `null` when no transfer was requested. See the `transferTo` field on `POST /api/v1/calls`.
    - `transferredAt` string, date-time, nullable — Timestamp of the moment the call was cold-transferred to `transferTo`, or `null` if no hand-off occurred.
    - `createdAt` string, date-time

## Other responses

- `400` — The request body failed validation.
- `401` — Missing or invalid API key.
- `402` — Insufficient Dial credit. The number is pay-as-you-go and the account's credit balance is at or below zero. Add credit or start a subscription. (error code `insufficient_credit`.)
- `404` — The requested resource was not found on this account.
- `409` — Idempotency conflict — the original request with this `Idempotency-Key` is still processing and didn't finish within the wait window. Retry with the same key shortly.
- `429` — Concurrent-call limit reached. A free account — one that has never added credit and never subscribed — can have at most 2 calls in progress at once, inbound and outbound combined. Wait for a call to end, or add credit / start a subscription to lift the limit permanently. (error code `call_limit_reached`.)

---

[API](https://skmtc.net/getdial/apis/rest-api.md) · [All operations](https://skmtc.net/getdial/apis/rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/getdial/rest-api/revisions/5f4eb30ac29a/schema)
