Skip to main content
Docs menu: SMS

API reference

SMS

Send a text from one of your agents' numbers and read its delivery status.

Send a text message

POST https://api.telvana.com/sms/send

Texts to from from, which must be the phone number of one of the workspace's agents, and records the text on that agent's SMS thread with the recipient. The thread is the one the recipient's reply lands on, so replies appear under the text in the portal and in what the agent's SMS settings do with them (an AI reply, or staff answering). Both the agent and the workspace must have SMS turned on.

Numbers. US and Canadian numbers only, in any common format (+17145550123, (714) 555-0123); they are stored and sent as E.164. A number written with another country code (such as +65) is refused even when its digits would read as a US number, as are premium-rate, service and non-geographic numbers, and Telvana agent numbers, whose own AI would answer (400 UNSUPPORTED_DESTINATION).

Retries. Send an Idempotency-Key header (1 to 255 characters, unique per text) so a retry can never text the recipient twice. Telvana stores only its hash, but prefer an opaque value, such as a UUID or a hash of your own record ids, to anything a person could read. A retry with the same key and the same from, to and message answers with the first send (replayed: true) and sends nothing. Keys are per workspace and kept indefinitely: do not reuse one for another text. When the first attempt was refused (any 4xx below other than 409 IDEMPOTENCY_KEY_IN_USE and 422 IDEMPOTENCY_KEY_REUSED, or 502 SMS_PROVIDER_REFUSED, 502 SMS_PROVIDER_UNREACHABLE or 503 SMS_PROVIDER_BUSY), nothing was sent and the key is free again; 502 SMS_SEND_OUTCOME_UNKNOWN and 502 SMS_SENT_NOT_RECORDED keep it held. When the carrier did not confirm the send (502 SMS_SEND_OUTCOME_UNKNOWN), the text may have gone out, but Telvana has no record of it: it is not on the thread and has no status to read. A retry with that key answers 409 IDEMPOTENCY_KEY_IN_USE rather than risk a second text, as it does while the first attempt is still running. Retrying on 409 is always safe: once the first attempt finishes, a retry gets its send, or sends the text if the carrier refused it. Wait a few seconds between retries rather than retrying in a loop. If 409 persists for more than a minute, treat the text as possibly delivered and do not resend it automatically under a new key. 502 SMS_SENT_NOT_RECORDED means the text was sent but could not be put on the thread; error.details.providerSid is the carrier's id, and a retry with that key answers 409, with the same providerSid when Telvana could note it. Do not send it again. 502 SMS_PROVIDER_UNREACHABLE means Telvana could not reach the carrier at all, and 503 SMS_PROVIDER_BUSY that the carrier is throttling Telvana's account; in both nothing was sent: retry shortly.

Delivery. A 200 means the carrier accepted the text (status queued or accepted), not that it was delivered. A text to a landline is often accepted and fails afterwards. Read GET /sms/messages/{id} once, a few minutes later, for the final status. On a number Telvana carries through Telnyx rather than Twilio, an opt-out or a delivery failure may only show after the send, and GET /sms/messages/{id} has no status for it.

Refusals a sender should act on: 422 RECIPIENT_OPTED_OUT (the recipient replied STOP to this number; texts to it are refused until they reply START), 400 INVALID_PHONE_NUMBER (not a valid number), 422 LANDLINE_OR_UNREACHABLE (a landline, or a number that cannot receive texts). A carrier refusal carries the carrier's own error code in error.details.providerErrorCode.

This page shows the success response only. The errors to retry and the refusals to act on, and how to read delivery, are in Sending texts. Keys are kept a long time but not promised forever, so retry within hours, not weeks.

Header parameters

Name Description
Idempotency-Key string Makes a retry safe: a second request with the same key and the same text answers with the first send and texts nothing. 1 to 255 characters; use an opaque value such as a UUID (up to 255 characters).

Request body (application/json)

Name Description
from string required One of the workspace's agents' phone numbers
to string required The recipient, a US or Canadian number
message string required up to 1,600 characters

Example request

curl -X POST "https://api.telvana.com/sms/send" \
  -H "x-api-key: $TELVANA_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+16575550100",
    "to": "+17145550123",
    "message": "Hi Dana, this is Sunrise Home Care checking in after your first visit. Reply here anytime."
  }'

Response 200

The carrier accepted the text, and it is on the agent thread. Errors use the format in Errors .

Fields in data

Name Description
success boolean
messageId string The text on the thread; pass it to GET /sms/messages/{id}
conversationId string The SMS thread
providerSid string The carrier's message id
status string | null The carrier's status when it took the text
replayed boolean True when an earlier request with the same Idempotency-Key sent this text

Example response

{
  "data": {
    "success": true,
    "messageId": "h8k2m4p6r8t0v2x4z6b8d0f2",
    "conversationId": "q1w3e5r7t9y1u3i5o7p9a1s3",
    "providerSid": "SM0123456789abcdef0123456789abcdef",
    "status": "queued",
    "replayed": false
  }
}

Get a text's delivery status

GET https://api.telvana.com/sms/messages/{id}

Where a text stands now, read from the carrier on each request: queued, sending, sent, delivered, undelivered or failed (received for a text the agent received), with the carrier's error code when it failed. Error 30006 is a landline or a carrier that cannot be reached, 30003 an unreachable handset, 30007 a text the carrier filtered. Read it once per text, a few minutes after sending, rather than polling; a workspace may make 120 reads a minute (429 RATE_LIMITED). A message Telvana holds no Twilio id for (the agent's own AI replies, and texts on a Telnyx number) has status null.

Path parameters

Name Description
id string required The messageId POST /sms/send answered with

Example request

curl "https://api.telvana.com/sms/messages/{id}" \
  -H "x-api-key: $TELVANA_API_KEY"

Response 200

The status, as the carrier reports it now. Errors use the format in Errors .

Example response

{
  "data": {
    "id": "h8k2m4p6r8t0v2x4z6b8d0f2",
    "conversationId": "q1w3e5r7t9y1u3i5o7p9a1s3",
    "providerSid": "SM0123456789abcdef0123456789abcdef",
    "status": "undelivered",
    "errorCode": 30006
  }
}