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

# Creating calls

> Place an outbound call with one of your agents.

`POST /v1/calls` places a call and returns as soon as it is queued. It does
not wait for the call to be answered. Full schema and playground:
[Create an outbound call](/api-reference/calls/create-call).

```json theme={null}
{
  "agent_id": "3f1c1b2e-...",
  "to_number": "+15555550100",
  "from_number": "+15555550199",
  "variables": {
    "patient_name": "Jane Doe",
    "appointment_date": "2026-09-15"
  },
  "metadata": {
    "your_order_id": "ORD-8812"
  }
}
```

<ParamField body="agent_id" type="string" required>
  The agent to place the call with. Find it in the dashboard under **Agents**:
  open the agent and copy the ID shown under its name. Only active, outbound
  agents can place calls; others are rejected with `agent_inactive` or
  `agent_not_outbound`.
</ParamField>

<ParamField body="to_number" type="string" required>
  Number to dial. E.164 (`+1...`) preferred.
</ParamField>

<ParamField body="from_number" type="string">
  Caller ID. If sent, it must equal the agent's configured number or the
  request is rejected with `from_number_mismatch`.
</ParamField>

<ParamField body="variables" type="object">
  Per-call values the agent's script uses. Some are required per agent; a
  missing one is a `422` listing the keys.
</ParamField>

<ParamField body="metadata" type="object">
  Any JSON object. Stored untouched and echoed back on every webhook and on
  `GET /v1/calls/{call_id}`.
</ParamField>

## Retell-compatible aliases

A client written for Retell's create-call endpoint works with only a URL
change. `override_agent_id` maps to `agent_id` and
`retell_llm_dynamic_variables` maps to `variables`. `override_agent_version`
and any unknown fields are ignored.

```json theme={null}
{
  "override_agent_id": "3f1c1b2e-...",
  "override_agent_version": 2,
  "from_number": "+15555550199",
  "to_number": "+15555550100",
  "retell_llm_dynamic_variables": { "patient_name": "Jane Doe" },
  "metadata": { "your_order_id": "ORD-8812" }
}
```

## Response

```json theme={null}
201
{
  "call_id": "9d2f7a3c-...",
  "status": "queued",
  "agent_id": "3f1c1b2e-...",
  "to_number": "+15555550100",
  "from_number": "+15555550199",
  "created_at": "2026-09-10T14:03:11.412Z"
}
```

`call_id` is stable for the life of the call. It is the same id on every
webhook and on `GET /v1/calls/{call_id}`.

## Errors

Errors come wrapped in a `detail` key. For validation and dispatch failures
`detail` is an object with `error`, `error_code`, and where applicable extra
fields. For auth and not-found errors it is a plain string.

```json theme={null}
422
{
  "detail": {
    "error": "Required variables are missing: patient_dob",
    "error_code": "missing_variables",
    "missing_variables": ["patient_dob"]
  }
}
```

| Status | `error_code`                           | Meaning                                                                                   |
| ------ | -------------------------------------- | ----------------------------------------------------------------------------------------- |
| 401    |                                        | Missing or invalid API key.                                                               |
| 404    | `agent_not_found`                      | No such agent in your organization.                                                       |
| 400    | `agent_not_outbound`, `agent_inactive` | The agent can't place calls.                                                              |
| 422    | `missing_variables`                    | `missing_variables: [...]` lists what to add.                                             |
| 422    | `from_number_mismatch`                 | `expected_from_number` tells you the right value.                                         |
| 422    | `dnc_blocked`, `number_blocked`        | The number is on a do-not-call or block list. A call record exists with `status: failed`. |
| 502    | `dispatch_error`, `dispatch_failed`    | Transient failure placing the call. Safe to retry.                                        |

## Reading a call

`GET /v1/calls/{call_id}` returns the [call object](/calls/call-object) as of
now.

`GET /v1/calls/{call_id}/recording` returns `{ "url": "...", "expires_at": "..." }`,
a fresh link to the recording valid for about an hour. It is `404` until a
recording exists.
