Products · /v1/calls
A receptionist in an API
Calls in both directions. Inbound rings route by each tenant's business hours — forwarded to the right person or sent to voicemail with a transcript. Outbound, one API call dials your user and their customer and bridges them — and can stream a live transcript of the conversation while it happens.
Voicemailafter hours
+1 415 413 6287
“Hi, calling about a leaky faucet in the…”
What you get out of the box
Business-hours routing
Open hours forward to real phones; closed hours go to voicemail. Evaluated per tenant, in the tenant's own timezone.
Voicemail with transcripts
voicemail.created delivers the recording and a transcript, ready to render in your product's inbox next to the texts.
Live transcripts, mid-call
Pass transcribe: true and every utterance arrives as a call.transcript webhook while the call is happening — the raw material for agent assist, coaching, and instant call notes.
Click-to-call, bridged
POST /v1/calls rings your user first, then their customer, and bridges the legs — both sides see the tenant's number, never a personal cell.
Keypad in, keypad out
POST a gather and the call speaks your prompt and collects keypresses — “press 1 to confirm tomorrow's appointment” is one request, and call.gather delivers the answer to your webhook. Going the other way, send DTMF on a live call to dial extensions and navigate phone trees; every far-end keypress streams in as call.dtmf.
The browser is a phone
Create a web client per agent seat and add client:wc_… to the ring targets — inbound calls ring inside your web app alongside cell phones; first answer wins and sees the caller's real number. Simultaneous ring and no-answer voicemail included.
Raw audio, streamed live
POST a stream and the call's audio forks to your WebSocket as ~20ms frames — no public server needed, you connect to us. Bidirectional streams play your audio back into the call: the substrate for AI voice agents, custom speech recognition, and real-time coaching.
curl -X PATCH https://api.handset.dev/v1/tenants/tnt_01kzv…/routing_config \ -d timezone="America/Los_Angeles" \ -d hours[mon][open]="08:00" -d hours[mon][close]="17:00" \ -d after_hours="voicemail" \ -d greeting="You've reached Bayview Dental…" # later, after a missed evening call: → webhook: voicemail.created { "duration": 16, "transcript": "Hi, calling about…" }
The API surface
Endpoints
| POST | /v1/calls | Start a click-to-call: dial the agent, then the customer, bridged |
| GET | /v1/calls | List calls with status, duration, and routing outcome |
| GET | /v1/calls/{id} | Retrieve one call and its event timeline |
| GET | /v1/calls/{id}/transcript | The live transcript so far — callable mid-call |
| POST | /v1/calls/{id}/gather | Ask a keypad question: TTS prompt, collected digits back as a webhook |
| POST | /v1/calls/{id}/dtmf | Send digits on a live call — extensions, PINs, phone trees |
| POST | /v1/calls/{id}/streams | Fork live call audio to your WebSocket — bidirectional for voice agents |
| POST | /v1/web_clients | Provision a browser softphone seat for an agent |
| POST | /v1/web_clients/{id}/tokens | Mint a short-lived browser login token — keys stay server-side |
| GET | /v1/voicemails | List voicemails per tenant |
| GET | /v1/voicemails/{id} | Retrieve a voicemail with recording and transcript |
| GET | /v1/recordings/{id} | Retrieve call recording metadata and media |
| PATCH | /v1/tenants/{id}/routing_config | Set hours, greeting, forwarding, and voicemail behavior |
Ship voice & voicemail this sprint.
We're onboarding a small group of vertical SaaS platforms. Tell us what your customers need to say, and to whom.