Skip to content

SMS, voice & numbers API

Phase 3 — endpoints live, telephony stubbed

The full SMS, voice, numbers, and A2P surface is wired through these endpoints. The underlying telephony runs through a stub adapter today — calls are accepted, recorded, and reflected in inbox/status reads, but no real message or call is placed until the carrier integration ships. All endpoints require auth.

Telephony is stubbed.

SMS sends, OTP requests, and voice calls succeed and appear in the activity audit, but nothing reaches a real handset yet. Build against the shapes now; real delivery turns on with Phase 3.

Project SMS

POST /v1/projects/:id/sms/activate

Activate SMS on a project (opt-in). Provisions a real number, bills it monthly, records it as the project's number, and injects CANTILA_SMS_NUMBER / CANTILA_SMS_API_KEY. Idempotent — returns the existing number if SMS is already active.

Requires deploy.

FieldTypeDescription
countrystringISO-3166 country code, e.g. US
numberTypestringlocal | toll_free | mobile | short_code (default local)
capabilitiesstring[]Subset of sms / mms / voice (default all)
e164stringOptional — a specific number; omit to take the first available
curl -X POST https://api.cantila.app/v1/projects/prj_a1b2/sms/activate \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{ "country": "US", "numberType": "local" }'

POST /v1/projects/:id/sms/deactivate

Deactivate SMS — releases the carrier number (stops the monthly charge), removes the project number, and strips the injected env. Idempotent.

Requires deploy.

POST /v1/projects/:id/sms/send

Send an SMS from a project.

Requires deploy.

FieldTypeDescription
tostringDestination number (E.164)
fromstringSending number owned by the project
bodystringMessage text
curl -X POST https://api.cantila.app/v1/projects/prj_a1b2/sms/send \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+15551230000", "from": "+15557890000", "body": "Your code is 123456" }'
{ "id": "sms_2a90", "status": "accepted", "stubbed": true }
Response shapes on this page are representative.

POST /v1/projects/:id/sms/otp/request

Request a one-time passcode be sent to a number.

Requires deploy.

FieldTypeDescription
tostringDestination number (E.164)

POST /v1/projects/:id/sms/otp/verify

Verify a one-time passcode the user entered.

Requires deploy.

FieldTypeDescription
tostringThe number the code was sent to
codestringThe code to verify
curl -X POST https://api.cantila.app/v1/projects/prj_a1b2/sms/otp/verify \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+15551230000", "code": "123456" }'

POST /v1/projects/:id/sms/inbound

Inbound webhook endpoint for SMS addressed to the project. Called by the SMS pipeline, not by API-key clients.

GET /v1/projects/:id/sms/inbox

Read received SMS for the project.

Requires read.

GET /v1/projects/:id/sms/status

Delivery status for the project's recent outbound messages.

Requires read.

POST /v1/projects/:id/sms/opt-out

Record an opt-out / STOP for a number so the project no longer messages it.

Requires deploy.

FieldTypeDescription
numberstringThe number opting out

Fleet & deliverability

GET /v1/sms/fleet

Account-wide view of SMS-sending numbers and their state.

Requires read.

GET /v1/sms/inbox

Account-level aggregated SMS inbox.

Requires read.

GET /v1/sms/deliverability

SMS deliverability signals across the account.

Requires read.

GET /v1/sms/otp

OTP issuance and verification stats across the account.

Requires read.

Numbers

GET /v1/numbers

List the phone numbers owned by the account.

Requires read.

curl https://api.cantila.app/v1/numbers \
  -H "Authorization: Bearer sk_live_xxxx"

GET /v1/numbers/catalog

Browse purchasable numbers by area, type, and capability.

Requires read.

GET /v1/numbers/:id

Fetch one number by ID.

Requires read.

POST /v1/numbers/port-in

Begin porting an existing number into Cantila.

Requires admin.

FieldTypeDescription
numberstringThe number to port in (E.164)
carrierstringCurrent carrier

POST /v1/numbers/:id/complete-port

Complete a previously initiated port-in once the losing carrier releases the number.

Requires admin.

POST /v1/numbers/:id/transfer

Transfer a number to another sub-account.

Requires admin.

Voice

POST /v1/projects/:id/voice/calls

Place an outbound voice call from a project.

Requires deploy.

FieldTypeDescription
tostringDestination number (E.164)
fromstringCalling number owned by the project

GET /v1/projects/:id/voice/status

Status of the project's recent voice calls.

Requires read.

POST /v1/projects/:id/voice/inbound

Inbound webhook endpoint for calls to the project. Called by the voice pipeline, not by API-key clients.

GET /v1/projects/:id/voice/routing

Read the project's inbound call routing rules.

Requires read.

POST /v1/projects/:id/voice/routing

Set the project's inbound call routing rules.

Requires deploy.

GET /v1/voice/calls

List voice calls across the account.

Requires read.

POST /v1/voice/calls

Place an account-level voice call.

Requires deploy.

A2P registration

A2P (application-to-person) registration is required by carriers before business messaging is allowed at scale.

GET /v1/a2p/brands

List registered A2P brands.

Requires read.

POST /v1/a2p/brands

Register an A2P brand.

Requires admin.

GET /v1/a2p/campaigns

List A2P campaigns.

Requires read.

POST /v1/a2p/campaigns

Register an A2P campaign under a brand.

Requires admin.

GET /v1/a2p/registrations

List A2P registration records.

Requires read.

POST /v1/a2p/registrations

Submit an A2P registration.

Requires admin.

GET /v1/a2p/registrations/:id

Fetch one A2P registration by ID.

Requires read.

GET /v1/a2p/registrations/:id/status

Check the carrier-side status of an A2P registration.

Requires read.

curl https://api.cantila.app/v1/a2p/registrations/reg_77a1/status \
  -H "Authorization: Bearer sk_live_xxxx"
{ "id": "reg_77a1", "status": "pending", "stubbed": true }