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

# Place a Call Endpoint

> Place an outbound click-to-call from your own system: Tuco dials your agent, dials the lead from your Tuco number, and bridges the two.

<Info>This endpoint is in **beta**. The interface is stable enough to build on; we may add fields as it matures.</Info>

## Overview

Place an outbound call programmatically with a single request. Tuco rings your
agent first, then dials the lead **from your Tuco number**, and bridges the two
legs — so the lead sees the same number they've been texting, and your rep's
personal number is never exposed.

<Info>
  US and Canada (`+1`) numbers only.
</Info>

***

## What you'll need

Three things before you make a request:

<Steps>
  <Step title="Your API key">
    A workspace API key (starts with `tuco_`). Get it in the Tuco dashboard under
    **Settings → Integrations → API Keys → Create API Key**. Send it as a bearer
    token: `Authorization: Bearer tuco_...`. This is the same key used for the
    Messages API.
  </Step>

  <Step title="A voice-verified calling line">
    The call goes out **from a line in your workspace whose caller ID is
    voice-verified** — that's the number the recipient sees. Pass it as `from`,
    using **either**:

    * the line's **`+1` number** — simplest, no lookup needed, or
    * the **line ID** — go to the **Lines** page in the dashboard; each line row
      has a **Copy Line ID** button (the copy icon next to the line) — click it
      to copy the ID. You can also get it from the
      [List Lines](/api-reference/lines) API (each line's `_id`).

    If the line isn't voice-verified yet, verify it in the dashboard (or ask your
    Tuco contact to enable voice on it).
  </Step>

  <Step title="Two phone numbers">
    The **lead** you want to reach (`to`) and **your rep's phone** (`agent`), both
    in E.164 format (US/CA, e.g. `+13025550123`).
  </Step>
</Steps>

***

## How it works

```
POST /api/voice/calls
   │
   ├─ 1. Tuco dials your AGENT      → your rep's phone rings first
   ├─ 2. agent answers             → Tuco dials the LEAD from your Tuco number
   ├─ 3. lead answers              → Tuco bridges the two legs
   └─ call is recorded, then billed on hangup
```

The lead is **only dialed after your agent answers**, so a lead is never left
listening to dead air.

***

## Making a request

* **Method**: `POST`
* **URL**: `https://app.tuco.ai/api/voice/calls`
* **Headers**: `Authorization: Bearer tuco_...` and `Content-Type: application/json`
* **Body**: JSON with `from`, `to`, and `agent`

### Request body

```json theme={null}
{
  "from":  "69f918a0f62015705ca41fbb",
  "to":    "+13025550123",
  "agent": "+13025550456"
}
```

<ParamField body="from" type="string" required>
  Your calling line — pass either the **line ID** or the line's **`+1` number**.
  Must be a line in your workspace with a voice-verified caller ID. This is the
  number the lead sees.
</ParamField>

<ParamField body="to" type="string" required>
  The number to call, E.164 US/CA (e.g. `+13025550123`). Non-toll-free. This is
  just a phone number — **the contact does not need to exist in Tuco first**; you
  can call any US/CA number directly.
</ParamField>

<ParamField body="agent" type="string" required>
  Your rep's phone number, E.164 US/CA. This leg is dialed **first** — your rep
  answers, then the number is dialed and bridged in.
</ParamField>

<ParamField body="leadId" type="string">
  Optional, advanced. Only if you already have a lead record in Tuco and want the
  call logged against it (shows in that lead's Unibox thread). Not required to
  place a call.
</ParamField>

### Example

```bash theme={null}
curl -X POST https://app.tuco.ai/api/voice/calls \
  -H "Authorization: Bearer tuco_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from":  "<your line ID or +1 number>",
    "to":    "+13025550123",
    "agent": "+13025550456"
  }'
```

***

## Response

**`202 Accepted`** — the call was accepted and is being placed. Ringing takes a
few seconds, so the response returns a call ID immediately and the call then
progresses asynchronously.

```json theme={null}
{
  "callId": "6a4ed2d5dec1b2d01a6f7656",
  "status": "requested"
}
```

<ResponseField name="callId" type="string">The call record ID (MongoDB ObjectId).</ResponseField>
<ResponseField name="status" type="string">Always `"requested"` on a successful create.</ResponseField>

***

## Call lifecycle

The call advances through these states on the call record:

```
requested → ringing → answered → billed
                           ↘ failed
```

| State       | Meaning                                                                   |
| ----------- | ------------------------------------------------------------------------- |
| `requested` | Accepted; the agent leg is dialing                                        |
| `ringing`   | A leg is ringing                                                          |
| `answered`  | Both legs connected and bridged                                           |
| `billed`    | Call ended; `durationSec`, `billedSec`, and the recording URL are settled |
| `failed`    | The agent didn't answer, or the call couldn't be placed                   |

Every call is recorded; the recording URL is attached to the call record once
the call ends.

<Note>
  The `agent` leg rings first — your rep must answer within \~30 seconds or the call
  times out. If the agent's phone goes to voicemail, the call ends without dialing
  or bridging the lead.
</Note>

***

## Getting the recording

Recordings are captured automatically. After a call ends, fetch the recording (and
the call's timing details) with the [Get Call Recordings](/api-reference/endpoint/get-recordings)
endpoint, using the lead's number.

To get the **most recent** call's recording for a lead, pass `latest=true`:

```bash theme={null}
curl "https://app.tuco.ai/api/voice/recordings?number=+13025550123&latest=true" \
  -H "Authorization: Bearer tuco_your_key"
```

The `recordingUrl` in the response is the download link. Drop `latest=true` to get
all calls to that number (newest first).

<Note>
  Recordings resolve a **few seconds after the call ends**. If you request right on
  hangup and `recordingUrl` comes back `null`, wait \~5-10 seconds and retry. See the
  [Get Call Recordings](/api-reference/endpoint/get-recordings) endpoint for all
  parameters.
</Note>

***

## Errors

All errors return `{ "error": "...", "code": "..." }`.

| HTTP | `code`              | Meaning                                                 |
| ---- | ------------------- | ------------------------------------------------------- |
| 401  | `UNAUTHORIZED`      | Missing or invalid API key                              |
| 400  | `MISSING_FROM`      | `from` (calling line) not provided                      |
| 400  | `MISSING_TO`        | `to` (lead number) not provided                         |
| 400  | `MISSING_AGENT`     | `agent` (rep number) not provided                       |
| 400  | `INVALID_TO`        | `to` is not a US/CA number, or is toll-free             |
| 400  | `INVALID_AGENT`     | `agent` is not a US/CA number, or is toll-free          |
| 403  | `VOICE_NOT_ENABLED` | Voice calling is not enabled for this workspace         |
| 404  | `LINE_NOT_FOUND`    | `from` line does not exist in your workspace            |
| 409  | `LINE_NOT_VERIFIED` | The line exists but its caller ID is not voice-verified |
| 429  | `CONCURRENT_CAP`    | Too many live calls on this line                        |
| 429  | `LINE_MONTHLY_CAP`  | The line hit its monthly minutes cap                    |
| 402  | `MINUTES_EXHAUSTED` | The workspace is out of voice minutes                   |
| 502  | `ORIGINATE_FAILED`  | The carrier rejected the outbound dial                  |
| 500  | `INTERNAL_ERROR`    | Unexpected server error                                 |
