Messages
Message status updated
message.status.updatedFires when the delivery status of an outbound message changes. Statuses progress in order: queued → sent → delivered → read → played; a lower status is silently dropped if a higher one is already recorded. failed is a terminal status, but it is only recorded when the message has not already reached a higher status: a provider failure receipt arriving AFTER delivered/read/played was already recorded (e.g. delayed or duplicated) is silently suppressed — an already-delivered message's status is never downgraded retroactively. A suppressed receipt is not lost silently: it is written to the channel log (GET /channels/{id}/logs) under the message.status.failed_suppressed code. 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:
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
{
"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: queued (queued for sending), sent (sent to recipient device), delivered (delivered to recipient device), read (read by recipient), played (played by recipient — voice/video), failed (delivery failed, terminal, but suppressed when a higher status is already recorded — see the event description) |
status.timestamp | string | ISO 8601 timestamp when the status was recorded |
status.error_details | string|null | Error description in the "text (code)" format — a human-readable reason (from the runtime/provider response or an error catalog) with the technical code in parentheses; the code may be absent, leaving just the text. Only present when name is failed |