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

# Calls

> Make outbound calls, receive inbound calls, read results, and manage call records. OneInbox automatically classifies outcomes after every call.

## Make an outbound call

Pass the registered `from_number` and the destination `to_number`. Use `variables` to inject per-call context (e.g., the customer's name or order ID) into the agent's first message and system prompt.

```bash theme={null}
curl -X POST https://api-tokyo.oneinbox.ai/v1/calls \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<agent_id>",
    "to_number": "+919876543210",
    "from_number": "+15739693824",
    "variables": { "customer_name": "Sama", "order_id": "ORD-001" },
    "webhook_url": "https://your-server.com/per-call-webhook",
    "out_sms": false
  }'
```

| Optional field | Default | What it does                                                                           |
| -------------- | ------- | -------------------------------------------------------------------------------------- |
| `variables`    | `{}`    | Key-value pairs injected into the agent's system prompt and first message at call time |
| `webhook_url`  | —       | Per-call webhook URL — overrides any global webhook for this call only                 |
| `out_sms`      | `false` | Send an SMS to `to_number` after the call ends                                         |
| `schedule_at`  | —       | ISO 8601 timestamp to schedule the call for a future time                              |

```json theme={null}
{
  "id": "call_abc123",
  "status": "initiated",
  "to_number": "+919876543210",
  "from_number": "+15739693824"
}
```

The call goes through these states:

| Status        | Meaning                                        |
| ------------- | ---------------------------------------------- |
| `initiated`   | Call created, connecting through your provider |
| `in_progress` | Call connected, agent is talking               |
| `completed`   | Call ended normally                            |
| `failed`      | Call failed to connect                         |

***

## Receive inbound calls

When someone dials your registered number, OneInbox routes the call to your agent automatically — no extra API call needed. The call record appears in your account just like an outbound call, with the same `status`, `outcome`, `transcript`, and `recording_url` fields.

To enable inbound on a number, set `inbound_routing` when you register or purchase it:

```json theme={null}
"inbound_routing": {
  "agent_id": "<routing_agent_id>",
  "fallback": { "agent_id": "<fallback_agent_id>" },
  "voicemail_message": "Sorry we missed you, please leave a message."
}
```

To add or update routing on an existing number:

```bash theme={null}
curl -X PATCH https://api-tokyo.oneinbox.ai/v1/phone-numbers/<phone_id> \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "inbound_routing": {
      "agent_id": "<routing_agent_id>",
      "voicemail_message": "Updated voicemail message."
    }
  }'
```

→ [Phone numbers](/guides/phone-calls) — full setup for search, purchase, and bring-your-own-number paths

***

## Stop a call

Send a stop request to end the session. If the agent already ended the call via the `end_call` tool, this is a no-op.

```bash theme={null}
curl -X POST https://api-tokyo.oneinbox.ai/v1/calls/<call_id>/stop \
  -H "Authorization: Bearer <api_key>"
```

***

## Read the results

After the call ends, fetch the full record to get the transcript, outcome, and summary. Wait 2–3 seconds after stopping — the transcript and analysis are written asynchronously.

```bash theme={null}
curl https://api-tokyo.oneinbox.ai/v1/calls/<call_id> \
  -H "Authorization: Bearer <api_key>"
```

```json theme={null}
{
  "id": "call_abc123",
  "status": "completed",
  "duration_seconds": 87,
  "messages": [
    { "role": "agent", "content": "Hi Sama! This is Aria from Acme." },
    { "role": "user",  "content": "Oh hi, yes I've been expecting your call." }
  ],
  "outcome": "Appointment Booked",
  "ai_summary": "Caller agreed to a product demo on Thursday at 3pm.",
  "analysis": {
    "summary": "Caller agreed to a product demo on Thursday at 3pm."
  },
  "recording_url": "https://storage.oneinbox.ai/recordings/call_abc123.mp3",
  "latency": {
    "llm_ttft": { "avg_ms": 857, "p50_ms": 820, "min_ms": 710, "max_ms": 1050, "samples": 4 },
    "tts_ttfb": { "avg_ms": 312, "p50_ms": 290, "min_ms": 240, "max_ms": 410, "samples": 4 },
    "eou_delay": { "avg_ms": 180, "p50_ms": 175, "min_ms": 140, "max_ms": 230, "samples": 4 }
  },
  "credits_used": 1.45,
  "cost_cents": 8.7
}
```

`messages` and `analysis` are only populated after the call ends. Stop first, wait 2–3 seconds, then fetch.

| Field               | When it's available          | What it means                                                                                                    |
| ------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `latency.llm_ttft`  | After call ends              | Time-to-first-token from the LLM — per turn, with avg/p50/min/max                                                |
| `latency.tts_ttfb`  | After call ends              | Time-to-first-byte from TTS — per turn                                                                           |
| `latency.eou_delay` | After call ends              | End-of-utterance detection lag — how long before the agent started responding                                    |
| `credits_used`      | After call ends              | OneInbox billing units — `duration_seconds ÷ 60` (1 credit per active minute)                                    |
| `cost_cents`        | Finalized async by carrier   | Raw carrier cost (Twilio/Telnyx). May be `null` immediately after hangup — backfilled once the carrier finalizes |
| `recording_url`     | After call ends (if enabled) | Pre-signed S3 URL, valid 4 hours. Each GET returns a fresh URL so it never expires for active integrations       |

***

## List calls

Returns your most recent calls. Default order is newest first.

```bash theme={null}
curl https://api-tokyo.oneinbox.ai/v1/calls \
  -H "Authorization: Bearer <api_key>"
```

***

## List calls — cursor pagination

For large result sets, use cursor-based pagination. Pass the `cursor` token from the previous response to get the next page.

```bash theme={null}
# First page
curl "https://api-tokyo.oneinbox.ai/v1/calls/cursor?limit=20" \
  -H "Authorization: Bearer <api_key>"

# Next page — use the cursor from the previous response
curl "https://api-tokyo.oneinbox.ai/v1/calls/cursor?cursor=<cursor>&limit=20" \
  -H "Authorization: Bearer <api_key>"
```

The response includes a `cursor` token. When `cursor` is `null`, you have reached the last page.

***

## Delete a call

Permanently deletes a call record.

```bash theme={null}
curl -X DELETE https://api-tokyo.oneinbox.ai/v1/calls/<call_id> \
  -H "Authorization: Bearer <api_key>"
```

***

## Manually set a call outcome

After a call ends you can override the AI-assigned outcome — useful when your CRM or a human reviewer has classified the call differently.

```bash theme={null}
curl -X PATCH https://api-tokyo.oneinbox.ai/v1/calls/<call_id> \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{ "outcome": "interested" }'
```

The updated `outcome` value is immediately reflected in `GET /v1/calls/<call_id>` and in webhook payloads for that call.

***

## What is an outcome?

An outcome is a label assigned to a completed call that summarises its result. It's the top-level `outcome` field on the call record, set automatically after the call ends. `analysis` is a separate object holding the AI-generated `summary` — it does not contain `outcome`. You can also set or override `outcome` manually, and you can create your own custom outcome labels for your workspace.

***

## Built-in outcome labels

OneInbox ships with a set of platform-level outcomes available to every account. `GET /v1/workspace/call-outcomes` returns their snake\_case identifiers; the `outcome` field on a call record stores the human-readable Title Case form:

| Identifier (`call-outcomes` catalog) | Stored on `call.outcome` | What it means                                       |
| ------------------------------------ | ------------------------ | --------------------------------------------------- |
| `appointment_booked`                 | `Appointment Booked`     | A meeting or demo was scheduled                     |
| `callback_requested`                 | `Callback Requested`     | Caller asked to be called back later                |
| `completed`                          | `Completed`              | Call finished with no other outcome matched         |
| `do_not_call`                        | `Do Not Call`            | Caller asked not to be contacted again              |
| `failed`                             | `Failed`                 | Call failed to connect properly                     |
| `interested`                         | `Interested`             | Caller engaged but did not commit                   |
| `no_answer`                          | `No Answer`              | Call rang out with no pickup                        |
| `not_connected`                      | `Not Connected`          | No conversation happened (busy, immediate hang-up)  |
| `not_interested`                     | `Not Interested`         | Caller explicitly declined                          |
| `other`                              | `Other`                  | Doesn't match any other label                       |
| `spam`                               | `Spam`                   | Identified as a spam/robocall situation             |
| `voicemail`                          | `Voicemail`              | Voicemail greeting detected                         |
| `wrong_number`                       | `Wrong Number`           | Reached the wrong person/number                     |
| —                                    | `null`                   | No outcome classified — call too short or ambiguous |

***

## How auto-classification works

After every call ends, OneInbox reads the transcript and assigns an outcome automatically. No configuration needed.

A few things to know:

* **Classification happens post-call.** `outcome` is `null` during an active call. Fetch the record after the call ends.
* **`ai_summary` explains the reasoning.** If an outcome looks wrong, read the summary to understand what the model saw in the conversation.
* **Custom outcomes are also used.** If you have created custom outcome labels (see below), the agent uses those in addition to the built-in set when classifying calls.

***

## Custom outcome labels

You can create custom outcome labels specific to your workspace. The agent uses these alongside the built-in labels when classifying calls — so if you add "Hot Lead" as a custom outcome, the AI will start assigning it when a call matches that description.

### List call outcomes

Returns both the built-in platform labels (always available) and any custom labels you have created for your workspace.

```bash theme={null}
curl https://api-tokyo.oneinbox.ai/v1/workspace/call-outcomes \
  -H "Authorization: Bearer <api_key>"
```

```json theme={null}
{
  "builtin": [
    "appointment_booked", "callback_requested", "completed", "do_not_call",
    "failed", "interested", "no_answer", "not_connected", "not_interested",
    "other", "spam", "voicemail", "wrong_number"
  ],
  "items": [
    {
      "id": "co_abc123",
      "label": "Hot Lead",
      "description": "Expressed strong interest and asked specific product questions",
      "is_active": true
    }
  ],
  "total": 1
}
```

### Create a custom outcome

Add a new outcome label to your workspace. Any casing is accepted — e.g. `"Hot Lead"` or `"demo_scheduled"`. Once created, the agent starts using it automatically when classifying future calls.

```bash theme={null}
curl -X POST https://api-tokyo.oneinbox.ai/v1/workspace/call-outcomes \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Hot Lead",
    "description": "Qualified lead with confirmed budget and decision timeline"
  }'
```

```json theme={null}
{
  "id": "co_abc123",
  "label": "Hot Lead",
  "description": "Qualified lead with confirmed budget and decision timeline",
  "is_active": true
}
```

| Field         | What it does                                                                                       |
| ------------- | -------------------------------------------------------------------------------------------------- |
| `label`       | The outcome name. Any casing is accepted — stored and displayed as-is                              |
| `description` | Optional. Explains to the AI when this outcome applies. More detail = more accurate classification |

### Update a custom outcome

Rename a label or deactivate it. Deactivating (`is_active: false`) hides the outcome from future auto-classification but preserves it on historical call records — no data is lost.

```bash theme={null}
curl -X PATCH https://api-tokyo.oneinbox.ai/v1/workspace/call-outcomes/<outcome_id> \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Qualified Lead",
    "is_active": true
  }'
```

| Field       | What it does                                                                              |
| ----------- | ----------------------------------------------------------------------------------------- |
| `label`     | New label name — updates how it appears on call records going forward                     |
| `is_active` | `false` = hides this outcome from new classification while keeping historical data intact |

***

## Get notified automatically with webhooks

Instead of polling, set up a webhook to receive the full call record as soon as a call ends:

```bash theme={null}
curl -X POST https://api-tokyo.oneinbox.ai/v1/webhooks \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Call completed",
    "url": "https://your-server.com/webhooks/oneinbox",
    "events": ["call.ended"]
  }'
```

→ [Webhooks guide](/guides/webhooks)

***

## API reference

[Create outbound call](/api-reference/calls/create-outbound-call) · [Stop call](/api-reference/calls/stop-call) · [Get call](/api-reference/calls/get-call) · [Update call](/api-reference/calls/update-call) · [List calls](/api-reference/calls/list-calls) · [Delete call](/api-reference/calls/delete-call) · [List call outcomes](/api-reference/workspace/list-call-outcomes) · [Create call outcome](/api-reference/workspace/create-call-outcome) · [Update call outcome](/api-reference/workspace/update-call-outcome)
