Docs › Get started
Quickstart
Handset gives your platform a complete business phone system —
compliant two-way SMS, inbound voice, voicemail, and real numbers — through
one REST API at https://api.handset.dev/v1. Ten minutes to your
first text.
1. Authenticate
Every request carries your API key as a bearer token. Keys are mode-scoped:
hs_test_… keys hit the simulated carrier (free numbers, instant
compliance), hs_live_… keys hit the real network. Same code,
different key.
# Sanity check: list your tenants curl https://api.handset.dev/v1/tenants \ -H "Authorization: Bearer $HANDSET_API_KEY"
2. Create a tenant
A tenant is one of your customers — the dental practice or plumbing company inside your product. Numbers, conversations, and business hours all belong to tenants, so one integration serves every customer.
curl https://api.handset.dev/v1/tenants \ -H "Authorization: Bearer $HANDSET_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Bayview Dental", "timezone": "America/Los_Angeles"}' { "id": "tnt_01kzv90afex…", "name": "Bayview Dental", … }
3. Buy a number
# Search available inventory… curl "https://api.handset.dev/v1/phone_numbers/available?area_code=415" \ -H "Authorization: Bearer $HANDSET_API_KEY" # …and purchase one for the tenant. SMS- and voice-ready on arrival. curl https://api.handset.dev/v1/phone_numbers \ -H "Authorization: Bearer $HANDSET_API_KEY" \ -H "Content-Type: application/json" \ -d '{"tenant_id": "tnt_…", "phone_number": "+14155550134"}'
4. Send a message
Threading, opt-out enforcement, and 10DLC checks happen inside this one
call. Pass an Idempotency-Key and retries are safe.
curl https://api.handset.dev/v1/messages \ -H "Authorization: Bearer $HANDSET_API_KEY" \ -H "Idempotency-Key: 3f1b2c…" \ -H "Content-Type: application/json" \ -d '{"from": "num_…", "to": "+14805550199", "body": "Your technician is 15 minutes out."}' { "id": "msg_01kzv…", "status": "queued", "conversation_id": "cnv_01kzv…" }
import { sendMessage } from "@handset/sdk"; const { data } = await sendMessage({ body: { from: "num_…", to: "+14805550199", body: "Your technician is 15 minutes out." }, headers: { "Idempotency-Key": job.id }, }); // data → { id: "msg_01kzv…", status: "queued", conversation_id: "cnv_01kzv…" }
from handset.api.messaging import send_message from handset.models import MessageCreate msg = send_message.sync(client=client, body=MessageCreate( from_="num_…", to="+14805550199", body="Your technician is 15 minutes out.", )) # msg.id, msg.status, msg.conversation_id
Where to next
- Webhooks — receive
message.received,voicemail.created, and the rest, signed and retried. - Test mode — free numbers, instant compliance, and magic numbers for rehearsing failure.
- TypeScript SDK — one typed function per endpoint:
npm install @handset/sdk. - API reference — every endpoint, parameter, and schema.