API reference
Voice and SMS
Place single calls and send single SMS over the routes you bought, and read their history.
BrowseVoice and SMS
List your API call history
GET/
- Access
- API key. Full-access keys only; not reachable by scoped keys.
- Rate limit
- 100 requests per second (the default)
Ledger entries for calls placed through POST /comms/calls, newest first.
Parameters
typequery · string
Accepted but not applied: each endpoint already fixes its own typeOne of api_call, api_sms, smpp_sms, dialer_campaignfromquery · string (date-time)
Only rows created at or after this instanttoquery · string (date-time)
Only rows created before this instantcursorquery · string (uuid)
ThenextCursorfrom the previous pagelimitquery · integer
Default 25
Response 200
datarequiredobject[]
idrequiredstring (uuid) · data[].id
userIdrequiredstring (uuid) · data[].userId
typerequiredstring · data[].type
Ledger entry type, e.g. chargeamountrequiredmoney · data[].amount
Signed: a charge is negative USD as a decimal string with exactly 6 places, e.g. "0.012500".balanceAfterrequiredmoney · data[].balanceAfter
USD as a decimal string with exactly 6 places, e.g. "0.012500".referencerequiredstring | null · data[].reference
Human-readable description of the call or messagerelatedEntityTyperequiredstring | null · data[].relatedEntityType
api_call for calls; api_sms or smpp_sms for messagesrelatedEntityIdrequiredstring (uuid) | null · data[].relatedEntityId
The callId or messageIdcallIdrequiredstring | null · data[].callId
createdAtrequiredstring (date-time) · data[].createdAt
ISO-8601 timestamp (UTC)nextCursorrequiredstring | null
Pass ascursorto fetch the next page; null on the last page.hasMorerequiredboolean
True when another page exists.
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Place a single outbound call
POST/
- Access
- API key. Scoped keys need
voice:send. - Rate limit
- 10 requests per second
- Safe retries
- Send
X-Idempotency-Key; a replay within 24 hours returns the first response. - Real traffic
- Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit.
Dials to over a route you purchased (or one Smart Routing selects). By default the request BLOCKS until the call ends - answer and hangup, no answer, or maxDuration - then returns the outcome and what it cost (200); set a client timeout above maxDuration. With async: true it returns at once with 202 and status: ringing; follow the call on GET /comms/calls/{id} or with the call.ringing, call.answered, call.gathered and call.completed webhooks. Validation, routing and balance errors are still returned straight away in both modes. actions make the answered call speak (say, in en, es, fr, de, pt or hi), play an MP3 (play), collect keypad digits (gather), wait (pause) or end (hangup), in order; audio is prepared before dialling, so a bad URL costs nothing. Billed per the route increment at the route price plus the platform fee, after the call completes; there is no charge for spoken text. A test key simulates the call against test credit and runs no actions.
Parameters
X-Idempotency-Keyheader · string
Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.
Request body (application/json)
torequiredstring
Destination number (E.164)fromrequiredstring
Caller ID to present (E.164)routeIdstring (uuid)
A route you purchased. Omit to let Smart Routing pick onestrategystring
Smart Routing strategy used when routeId is omittedOne ofcheapest,best_quality,balancedmaxDurationinteger
Hang up after this many seconds10 to 3600, default 300asyncboolean
Return at once (202, status ringing) instead of waiting for the call to end. Follow the call on GET /comms/calls/{id} or with the call.* webhooksactionsobject[]
What the call does once answered, in order: say, play, gather, pause, hangup. At most 10 actions, 1,500 characters of spoken text, 3 play URLs and 5 gathers. The call ends when the actions finishsaystring · actions[].say
Text spoken by our text-to-speech voicemax 500 charslanguagestring · actions[].language
Overrides the call default for this actionOne ofen,es,fr,de,pt,hiplaystring (uri) · actions[].play
HTTPS URL of an MP3 file, at most 2 MB. We download it once before dialling (public addresses only, no redirects) and play our copymax 2048 charsgatherobject · actions[].gather
digitsinteger · actions[].gather.digits
Most keys to collect1 to 20, default 1timeoutinteger · actions[].gather.timeout
Seconds to wait for the first key1 to 30, default 5finishOnKeystring · actions[].gather.finishOnKey
Key that ends input early; empty for nonedefault "#"One of#,*,triesinteger · actions[].gather.tries
Prompt and wait again this many times in total when nothing is pressed1 to 3, default 1saystring · actions[].gather.say
Prompt spoken while listening; a key press interrupts itmax 500 charsplaystring (uri) · actions[].gather.play
Prompt played while listening (instead of say)max 2048 charslanguagestring · actions[].gather.language
One ofen,es,fr,de,pt,hipauseinteger · actions[].pause
Seconds of silence1 to 10hangupboolean · actions[].hangup
One oftruelanguagestring
Default language for say actions (default en)One ofen,es,fr,de,pt,hi
Response 200
datarequiredobject
callIdstring (uuid) · data.callId
Use with GET /comms/calls/{id}; the same id appears on the call.* webhookstostring · data.to
fromstring · data.from
statusstring · data.status
The call has been handed to the network and is being dialledOne ofringingsipResponseCodeinteger | null · data.sipResponseCode
hangupCausestring | null · data.hangupCause
durationSecondsinteger · data.durationSeconds
billableSecondsinteger · data.billableSeconds
Duration rounded up to the route billing incrementcostmoney · data.cost
What this call cost you, platform fee included USD as a decimal string with exactly 6 places, e.g. "0.012500".billingIncrementstring · data.billingIncrement
The route billing increment, e.g. "6/6" or "60/60"startedAtstring (date-time) · data.startedAt
ISO-8601 timestamp (UTC)completedAtstring (date-time) · data.completedAt
ISO-8601 timestamp (UTC)simulatedboolean · data.simulated
Present and true for test-key calls: nothing was dialledrouteIdstring (uuid) | null · data.routeId
Present on calls placed over a failover chain (Smart Routing calls with automatic failover, and Switch sub-account calls): the route that carried the call, or the last one triedattemptsobject[] · data.attempts
Present when the call was tried on more than one route: each route tried, in order. Only the one that connected is billed; a wrong number (404/484), a busy or declined call and no answer are never retriedrouteIdrequiredstring (uuid) · data.attempts[].routeId
sipResponseCoderequiredinteger | null · data.attempts[].sipResponseCode
statusrequiredstring · data.attempts[].status
hangupCauserequiredstring | null · data.attempts[].hangupCause
modestring · data.mode
One ofasyncactionsinteger · data.actions
How many call actions will run on answerstatusUrlstring · data.statusUrl
Path of GET /comms/calls/{id} for this call
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get one call: live status, cost and gathered digits
GET/
- Access
- API key. Scoped keys need
voice:send. - Rate limit
- 100 requests per second (the default)
Works for any call placed through POST /comms/calls, while it runs and after it ends: status, timestamps, duration, cost, the hangup cause in plain words, and the digits collected by gather actions. A reseller sub-account key sees only its own calls. Unknown ids answer 404.
Parameters
idrequiredpath · string (uuid)
Response 200
datarequiredobject
callIdrequiredstring (uuid) · data.callId
statusrequiredstring · data.status
queued, ringing and answered are live states; completed (answered, then ended), no_answer, busy and failed are finalOne ofqueued,ringing,answered,completed,no_answer,busy,failedmoderequiredstring · data.mode
One ofsync,asynctorequiredstring · data.to
fromrequiredstring · data.from
simulatedrequiredboolean · data.simulated
True for test-key calls: nothing was dialledcreatedAtrequiredstring (date-time) · data.createdAt
ISO-8601 timestamp (UTC)ringingAtrequiredstring (date-time) | null · data.ringingAt
ISO-8601 timestamp (UTC)answeredAtrequiredstring (date-time) | null · data.answeredAt
ISO-8601 timestamp (UTC)endedAtrequiredstring (date-time) | null · data.endedAt
ISO-8601 timestamp (UTC)durationSecondsrequiredinteger | null · data.durationSeconds
billableSecondsrequiredinteger | null · data.billableSeconds
Duration rounded up to the route billing incrementcostrequiredmoney | null · data.cost
What the call cost you, platform fee included. Null until it ends USD as a decimal string with exactly 6 places, e.g. "0.012500".billingIncrementrequiredstring | null · data.billingIncrement
sipResponseCoderequiredinteger | null · data.sipResponseCode
hangupCauserequiredstring | null · data.hangupCause
The switch cause code, e.g. NORMAL_CLEARING or USER_BUSYhangupReasonrequiredstring | null · data.hangupReason
Why the call ended, in plain words. Null while it is liveerrorrequiredstring | null · data.error
Why the call could not be placed, when it failed before reaching the networkactionsrequiredany[] | null · data.actions
The call actions as you sent themgatheredrequiredobject[] | null · data.gathered
Keypad input from gather actions, filled in when the call endsindexrequiredinteger · data.gathered[].index
Which gather action (0 for the first)digitsrequiredstring | null · data.gathered[].digits
The keys pressed, without the finish keystatusrequiredstring · data.gathered[].status
no_input: nothing was pressed, or the call ended before this stepOne ofreceived,no_inputrouteIdstring (uuid) | null · data.routeId
Present when the call was placed over a failover chain: the route that carried it, or the last one triedattemptsobject[] · data.attempts
Present when the call was tried on more than one route: every attempt in order. Only the attempt that connected is billedattemptrequiredinteger · data.attempts[].attempt
1 for the first route triedrouteIdrequiredstring (uuid) | null · data.attempts[].routeId
statusrequiredstring · data.attempts[].status
answered, failed, busy or no_answersipResponseCoderequiredinteger | null · data.attempts[].sipResponseCode
hangupCauserequiredstring | null · data.attempts[].hangupCause
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support. - Also
NOT_FOUND
List your SMS history
GET/
- Access
- API key. Full-access keys only; not reachable by scoped keys.
- Rate limit
- 100 requests per second (the default)
Ledger entries for messages sent over the API and SMPP, newest first.
Parameters
typequery · string
Accepted but not applied: each endpoint already fixes its own typeOne of api_call, api_sms, smpp_sms, dialer_campaignfromquery · string (date-time)
Only rows created at or after this instanttoquery · string (date-time)
Only rows created before this instantcursorquery · string (uuid)
ThenextCursorfrom the previous pagelimitquery · integer
Default 25
Response 200
datarequiredobject[]
Same fields as CommsHistoryEntry, shown earlier on this page.nextCursorrequiredstring | null
Pass ascursorto fetch the next page; null on the last page.hasMorerequiredboolean
True when another page exists.
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Send a single SMS
POST/
- Access
- API key. Scoped keys need
sms:send. - Rate limit
- 10 requests per second
- Safe retries
- Send
X-Idempotency-Key; a replay within 24 hours returns the first response. - Real traffic
- Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit.
Forwards the message to the route seller and returns straight away with a message id. status is the send-time outcome (accepted, sent or failed). The final outcome comes later from the carrier's delivery receipt, when the route returns one: read it with GET /comms/sms/{messageId} or subscribe to the sms.delivered and sms.failed webhooks. A message that fails on its receipt is refunded. Billed per segment at the route price plus the platform fee. A test key simulates the send against test credit.
Parameters
X-Idempotency-Keyheader · string
Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.
Request body (application/json)
torequiredstring
Destination number (E.164)fromrequiredstring
Sender ID: a number or an alphanumeric sender (letters, digits, spaces and . + _ -)max 30 charsrouteIdstring (uuid)
A route you purchased. Omit to let Smart Routing pick onestrategystring
Smart Routing strategy used when routeId is omittedOne ofcheapest,best_quality,balancedmessagerequiredstring
Message body. Long messages are sent as concatenated segmentsmax 1600 chars
Response 200
datarequiredobject
messageIdrequiredstring · data.messageId
Use with GET /comms/sms/{messageId}torequiredstring · data.to
fromrequiredstring · data.from
statusrequiredstring · data.status
Send-time outcome when we forwarded the message, not a handset delivery receiptOne ofsent,delivered,failed,pending,acceptedsegmentsrequiredinteger · data.segments
Billed segments (160 GSM-7 / 70 UCS-2 characters each, fewer when concatenated)costrequiredmoney · data.cost
USD as a decimal string with exactly 6 places, e.g. "0.012500".submittedAtrequiredstring (date-time) · data.submittedAt
ISO-8601 timestamp (UTC)simulatedboolean · data.simulated
Present and true for test-key messages: nothing was sentnetworkobject | null · data.network
Present when the route prices SMS to this country per destination network. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to)mccMncrequiredstring | null · data.network.mccMnc
Mobile network code (MCC-MNC) the message was priced as, e.g. "234-10"operatorrequiredstring | null · data.network.operator
Network name from public number-range datasourcerequiredstring · data.network.source
range = number-range data; hlr = a live network lookup; none = not determinedOne ofrange,hlr,nonerateBasisrequiredstring · data.network.rateBasis
network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the route's price for other or unknown networksOne ofnetwork,all_operators,country
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get the delivery status and timeline of a sent SMS
GET/
- Access
- API key. Scoped keys need
sms:send. - Rate limit
- 100 requests per second (the default)
Returns the message's current status and its timeline: queued (charged), sent (the route accepted the hand-off), then delivered or failed, each with a timestamp, and an errorCode on failure.
Where delivered comes from. Only from a carrier delivery receipt. Receipts come back on SMPP routes whose supplier returns them, and on HTTP routes whose seller posts them back to us. A route that returns none leaves its messages at sent with awaitingReceipt: true; routeReturnsReceipts tells you whether the route has returned any in the last 30 days, so you know whether to wait. A receipt that reports the message undelivered, expired or rejected marks it failed and refunds it.
Covers messages sent with POST /comms/sms and POST /comms/sms/bulk. An unknown id answers 200 with status not_found rather than 404.
Parameters
messageIdrequiredpath · string
Response 200
datarequiredobject
messageIdrequiredstring · data.messageId
statusrequiredstring · data.status
Current state: sent, accepted (test key), delivered or failed; not_found when the id is not on your account. delivered only ever comes from a carrier receipttostring | null · data.to
fromstring | null · data.from
segmentsinteger | null · data.segments
errorCodestring | null · data.errorCode
Set when status is failed: SELLER_REJECTED (the route refused the hand-off), NO_ENDPOINT, UNDELIVERABLE, EXPIRED or REJECTED (from the carrier receipt)timelineobject[] · data.timeline
Every state the message has been in, oldest firststatusrequiredstring · data.timeline[].status
queued = charged and waiting to be handed off; sent = the route accepted it; accepted = simulated on a test key; delivered / failed = finalOne ofqueued,sent,accepted,delivered,failedatrequiredstring (date-time) · data.timeline[].at
ISO-8601 timestamp (UTC)sourcerequiredstring · data.timeline[].source
Where we learned it: our ledger, the hand-off to the route, the carrier's delivery receipt, or a test-key simulationOne ofplatform,submit,carrier_receipt,simulatederrorCodestring | null · data.timeline[].errorCode
On failed: SELLER_REJECTED, NO_ENDPOINT, UNDELIVERABLE, EXPIRED or REJECTEDcarrierStatusstring | null · data.timeline[].carrierStatus
The carrier receipt's own status value, e.g. DELIVRD or UNDELIVcarrierErrorstring | null · data.timeline[].carrierError
The carrier receipt's own error value, when it sent oneawaitingReceiptboolean · data.awaitingReceipt
True while the message is sent and no carrier receipt has arrived. It stays true for good on a route that returns no receiptsrouteReturnsReceiptsboolean | null · data.routeReturnsReceipts
Whether the route that carried this message has returned at least one carrier receipt in the last 30 days. null for test-key messagesdlrSupportedboolean · data.dlrSupported
True: the platform collects carrier delivery receipts. Whether one arrives for this message depends on the route (routeReturnsReceipts)simulatedboolean · data.simulated
Present and true for test-key messages: nothing was sentcostmoney · data.cost
The ledger amount of the charge (negative) USD as a decimal string with exactly 6 places, e.g. "0.012500".referencestring | null · data.reference
sentAtstring (date-time) · data.sentAt
When the message was chargedmessagestring · data.message
Explanation, present when status is not_found
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Send up to 1,000 SMS in one request
POST/
- Access
- API key. Scoped keys need
sms:send. - Rate limit
- 100 requests per second (the default)
- Real traffic
- Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit.
Sends each message in order over one route and returns a result per recipient. Each message is billed exactly as POST /comms/sms bills it: a reseller sub-account API key pays the sub-account's retail rate, a test key simulates. Stops at the first insufficient-balance refusal (account or sub-account) and marks the rest skipped. Not idempotent: retrying resends every message.
Request body (application/json)
routeIdrequiredstring (uuid)
The purchased SMS route every message is sent overfromrequiredstring
Sender ID for every messagemax 30 charsmessagesrequiredobject[]
torequiredstring · messages[].to
max 30 charsmessagerequiredstring · messages[].message
max 1600 chars
Response 200
datarequiredobject
totalrequiredinteger · data.total
sentrequiredinteger · data.sent
failedrequiredinteger · data.failed
Failed plus skippedtotalCostrequiredmoney · data.totalCost
USD as a decimal string with exactly 6 places, e.g. "0.012500".resultsrequiredobject[] · data.results
torequiredstring · data.results[].to
statusrequiredstring · data.results[].status
The send status, or failed / skippedmessageIdstring · data.results[].messageId
fromstring · data.results[].from
segmentsinteger · data.results[].segments
costmoney · data.results[].cost
US dollars as a decimal string with exactly 6 decimal places, e.g. "0.012500". Do money arithmetic with a decimal type, not floating point. USD as a decimal string with exactly 6 places, e.g. "0.012500".submittedAtstring (date-time) · data.results[].submittedAt
ISO-8601 timestamp (UTC)errorstring · data.results[].error
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.