The business phone API for vertical SaaS
Phone infrastructure to grow your platform
Give your vertical SaaS compliant two‑way texting, inbound calling, voicemail, and real phone numbers, through one API, from your customers' first text to your millionth.
import { sendMessage } from "@handset/sdk"; await sendMessage({ body: { from: "num_01kzv…", // your customer's number to: "+14154136287", body: "Your technician is 15 minutes out.", }, }); // → queued: threading, opt-outs & 10DLC handled. Webhook incoming.
10DLC
Registered messaging
E911
Address provisioning
STOP/HELP
CTIA keywords built in
HMAC
Signed webhooks
AES-256
Encrypted EINs at rest
A complete phone system for every business on your platform. Your customers already run their businesses inside your product, then step outside it to text and call their customers. Handset is the phone company behind your API: carrier contracts, 10DLC, CTIA keywords, E911, and multi‑tenant numbers, designed to work as one.
Messaging
/v1/messages
Two-way SMS that threads into conversations per tenant. STOP, HELP, and START handled automatically, opt-outs enforced at send time.
Bayview Dental+1 415 259 5084
Hi Maria, reminder: cleaning tomorrow at 9:30 AM. Reply C to confirm.
C, see you then!
conversation cnv_01kzv9… · delivered
Voice & voicemail
/v1/calls
Inbound calls routed by each tenant's business hours, to real phones or a softphone right in your web app. Outbound click-to-call with live mid-call transcripts; voicemail with recordings.
Voicemailafter hours
+1 415 413 6287
“Hi, calling about a leaky faucet in the…”
Numbers
/v1/phone_numbers
Search, buy, or port in real numbers: E911 included, live on arrival.
+1 415 555 0184Buy · $1/mo
+1 415 555 0271sms · voice
+1 415 555 0339sms · voice
Compliance
/v1/brands
10DLC brands and campaigns as API objects, not support tickets.
Brand · Ridge Plumbingvetted
Campaign · appointmentsapproved
EIN **-***6789 · encrypted
Webhooks
/v1/webhook_endpoints
Nine event types, HMAC-signed, retried until you acknowledge.
message.received200 OK
call.completed200 OK
voicemail.created200 OK
Embed a phone system in your platform. One account, many tenants: each of your customers gets their own numbers, conversations, opt‑out lists, and business hours, isolated by design and billed as one platform.
Start with tenantsyour platform acct_01kzv90a5md2wmj9d79spjqywk ├─ tenant tnt_01kzv90afex… “Bayview Dental” │ ├─ +1 415 259 5084 │ └─ hours: Mon–Fri 8–5 America/Los_Angeles └─ tenant tnt_01kzvb2m9qp… “Ridge Plumbing” ├─ +1 602 555 0144 └─ after‑hours → voicemail + transcript
Carrier infrastructure, without the carrier.
Ed25519‑verified carrier webhooks in, HMAC‑signed platform events out, a transactional queue in between. You never touch a SIP trunk, but the dial tone is real. Press it.
350 Hz + 440 Hz
The dial tone behind vertical SaaS
0API
for messaging, voice, numbers, and compliance
0event types
HMAC-signed webhooks, retried until acknowledged
0endpoints
spec-first REST, typed SDKs on the way
0modes
live and test on every account, from day one
Developer experience
Test mode is not an afterthought. Every account ships with parallel live and test keys. Test mode runs a simulated carrier: numbers are free, compliance approves instantly, and magic numbers let you rehearse failure before it happens in production.
# Magic number: simulate a failed delivery curl https://api.handset.dev/v1/messages \ -H "Authorization: Bearer hs_test_…" \ -d to="+15005550001" -d body="…" → webhook: message.failed "failure_reason": "carrier_rejected"
# Same code. Real number, real delivery. curl https://api.handset.dev/v1/messages \ -H "Authorization: Bearer hs_live_…" \ -d to="+14154136287" -d body="…" → webhook: message.delivered status: "delivered"
Handset UI · open source
The UI is already built too. Handset UI is an open-source component registry for the shadcn CLI: inboxes, threads, a browser softphone, 10DLC compliance forms, number porting, and call routing, copied into your repo as source, styled with your tokens, wired to the API through your own backend.
# One command. Your product has a phone system. npx shadcn@latest add @handset/phone-system ✔ inbox · thread · composer · call-log ✔ voicemail-player · call-transcript 9 components installed → components/handset/
No iframes, no widget skins. The source lands in your project: rename it, restyle it, rip pieces out. Your API key stays on your server; the components talk to a proxy route you own.
@handset/messagingTwo-pane texting: inbox, threads, delivery states@handset/softphoneDial, answer, mute: a phone inside your app@handset/contact-timelineEvery text, call, and voicemail in one scroll@handset/opt-in-formConsent UI shaped by a real carrier review- 35+ components, live demos, MIT licensed → ui.handset.dev
AI agents
Your agent can already use us. Handset ships an MCP server, listed on the official registry: one config line and an AI agent is texting, calling, and reading transcripts against the simulated carrier, no signup meeting required. When it's time to speak, the same API streams raw call audio both ways.
# One line. Your agent has a phone system. claude mcp add handset -e HANDSET_API_KEY=hs_test_… -- npx -y @handset/mcp › send_message · make_call · get_transcript › start_transcription · buy_number · create_tenant · 9 more connected: test mode, simulated carrier # Live keys refused unless you explicitly allow them: HANDSET_ALLOW_LIVE=1, because agents shouldn't dial real people by accident
Coding agents get first-class treatment too: a companion skill (npx @handset/mcp --skill) teaches them the integration patterns, and the docs ship llms.txt for the rest.
MCP server
15 tools on the official MCP Registry (send, call, transcribe, provision), safe by default on test-mode keys.
Media streaming
Fork or bidirectional raw call audio over WebSockets: the substrate your speech loop runs on.
Live transcripts + AI summaries
Every utterance as a webhook mid-call; a written recap seconds after hangup.
Realtime events
The whole event catalog pushed the moment it commits, browser-safe tokens included.
- The AI & MCP guide → docs.handset.dev/ai
Pricing
Build for free. Pay for what you send.
Develop against the simulated carrier at no cost. When you go live, top up a prepaid balance and pay only for usage. No monthly fee, no minimums, no contract.
See full pricing details →Test mode
Free
No card required
- The full API and every feature
- Simulated carrier + magic numbers
- Instant compliance, free numbers
- MCP server and SDKs
Pay as you go
Self-serveUsage-based
Prepaid credits, top up from $5
- Outbound SMS$0.012 / segment
- Inbound SMS$0.006 / segment
- Outbound MMS$0.04 / message
- Inbound MMS$0.015 / message
- Voice$0.02 / minute
- Live transcription$0.05 / minute
- Phone numbers$2.50 / month
- 10DLC registrationat cost
Scale
Custom
For embedding at volume
- Volume usage rates
- White-glove 10DLC onboarding
- Number porting
- Invoicing and net terms
- Founder-direct support
Building something ambitious? Early design partners lock in lower founding rates for life, plus white-glove onboarding and founder-direct support.
hello@handset.dev →A segment is one 160-character SMS (70 characters for messages with emoji or other Unicode); longer texts are split into multiple segments and billed per segment, the way carriers meter them. Prices are in USD. Carrier surcharges (e.g. per-message 10DLC fees) are passed through at cost and itemized. Credits never expire.
Put a handset in your product.
We're onboarding a small group of vertical SaaS platforms. Tell us what your customers need to say, and to whom.