Message status, listing and cancelling
Statuses
| Status | Meaning | Final? | Charged? |
|---|---|---|---|
scheduled | Accepted with a future send_at | No | Held |
queued | Accepted and waiting to be sent, or being sent | No | Held |
sent | A route accepted the message | No | Yes |
delivered | The handset received it | Yes | Yes |
undelivered | The network could not deliver it | Yes, but can still become delivered | Yes |
expired | No delivery receipt arrived within 72 hours | Yes, but can still become delivered or undelivered | Yes |
rejected | Refused before any route accepted it | Yes | No |
failed | No route could send it | Yes | No |
cancelled | Cancelled before it was sent | Yes | No |
Nothing ever leaves delivered. When a message is rejected, failed, cancelled, undelivered or expired, error.code says why; see message error codes. A message's status never gains a new value within v1.
Get one message
curl 'https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP' \ -H "Authorization: Bearer $API_KEY_500CALLS"import osimport requestsresponse = requests.get( "https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP", headers={ "Authorization": f"Bearer {os.environ['API_KEY_500CALLS']}", }, timeout=30,)print(response.status_code, response.json())const response = await fetch("https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP", { headers: { Authorization: `Bearer ${process.env.API_KEY_500CALLS}`, },});console.log(response.status, await response.json());<?php$curl = curl_init('https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP');curl_setopt_array($curl, [ CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('API_KEY_500CALLS'), ], CURLOPT_RETURNTRANSFER => true,]);$body = curl_exec($curl);$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);echo $status, PHP_EOL, $body, PHP_EOL;The response adds status_history: every status the message has had, with its time. An unknown ID, a malformed ID and another organisation's message all answer 404 not_found.
List messages
GET /v1/messages lists messages newest first, 50 to a page by default and at most 100. Filter by status and source (repeat either for several values), from, to, client_reference, campaign_id, created_after and created_before.
With neither time bound, the last 7 days are listed. One request spans at most 92 days by default, and messages are kept for 12 months. Pass the response's next_cursor back as cursor for the next page; it is null on the last page. To page without gaps or repeats while new messages arrive, send both created_after and created_before.
curl 'https://api.messaging.500calls.com/v1/messages?client_reference=order-78123&limit=10' \ -H "Authorization: Bearer $API_KEY_500CALLS"import osimport requestsresponse = requests.get( "https://api.messaging.500calls.com/v1/messages?client_reference=order-78123&limit=10", headers={ "Authorization": f"Bearer {os.environ['API_KEY_500CALLS']}", }, timeout=30,)print(response.status_code, response.json())const response = await fetch("https://api.messaging.500calls.com/v1/messages?client_reference=order-78123&limit=10", { headers: { Authorization: `Bearer ${process.env.API_KEY_500CALLS}`, },});console.log(response.status, await response.json());<?php$curl = curl_init('https://api.messaging.500calls.com/v1/messages?client_reference=order-78123&limit=10');curl_setopt_array($curl, [ CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('API_KEY_500CALLS'), ], CURLOPT_RETURNTRANSFER => true,]);$body = curl_exec($curl);$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);echo $status, PHP_EOL, $body, PHP_EOL;Cancel a message
POST /v1/messages/{id}/cancel cancels a message that is still scheduled or queued and releases its held funds, which return to your available balance within about a minute. Send no body, or an empty JSON object {}.
- Only messages sent through the API are cancelled here; a campaign's messages are cancelled with their campaign.
- A message that is already cancelled comes back unchanged with
200, so retrying is safe. - A message that is being sent, already sent, or in a final status answers
409invalid_state_transition. - A send made straight after a cancel can still get
402insufficient_balanceif it needs the money the cancel frees: wait untilavailablehas risen in your balance.
curl -X POST 'https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP/cancel' \ -H "Authorization: Bearer $API_KEY_500CALLS" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: order-78123-otp' \ -d '{}'import osimport requestsresponse = requests.post( "https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP/cancel", headers={ "Authorization": f"Bearer {os.environ['API_KEY_500CALLS']}", "Idempotency-Key": "order-78123-otp", }, json={}, timeout=30,)print(response.status_code, response.json())const response = await fetch("https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP/cancel", { method: "POST", headers: { Authorization: `Bearer ${process.env.API_KEY_500CALLS}`, "Content-Type": "application/json", "Idempotency-Key": "order-78123-otp", }, body: JSON.stringify({}),});console.log(response.status, await response.json());<?php$curl = curl_init('https://api.messaging.500calls.com/v1/messages/msg_01M3KR6CEGVQVV5PV6Q9J1G6SP/cancel');curl_setopt_array($curl, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('API_KEY_500CALLS'), 'Content-Type: application/json', 'Idempotency-Key: order-78123-otp', ], CURLOPT_POSTFIELDS => json_encode(new stdClass()), CURLOPT_RETURNTRANSFER => true,]);$body = curl_exec($curl);$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);echo $status, PHP_EOL, $body, PHP_EOL;Poll or listen
Polling GET /v1/messages/{id} works, but it spends your rate limit. A webhook tells your server when a status changes instead.