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

# Inbound Calls

> Answer calls to your phone numbers with an inbound campaign. Greeting, who speaks first, hours, duration and webhook live on the campaign. Read the results through the same call object and webhook you already use.

## How It Works

An inbound call is a call someone places to one of your TopCalls phone numbers. You decide which campaign answers it.

1. You attach a campaign to a phone number with `PATCH /v1/phone-numbers/{phone_number_id}`.
2. You start the campaign with `POST /v1/campaigns/{id}/start`. Until then the number stays silent, even if it is attached.
3. When the number rings, TopCalls checks that the campaign is `running`, then the campaign's business hours and your account's concurrency limit.
4. The call is answered and the caller hears the campaign's `first_sentence`.
5. The campaign takes over the conversation, exactly as it does on an outbound call: same prompt, same knowledge base, same tools.
6. When the call ends you receive the usual completion webhook, and the call appears in `GET /v1/calls` with `direction: "inbound"`.

<Note>
  Greeting, who speaks first, max duration and webhook live on the campaign, not on the number. Enabling fails with `422` when the campaign has no `first_sentence`. Inbound calls have no lead, so a `first_sentence` that still contains a `{{...}}` placeholder is rejected with `422` (`code: "greeting_placeholder"`). Write the opening line as an answer: who is speaking, and what the caller can ask for.
</Note>

## Campaign direction

An inbound campaign has `direction: "inbound"`. Create it, attach a number with `PATCH /v1/phone-numbers/{id}`, then `POST /v1/campaigns/{id}/start` — the same start/pause/resume/stop as outbound. It is never dialled and needs no lead list. Callers are answered only while `status` is `running`. Pause stops answering; resume starts again; stop completes it. `POST /v1/campaigns/{id}/test` still places a billed outbound test call to a number you pass, using this campaign's prompt. A number can only be routed to an inbound campaign. Switching a draft campaign back to `outbound` while a number still routes to it returns `409` (`code: "campaign_has_inbound_routes"`); disable the routing first.

Bring-your-own-trunk (BYOT) numbers must originate from static source ranges, or use registration or credential authentication. A carrier that sends inbound calls from more than one address declares each range as its own inbound gateway: the primary gateway on `sip_gateway`, and any additional ranges in `inbound_gateways`. Each inbound range is an IPv4 address or a CIDR (`ipv4` plus an optional `netmask`, defaulting to `32`); hostnames are rejected for inbound because inbound calls are matched by source IP. A BYOT number whose carrier has no active inbound gateway is refused at enable time with `422` (`code: "carrier_no_inbound_gateway"`).

For a provider that originates from several ranges, add the carrier with every range declared:

```json theme={null}
{
  "carrier_name": "My SIP trunk",
  "trunk_type": "static_ip",
  "sip_gateway": { "ipv4": "203.0.113.0", "netmask": 30, "inbound": true, "outbound": true },
  "inbound_gateways": [
    { "ipv4": "203.0.113.4", "netmask": 30 },
    { "ipv4": "198.51.100.0", "netmask": 30 }
  ]
}
```

The primary `sip_gateway` still carries outbound dialling; each `inbound_gateways` entry is inbound-only. Omitting `inbound_gateways` keeps the original single-gateway behaviour.

## Business Hours

By default a running inbound campaign answers around the clock. Restrict the window on the campaign (`config.inbound_business_hours`): timezone, weekdays (`0` is Sunday), and `HH:MM` start/end. An overnight window (`start` after `end`) stays open past midnight on the weekday the night started on. Outside that window the call is declined without being answered. Sending `business_hours` on the number is rejected with `400`.

## Answering Style

Who speaks first is a campaign setting (`first_sentence_wait_for_caller`):

* Off (default) speaks the campaign `first_sentence` as soon as the call is answered.
* On answers the line silently and lets the caller speak first, then speaks the greeting after the caller's first sentence (waiting at most 5 seconds, or the campaign's `first_sentence_delay_seconds`).

## Concurrency and Duration

* Each account can have a limited number of inbound calls in progress at the same time. When the limit is reached, additional callers are declined until a call ends.
* The campaign's `max_duration` caps an inbound call in minutes (1 to 60). When it is reached the agent wraps up and the call ends.
* Inbound calls consume plan minutes the same way outbound calls do. When the balance is exhausted, the caller hears a short unavailable message and the call ends.

## What You Receive

### The call object

Inbound calls appear in `GET /v1/calls` and `GET /v1/calls/{call_id}` alongside outbound calls. These fields tell them apart:

| Field               | Outbound               | Inbound                     |
| ------------------- | ---------------------- | --------------------------- |
| `direction`         | `"outbound"`           | `"inbound"`                 |
| `phone_number`      | The number you dialled | The caller's number         |
| `from_phone_number` | Your caller ID         | Your number that was called |

`phone_number` is always the other party, so `GET /v1/calls?phone_number=+40...` finds every conversation with that person in either direction. Filter by direction with `GET /v1/calls?direction=inbound`.

A caller who withholds their number is recorded with `phone_number` set to `"+10000000000"`.

### The webhook

The completion webhook carries the same payload as for outbound calls, plus:

* `direction`: `"inbound"` or `"outbound"`.
* `caller_name`: the name presented by the caller's network, when available. Present only on inbound calls; `null` when the network did not provide one.

Inbound calls use the campaign's webhook.

## Enabling Inbound on a Number

The number must be `active` and the campaign must belong to your account, have `direction: "inbound"`, not be `cancelled` or `completed`, and use the standard (non-realtime) mode. `campaign_id` is required when enabling. The campaign must already have a `first_sentence`. Greeting, who speaks first, hours, max duration and webhook live on the campaign. Sending those fields on `inbound` is rejected with `400`. Enabling wires the number. The campaign answers only after `POST /v1/campaigns/{id}/start` (and while `status` stays `running`).

```bash theme={null}
curl -X PATCH https://api.topcalls.ai/v1/phone-numbers/27bc24c9-0d16-47fe-bc1b-6b22924e9996 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inbound": {
      "enabled": true,
      "campaign_id": "8f1c1a2e-3b4d-4c5e-9f6a-7b8c9d0e1f2a"
    }
  }'
```

The response is the phone number object with its stored inbound routing:

```json theme={null}
{
  "id": "27bc24c9-0d16-47fe-bc1b-6b22924e9996",
  "number": "+40742600785",
  "status": "active",
  "inbound": {
    "enabled": true,
    "campaign_id": "8f1c1a2e-3b4d-4c5e-9f6a-7b8c9d0e1f2a"
  }
}
```

Enabling runs the campaign prompt through the same safety review as an outbound campaign. A refused prompt returns `422` with a `code` naming the reason, and the number stays unchanged.

Each enabling request is the complete routing for the number: the stored settings are replaced by what you send, and any optional field you leave out returns to its default. To change one setting, resend the whole `inbound` object with the change applied.

### Errors

| Status | `code`                       | Meaning                                                                                                                                               |
| ------ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `403`  | —                            | The `campaign_id` belongs to another account.                                                                                                         |
| `404`  | —                            | The phone number or the campaign was not found (a deleted campaign counts as not found).                                                              |
| `409`  | `inbound_number_conflict`    | Another number with the same digits already answers inbound calls.                                                                                    |
| `409`  | `inbound_already_routed`     | This number already answers for another inbound campaign. Disable it there first.                                                                     |
| `400`  | —                            | `inbound` included an unknown field such as `greeting`, `answer_mode`, `max_duration`, `webhook_url` or `business_hours`. Those live on the campaign. |
| `422`  | —                            | The number is not `active`, `campaign_id` is missing, or the campaign has no `first_sentence`.                                                        |
| `422`  | `campaign_direction`         | The campaign is not an inbound campaign. Set its `direction` to `inbound` first.                                                                      |
| `422`  | `campaign_status`            | The campaign is `cancelled` or `completed`.                                                                                                           |
| `422`  | `greeting_placeholder`       | The campaign `first_sentence` still contains an unresolved `{{...}}` placeholder.                                                                     |
| `422`  | `carrier_no_inbound_gateway` | The number is on a customer trunk (BYOT) whose carrier has no active inbound gateway.                                                                 |
| `422`  | —                            | The campaign uses the realtime mode, or the prompt was refused by the safety review.                                                                  |
| `503`  | —                            | Inbound calling is not available in this environment.                                                                                                 |

## Disabling Inbound

```bash theme={null}
curl -X PATCH https://api.topcalls.ai/v1/phone-numbers/27bc24c9-0d16-47fe-bc1b-6b22924e9996 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "inbound": { "enabled": false } }'
```

Disabling always succeeds, whatever the state of the number or the campaign. Callers are declined from the next call onwards; a call already in progress runs to its end. The previous settings remain visible on the phone number object, so you can copy them into a new enabling request. Re-enabling goes through the safety review again.

Deleting the campaign detaches it from the number: the number stays enabled but declines callers until a new campaign is attached.

## Current Limits

* Calls are answered by the campaign only. Transferring a caller to a person is not available yet.
* Campaigns in the realtime mode cannot answer inbound calls. Use the standard mode.
* One number answers with one campaign. To route by menu choice, build the routing into the campaign prompt.

## Related

<CardGroup cols={2}>
  <Card title="Making Calls" icon="phone" href="/guides/making-calls">
    Outbound calls, campaigns and call configuration.
  </Card>

  <Card title="Webhooks" icon="bolt" href="/guides/webhooks">
    The completion payload, retries and filtering.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Phone number and call endpoints.
  </Card>
</CardGroup>
