Overview
When you send a message with acallback_url, Oliver POSTs to that URL each time the message’s status changes. The current status is also always available from GET /messages/{id}.
When the webhook fires
Each status is sent once, in order. If statuses change faster than they can be delivered, you get the latest one, e.g.
message.read without a separate message.delivered. Branch on status, and treat a status at or past one you already handled as a no-op.
Payload
The body is the message object plus these fields:string
required
message.{status}, e.g. message.delivered.string
required
Unique per delivery. Use it to de-duplicate.
string
The
reference_id you supplied when sending, if any.string
rcs or sms: how the client got the message. Can be null on message.sent with channel: "auto", before the carrier reports it.string
required
The practice the message was sent for.
string
required
When the status changed (ISO 8601).
Verifying Webhook Signatures
Signatures work the same way as the AI outbound outcome webhook and use the same practice secret. When it’s configured, each request carriesX-Webhook-Signature: the HMAC-SHA256 hex digest of the raw request body. Verify it with a constant-time comparison before processing the payload.
Delivery and Retries
- Webhooks are an HTTP POST with a
Content-Type: application/jsonbody and aUser-AgentofOliver-Messages/1.0. - Your
callback_urlmust behttps://. Oliver verifies the TLS certificate and allows 10 seconds for a response. - Respond with a
2xxstatus code to acknowledge receipt. - If your endpoint doesn’t respond successfully, Oliver makes up to 3 attempts in total (waiting 2s, then 4s). After that the status isn’t retried on its own, but the next status change sends the latest status. Use
GET /messages/{id}to catch up.

