How It Works
An inbound call is a call someone places to one of your TopCalls phone numbers. You decide which campaign answers it.- You attach a campaign to a phone number with
PATCH /v1/phone-numbers/{phone_number_id}. - You start the campaign with
POST /v1/campaigns/{id}/start. Until then the number stays silent, even if it is attached. - When the number rings, TopCalls checks that the campaign is
running, then the campaign’s business hours and your account’s concurrency limit. - The call is answered and the caller hears the campaign’s
first_sentence. - The campaign takes over the conversation, exactly as it does on an outbound call: same prompt, same knowledge base, same tools.
- When the call ends you receive the usual completion webhook, and the call appears in
GET /v1/callswithdirection: "inbound".
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.Campaign direction
An inbound campaign hasdirection: "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:
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_sentenceas 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_durationcaps 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 inGET /v1/calls and GET /v1/calls/{call_id} alongside outbound calls. 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. 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;nullwhen the network did not provide one.
Enabling Inbound on a Number
The number must beactive 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).
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
Disabling Inbound
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
Making Calls
Outbound calls, campaigns and call configuration.
Webhooks
The completion payload, retries and filtering.
API Reference
Phone number and call endpoints.