Messaging API
Message Status API
Check whether a message you sent through the API is still queued, has been sent, or failed. Use it to confirm important messages went out and to find out why one didn't.
https://wbiztool.com/api/v1/message/status/{msg_id}/Body: JSON or form fields
Put the message ID in the URL, replacing {msg_id} with the msg_id returned by Send message, Send to group, Send to multiple numbers or Schedule message. For example: https://wbiztool.com/api/v1/message/status/9817263/.
Quick example#
curl -X POST https://wbiztool.com/api/v1/message/status/9817263/ \
-H "Content-Type: application/json" \
-d '{
"client_id": 12345,
"api_key": "YOUR_API_KEY"
}'import requests
msg_id = 9817263
response = requests.post(
f"https://wbiztool.com/api/v1/message/status/{msg_id}/",
json={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
},
timeout=60,
)
result = response.json() # read the body even when the HTTP code is 400
if result.get("message") == "Unknown message id":
print("No message with this ID in your workspace")
elif "status_text" not in result:
print("Request failed:", result.get("message", "no message in response"))
elif result["status"] == 1:
print("Sent")
elif result["status"] == 2:
print("Failed:", result["error"])
else:
print("Status:", result["status_text"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const msgId = 9817263;
const response = await fetch(`https://wbiztool.com/api/v1/message/status/${msgId}/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: 12345,
api_key: "YOUR_API_KEY",
}),
});
const result = await response.json(); // read the body even when the HTTP code is 400
if (result.message === "Unknown message id") {
console.log("No message with this ID in your workspace");
} else if (!("status_text" in result)) {
console.error("Request failed:", result.message ?? "no message in response");
} else if (result.status === 1) {
console.log("Sent");
} else if (result.status === 2) {
console.log("Failed:", result.error);
} else {
console.log("Status:", result.status_text);
}<?php
$msgId = 9817263;
$payload = [
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
];
$ch = curl_init("https://wbiztool.com/api/v1/message/status/{$msgId}/");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['message'] ?? '') === 'Unknown message id') {
echo 'No message with this ID in your workspace';
} elseif (!isset($result['status_text'])) {
echo 'Request failed: ' . ($result['message'] ?? 'no message in response');
} elseif ($result['status'] === 1) {
echo 'Sent';
} elseif ($result['status'] === 2) {
echo 'Failed: ' . $result['error'];
} else {
echo 'Status: ' . $result['status_text'];
}Replace 12345 and YOUR_API_KEY with your own values. See Authentication for where to find them.
Request parameters#
URL
msg_idintegerrequiredThe message ID, as part of the URL path. It must be a whole number and belong to the workspace of your API key.
Body
client_idintegerrequiredYour API Client ID from Settings → API keys.
api_keystringrequiredYour API key from the same page.
Using the official client#
The Python client calls this endpoint for you.
from wbiztool_client import WbizToolClient
client = WbizToolClient(api_key="YOUR_API_KEY", client_id=12345)
result = client.get_message_status(msg_id=9817263)
print(result.get("status_text"), result.get("error"))The client returns the same fields as the API, so result["status"] is the message's state, not a success flag. Authentication errors raise requests.HTTPError; read the reason with e.response.json()["message"].
Response#
The endpoint returns HTTP 200 with the message's current state:
{
"message": "Sent",
"status": 1,
"status_text": "Sent",
"error": ""
}
A failed message:
{
"message": "Failed",
"status": 2,
"status_text": "Failed",
"error": "Phone number invalid"
}
| Field | Type | Description |
|---|---|---|
status | integer | The message's status code. See the table below. |
status_text | string | Name of the status: Created, Sent, Failed, Cancelled or Expired. |
message | string | Same value as status_text. |
error | string or null | Why the message failed. Always present; empty ("" or null) when there's no error. |
Status values#
status | status_text | Meaning |
|---|---|---|
0 | Created | Queued or scheduled, waiting to be sent. |
1 | Sent | Sent from your WhatsApp number. |
2 | Failed | Couldn't be sent, or sending was interrupted. error says why. If error is Sending was interrupted and may have been delivered. Check WhatsApp before resending., the recipient may already have the message, so don't resend it automatically. |
3 | Cancelled | Cancelled before it was sent, for example with Cancel message. |
4 | Expired | Not sent before its expire_after_seconds deadline. |
Sent is the final success state. This endpoint doesn't report whether the message was delivered to the phone or read.
Examples of error values for failed messages: Phone number invalid, Group not found, Image Url Error, File Url Error, Blocked Contact, File exceeds WhatsApp size limit (…), File type not supported, Sending was interrupted and may have been delivered. Check WhatsApp before resending.
Errors#
{
"message": "Unknown message id",
"status": 0,
"status_text": "pending",
"error": "Invalid message id"
}
| Message | How to fix it |
|---|---|
Unknown message id | No message with that ID exists in the workspace of your API key. Check the ID and that you're using a key from the same workspace. |
Auth Error | Send both client_id and api_key. An invalid JSON body (for example a trailing comma) also returns Auth Error. |
Invalid Client Id | Send client_id as a number. Returned with HTTP 403. |
Auth Error: invalid api key | Check the key exists, hasn't been deleted and belongs to this client_id. Returned with HTTP 400. |
Tips#
- Prefer webhooks for real-time updates: pass
webhookwhen you send the message and Wbiztool notifies you when it's sent or fails, so you don't have to poll. Cancelled and expired messages don't trigger a webhook, so check those here. - Polling: if you do poll, stop once
statusis no longer0. Leave a few seconds between checks. - Many messages at once: to check a whole day's messages, use Message history instead of calling this endpoint for each ID.
- Old messages are purged: sent, failed, cancelled and expired messages untouched for about 90 days return
Unknown message id. So do messages still queued 90 days after they were created or scheduled, on a number that's disconnected or deleted. - Old integrations:
POST /api/v1/msg_status/withmsg_idin the body is deprecated. It returns the same fields. It also acceptsGETwithclient_id,api_keyandmsg_idin the query string, which exposes your API key in URLs and logs. Switch to this endpoint.
