Skip to main content

How It Works

An inbound call is one someone places to your TopCalls number. You pick the campaign that answers it.
  1. Attach an inbound campaign to the number with PATCH /v1/phone-numbers/{phone_number_id}.
  2. When the number rings, TopCalls checks your account’s concurrency limit, the campaign’s status and its business hours, then whether your balance covers the call.
  3. The call is answered and the caller hears the campaign’s first_sentence.
  4. The campaign runs the conversation just as it would outbound: same prompt, knowledge base and tools.
  5. When the call ends you get the usual completion webhook, and the call shows up in GET /v1/calls with direction: "inbound".
Any caller that fails a check is declined without being answered, so the call costs nothing.
Greeting, who speaks first, max duration and webhook live on the campaign, not the number. The campaign needs a first_sentence without {{...}} placeholders, since inbound greetings have no lead variables to fill. Write it as an answer: who’s speaking, and what the caller can ask for.

Campaign direction

An inbound campaign has direction: "inbound". It’s never dialled and needs no lead list. Its number answers only while the campaign is running, so call start after attaching the number. In any other status it declines callers. Start, pause, resume and stop work as they do outbound. POST /v1/campaigns/{id}/test still places a billed outbound test call, using this campaign’s prompt, to a number you pass. Only inbound campaigns can be routed to a number. 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.

Callers and leads

A caller whose number matches one of your leads is linked to that lead, and the agent gets the lead’s name and notes. An unknown caller becomes a new lead in an “Inbound callers” list. Either way the call’s lead_id points at that lead. A withheld number gets no lead.

Bring your own trunk

A bring-your-own-trunk (BYOT) carrier must send calls from static IP ranges, or use registration or credential authentication. Declare the primary range on sip_gateway and any extra ranges in inbound_gateways. Each inbound range is an IPv4 address with an optional netmask from 24 to 32 (default 32, or 30 inside a carrier’s published /30 signaling block). Declare a wider carrier block as several /24 ranges. Hostnames are rejected for inbound, because inbound calls are matched by source IP. A BYOT number whose carrier has no active inbound gateway can’t be enabled (422, code: "carrier_no_inbound_gateway"). A carrier that sends from several ranges:
sip_gateway still carries outbound dialling. Each inbound_gateways entry is inbound-only.

Business Hours

Without hours, an inbound campaign answers around the clock. To restrict it, set config.inbound_business_hours on the campaign: timezone, weekdays (0 is Sunday), and HH:MM start and end. An overnight window (start after end) stays open past midnight on the weekday the night started on. Outside the window, callers are declined. Sending business_hours on the number returns 400.

Answering Style

first_sentence_wait_for_caller on the campaign decides who speaks first:
  • Off (default): the agent says first_sentence as soon as the call is answered.
  • On: the line opens silently and the agent speaks after the caller’s first sentence, waiting at most 5 seconds (or first_sentence_delay_seconds, when set).

Concurrency, Duration and Credit

  • An account can have 5 inbound calls in progress at once. Further callers are declined until one ends.
  • The campaign’s max_duration caps an inbound call (1 to 60 minutes, default 10). When it’s reached, the agent wraps up and hangs up.
  • Inbound calls use credit like outbound ones. If your balance can’t cover a call, the caller is declined.

What You Receive

The call object

Inbound calls show up in GET /v1/calls and GET /v1/calls/{call_id} next to outbound ones. These fields tell them apart: phone_number is always the other party, so GET /v1/calls?phone_number=+40... finds every conversation with that person in either direction. GET /v1/calls?direction=inbound lists inbound calls only. A withheld caller ID is stored as phone_number: "+10000000000".

The webhook

Inbound calls send to the campaign’s webhook. The payload is the outbound one with direction: "inbound" and caller_name, the name the caller’s network sent (or null).

Enabling Inbound on a Number

inbound takes only enabled and campaign_id. The errors table below lists everything that blocks enabling.
The response is the phone number with its inbound routing:
Enabling runs the campaign prompt through the same safety review as outbound, and so does every inbound call. A campaign edited into a refused prompt stops answering. If one PATCH sets label or status along with inbound, those save first and stay saved even when the inbound change fails.

Errors

Disabling Inbound

Disabling doesn’t check the number’s or the campaign’s state, but it can still return 404 for an unknown number or 502 when the phone network rejects the change. Callers are declined from the next call on, and a call in progress runs to its end. inbound.campaign_id keeps the last campaign, so re-enabling is the same request with enabled: true. It goes through the safety review again. If the campaign is deleted, the number stays enabled but declines callers until you attach another campaign.

Current Limits

  • With config.transfer set, the agent can connect a caller to a person mid-call. See Transfer to a person.
  • One number answers with one campaign. To route by menu choice, write the routing into the campaign prompt.

Making Calls

Outbound calls, campaigns and call configuration.

Webhooks

The completion payload, retries and filtering.

API Reference

Phone number and call endpoints.