All webhooks
Messages
Message status updated
message.status.updatedFires when the delivery status of an outbound message changes. Statuses progress in order: pending → server_ack → sent → delivered → read → played; a lower status is silently dropped if a higher one is already recorded. failed is a terminal status and is always recorded. This event fires for outbound messages only, and not every channel reports every status (e.g. some channels do not report read).
HTTP request
AISAR sends a signed POST request to your webhook_url:
http
POST {webhook_url}
Content-Type: application/json
X-AISAR-Signature: sha256=...
{
"event": "message.status.updated",
"event_id": "evt_01JXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2026-03-26T12:00:00.000000Z",
"company_id": 1,
"data": {
"message_id": 123,
"conversation_id": 45,
"channel_id": 2,
"external_message_id": "3EB0ABC123456789",
"status": {
"name": "delivered",
"timestamp": "2026-03-26T12:00:05+00:00",
"error_details": null
}
}
}The X-AISAR-Signature header carries an HMAC-SHA256 signature of the request body — use it to verify the request came from AISAR.
Example payload
json
{
"event": "message.status.updated",
"event_id": "evt_01JXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2026-03-26T12:00:00.000000Z",
"company_id": 1,
"data": {
"message_id": 123,
"conversation_id": 45,
"channel_id": 2,
"external_message_id": "3EB0ABC123456789",
"status": {
"name": "delivered",
"timestamp": "2026-03-26T12:00:05+00:00",
"error_details": null
}
}
}Payload fields
| Field | Type | Description |
|---|---|---|
message_id | integer | Internal message ID |
conversation_id | integer | Conversation ID |
channel_id | integer | Channel ID |
external_message_id | string | Platform-specific message ID |
status.name | string | Status: pending (queued for sending), server_ack (server acknowledged), sent (sent to recipient device), delivered (delivered to recipient device), read (read by recipient), played (played by recipient — voice/video), failed (delivery failed, terminal) |
status.timestamp | string | ISO 8601 timestamp when the status was recorded |
status.error_details | string|null | Error description. Only present when name is failed |