Telephony carriers
A carrier sells you three things: numbers, a path to and from the public network, and a way for your software to hear about calls. Everything beyond that — recording, transfer, messaging, browser registration, trunking — differs by provider and by account, which is why a well-built system asks what a provider can do instead of assuming it from the provider's name.
The supplied surface#
- Numbers in the countries you are eligible for, with that country's documentation requirements.
- Origination and termination — calls in from the public network and calls out to it, billed per minute by destination.
- Signalling to your software, in one of two shapes: webhooks posted to an answer URL with a response your application composes, or SIP delivered to a trunk you nominate.
- A call log and an invoice, which are the authoritative record of what happened and what it cost.
- Optional capabilities, each of which may or may not be enabled on your particular account: recording, transfer, messaging, browser registration, media formats, concurrency limits.
The last line is the one that shapes code. Two accounts with the same provider can differ, so provider identity is not a reliable proxy for capability.
The differences that reach your architecture#
| Difference | What it costs you if you assumed |
|---|---|
| Webhook signature scheme | Either a rejected legitimate call or an unauthenticated endpoint — no middle ground |
| Response dialect (the XML or JSON you return) | The entire call-control layer, rewritten per provider unless it is confined to an adapter |
| What a status callback means | Ending a live call on a ringing event, which is exactly what one production defect did |
| Recording availability | A feature promised in your interface that silently produces nothing |
| Transfer support | An escalation that queues rather than completes, with a caller waiting through it |
| Messaging on the same account | A message thread in your product that cannot send |
| Browser registration and its address | Every browser line failing to register, with no error a user can act on |
The response to this is not abstraction for its own sake. It is one boundary: a single adapter module holds one provider's signature scheme, its dialect and its webhook shapes, and is the only place that provider's own words appear. The core knows what a line is, what an event means and who may be called when. Providers differ there only through a capability table, and anything that wants to know whether recording, transfer or browser calling exists asks telephony.can(provider, capability).
Reading a provider honestly#
Provider documentation is a description of intent. Two lessons from driving live endpoints here are worth carrying to any carrier.
- The written docs and the working system can disagree. The address a browser must register against came from the provider's own browser SDK; their written documentation named a different address that answered nothing from any network. Every registration failed while the code and the content security policy both pointed at the documented one.
- A response document is executed literally. A listening element placed last in a returned document meant that when nothing usable was heard, the carrier ran off the end of the document and hung up — greeting, fifteen seconds of silence, a normal clearing code, and the follow-up handler never requested once. The fix is an explicit redirect after the listening element, so 'I did not catch that' is something the caller hears.
Both were silent. Neither produced an error in the application; both were found by comparing the carrier's own call log with the call records on this side. That comparison is the cheapest telephony test there is.
Does Connect use a carrier, and which?#
Yes — Vobiz on the live account for the public-network leg, and on the realtime path a media platform's SIP service alongside it. Naming it here is a statement about this deployment, not about the architecture: nothing above the adapter layer knows the name.
Capabilities on this account are stated rather than implied. Call recording is a provider capability that is not enabled, so recording is foundation rather than available. A completed warm handover to a colleague depends on a provider capability that is likewise not enabled, so an escalation phrase queues the request and the live supervisor panel can act on the call, but the handover itself is foundation. And the live carrier carries no SMS at all — the Phone screen says so instead of offering a thread that cannot send.
Questions#
How do I know what my carrier account can do?
Test it against the live endpoint and read the carrier's own call log beside your records. Account-level entitlements differ from published feature lists, and a capability that is documented but not enabled behaves exactly like one that does not exist — except that you believed in it.
Is it worth supporting two carriers?
Supporting two is expensive; being *able* to is nearly free if the provider is confined to one adapter and a capability table from the start. The cost of retrofitting that boundary after a provider's name has spread through the codebase is what makes migrations impossible rather than merely tedious.
Why does a webhook need a signature check at all?
Because the answer URL is reachable by anyone who finds it, and a forged call event can create records, place charges or end a live call. The signature nonce is also what makes replay protection possible — here every normalised provider event is stored once, with the nonce under a partial unique index.