Reference

On this page

SMS & voice API

Endpoints for SMS inboxes, the texts and calls they capture, and texts simulated from phones. Authentication, roles, errors and paging are described in the API overview.

An SMS inbox is a fake Twilio account: your app sends texts and places calls with its Account SID and auth token through the Twilio-compatible API, or binds to it over SMPP. The endpoints on this page are for your tests and tooling, with a team API key. They use the inbox's workspace id, which is not the Account SID.

SMS inboxes

Method and path Role Description
GET /api/sms-inboxes Member Every SMS inbox of the team, with messageCount, unreadCount and credentials
POST /api/sms-inboxes Admin Create one: { "name", "projectId"?, "failureRules"? }. 201 { smsInbox }
GET /api/sms-inboxes/:id Member One SMS inbox
PATCH /api/sms-inboxes/:id Admin Change name, projectId or failureRules
DELETE /api/sms-inboxes/:id Admin Delete it with its texts and calls. Open SMPP binds are closed. 204
POST /api/sms-inboxes/:id/rotate Admin Replace the auth token. The old token stops working at once. { smsInbox }
POST /api/sms-inboxes/:id/smpp Admin Generate SMPP credentials, or replace the SMPP password. The system_id stays the same; open binds are closed. { smsInbox }
bash
curl -X POST https://app.testlie.com/api/sms-inboxes \
  -H "Authorization: Bearer $TESTLIE_API_KEY" -H "Content-Type: application/json" \
  -d '{ "name": "Checkout SMS", "failureRules": [{ "pattern": "+1555000*", "errorCode": 30003, "mode": "async" }] }'
json
{
  "smsInbox": {
    "id": "cm2a7…",
    "name": "Checkout SMS",
    "projectId": null,
    "accountSid": "AC4f1c…",
    "authToken": "9b2e…",
    "baseUrl": "https://app.testlie.com/sms",
    "messagesUrl": "https://app.testlie.com/sms/2010-04-01/Accounts/AC4f1c…/Messages.json",
    "failureRules": [{ "pattern": "+1555000*", "errorCode": 30003, "mode": "async" }],
    "smpp": { "host": "smtp.testlie.com", "port": 2775, "tlsPort": 3550, "systemId": "tl3f9a…", "password": "…" },
    "messageCount": 0,
    "unreadCount": 0,
    "createdAt": "2026-10-23T10:30:00.000Z"
  }
}

Credentials are shown to every team member, like SMTP passwords. SMS inboxes and WhatsApp sandboxes share the plan's SMS inbox limit (402 with "code": "quota_exceeded" past it).

Failure rules

failureRules is a list of up to 20 rules, first match wins. Each rule matches the To number and makes the send fail with a Twilio error:

Field Notes
pattern Up to 64 characters; * matches any run of characters, ? one character
errorCode 21211 (invalid number), 21610 (unsubscribed), 30003 (unreachable), 30005 (unknown handset) or 30007 (carrier filtering)
mode sync (default): the API call fails with 400 and nothing is stored. async: the text is accepted, then ends undelivered (30xxx codes) or failed (21xxx)

Captured texts

Method and path Role Description
GET /api/sms-inboxes/:id/messages Member List texts, newest first: to (exact), q (body contains), page, limit (default 100, max 500). { total, page, limit, messages }
PATCH /api/sms-inboxes/:id/messages Member Mark every text read. { updated }
DELETE /api/sms-inboxes/:id/messages Member Empty the inbox. { deleted }
GET /api/sms-inboxes/:id/messages/wait Member Long-poll for a text (see below)
GET /api/sms/:sid Member One text by SID (or id), with extracted codes and links. { sms }
PATCH /api/sms/:sid Member { "isRead": true | false }
DELETE /api/sms/:sid Member Delete one text. 204
GET /api/sms/:sid/extract Member { sid, codes, links }

A text has id, sid, smsInboxId, to, from, messagingServiceSid, body, numSegments, encoding (GSM-7 or UCS-2), mediaUrls, status (queued, sent, delivered, undelivered, failed), errorCode, errorMessage, statusCallback, channel (api or smpp), isRead, receivedAt and sentAt.

Wait for a text

Parameter Notes
to The destination number, matched exactly (+15551234567; URL-encode the + as %2B)
contains Text the body contains (case-insensitive)
since ISO time; only texts received at or after it match
timeout 1 to 120 seconds, default 30
bash
curl -f -H "Authorization: Bearer $TESTLIE_API_KEY" \
  "https://app.testlie.com/api/sms-inboxes/$SMS_INBOX_ID/messages/wait?to=%2B15551234567&contains=code&since=2026-10-23T10:30:00Z"
json
{
  "sms": {
    "sid": "SM8c1d…",
    "to": "+15551234567",
    "from": "+15005550006",
    "body": "Your sign-in code is 482913",
    "numSegments": 1,
    "encoding": "GSM-7",
    "status": "delivered",
    "channel": "api",
    "receivedAt": "2026-10-23T10:30:02.114Z",
    "extracted": { "codes": ["482913"], "links": [] }
  }
}

The response is abridged here; it has every field listed above. On timeout it answers 408. extracted.codes lists likely one-time codes, best guess first: a code next to a word such as "code", "OTP" or "PIN" ranks first.

Voice calls

Calls placed with the Twilio Voice-compatible API are captured in the SMS inbox of the same account.

Method and path Role Description
GET /api/sms-inboxes/:id/calls Member List calls, newest first: to, status, q (spoken text contains), page, limit (default 100, max 500)
DELETE /api/sms-inboxes/:id/calls Member Delete every finished call; live calls keep running. { deleted }
GET /api/sms-inboxes/:id/calls/wait Member Long-poll for a call: to, status, contains (spoken text), since, timeout (1 to 120 seconds). status is final by default (completed, busy, no-answer, failed or canceled), a single status, or any. 200 { call } with the timeline, transcript and extracted.codes, or 408
GET /api/sms-inboxes/:id/voice Member { callsUrl, rules }: the Calls URL and the simulated callee rules
PUT /api/sms-inboxes/:id/voice Admin Replace the rules: { "rules": [{ "pattern", "behavior", "inputs"? }] }. See Simulated callees
GET /api/calls/:sid Member One call with its timeline and transcript
PATCH /api/calls/:sid Member { "isRead": true | false }
DELETE /api/calls/:sid Member Delete a finished call. 409 while it is still running
GET /api/calls/:sid/extract Member { sid, status, spokenText, codes, links }

Texts from phones

Simulate a person texting your app's number. Testlie posts the text to your app as Twilio would, and to SMPP clients bound to the inbox. See Inbound SMS & email to your app.

Method and path Role Description
GET /api/sms-inboxes/:id/inbound Member Where texts go: { target } with the inbox's phone number, your webhook URL and whether SMPP clients get them
PUT /api/sms-inboxes/:id/inbound Admin { "phoneNumber"?, "url"?, "smpp"? }. url must be reachable from the internet
POST /api/sms-inboxes/:id/inbound/messages Member Send a text: { "from", "body"?, "mediaUrls"?, "to"?, "source"? }. from is an E.164 number or a short code; give a body or at least one media URL. 201 { message } with its deliveries. At most 60 per team per minute
GET /api/sms-inboxes/:id/inbound/messages Member Texts sent to the inbox, newest first, with deliveries: from, page, limit (default 100, max 500)
GET /api/sms-inboxes/:id/conversations Member One row per phone number with its latest message; ?with=<number> returns that thread, oldest first, in both directions
GET, DELETE /api/inbound/:id Member One inbound text (id or SID) with every delivery attempt
POST /api/inbound/:id/redeliver Member Deliver again: every delivery, or { "deliveryId" }. 409 while an earlier delivery is still running

Captured texts, calls and texts from phones each count toward the plan's monthly SMS limit. A simulated text past the limit answers 402; your app's sends get Twilio error 20429 instead. See Plans & limits.