Webhooks allow your application to receive real-time events from InstaMessage.
Instead of polling for updates, your server is notified automatically when:
- A customer sends an inbound message
- A message’s delivery status changes (for example
delivered, thenreadon WhatsApp)
Webhooks are configured at the account level and delivered on a best-effort basis.
A webhook is an HTTPS endpoint on your server that InstaMessage sends events to via POST requests.
Whenever an event occurs - such as a customer replying to a message or a message being delivered or failing - InstaMessage sends a JSON payload to your configured webhook URL.
You simply:
- Create an HTTPS endpoint
- Configure the webhook URL in Admin → API
- Receive JSON events in real-time
Delivery status events are sent when a message’s delivery status changes.
You may receive multiple message.status events for the same message (for example: delivered followed by read).
Each status transition is emitted at most once, but your handler should be idempotent because duplicates may occur in rare failure scenarios.
| Event Type | Description |
|---|---|
message.inbound | A customer sends a message to your SMS, WhatsApp, Messenger or RCS agent |
message.status | Each delivery outcome for an outbound message |
Your webhook handler should be idempotent. In rare failure scenarios, duplicate events may occur.
Webhooks are configured once per account and apply to all API-sent messages.
https://yourapp.com/webhooks/instamessageYour endpoint must:
- Be publicly accessible
- Accept
POSTrequests - Parse JSON
- Respond with HTTP
200 OK
If your endpoint fails to respond with 200 OK, the webhook will not be retried.
Per-message webhook overrides are not supported. All events are sent to the account-level webhook URL.
message.inbound
{
"event_type": "message.inbound",
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "whatsapp",
"from": "+447111222333",
"text": "Yes please",
"timestamp": "2026-01-14T12:05:42Z"
}- Sent once per inbound message
- Works for SMS, WhatsApp and RCS (RCS suggested-reply taps also arrive as inbound messages)
- Use
conversation_idto correlate replies to prior outbound messages - Inbound messages may include media fields depending on channel and message type
message.status
{
"event_type": "message.status",
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "sms",
"to": "+447123456789",
"status": "delivered",
"timestamp": "2026-01-14T12:03:11Z"
}Statuses can include:
- delivered
- failed
- read (where supported)
Note:
readis only included for channels that support read receipts (e.g., WhatsApp and RCS).
Note: SMS delivery reporting depends on carrier support and destination. Some statuses may not be available for all messages.
- Webhooks are best-effort
- Events are sent on status changes
- Each status is emitted at most once per message
- No retries are performed
- Order is not guaranteed
- Your endpoint must be idempotent
If a webhook is missed or unavailable, you can always retrieve the latest delivery status using the Message Status API.
If you miss a webhook event, you can retrieve the latest delivery status using the message_id returned when the message was created.
GET /v1/messages/{message_id}Example response:
{
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "sms",
"to": "+447123456789",
"status": "delivered",
"created_at": "2026-01-14T12:02:10Z",
"delivered_at": "2026-01-14T12:03:11Z"
}This endpoint exists specifically as a recovery mechanism if a webhook delivery is missed.
Your webhook endpoint can be implemented in any language or framework that can accept HTTPS POST requests.
Your webhook handler should:
- Accept
POSTrequests - Parse JSON payloads
- Respond with HTTP 200 OK immediately
- Process events asynchronously
- Safely ignore unknown or duplicate events
Below are simple examples for receiving InstaMessage webhooks in different languages.
curl -X POST "https://yourapp.com/webhooks/instamessage" \
-H "Content-Type: application/json" \
-d '{
"event_type": "message.status",
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "sms",
"to": "+447123456789",
"status": "delivered",
"timestamp": "2026-01-14T12:03:11Z"
}'Most developers use a tunneling tool such as:
- ngrok
- Cloudflare Tunnel
- LocalTunnel
Example with ngrok:
ngrok http 3000ngrok will give you a public HTTPS URL such as:
https://abc123.ngrok.io/webhooks/instamessageUse that URL in your InstaMessage webhook configuration to receive real events during development.
Security best practices:
✅ Always use HTTPS
Use HTTPS (non-HTTPS URLs are rejected)
✅ Validate InstaMessage signatures (coming soon)
// TODO: verify signature header (when enabled)
We will add a request signature header like:
X-IM-Signature: sha256=<hash>Your server should verify this to ensure:
- the webhook really came from InstaMessage
- the payload wasn’t tampered with
✅ Respond quickly
Return 200 OK immediately. Process the event asynchronously if required (queues, workers, background tasks).
✅ Webhooks are best-effort
Webhooks are delivered on a best-effort basis.
If your webhook endpoint is unavailable or fails to respond with 200 OK, you may miss individual events.
You can always retrieve the latest status for any message using the Message Status endpoint by passing the message_id.
Until webhook signatures are available, you can optionally validate payloads by:
- Checking the
event_typevalue - Ensuring the
message_idorevent_idexists in your system - Restricting the endpoint to InstaMessage IP ranges (optional; ask support)
Signature validation will be added soon.
Once you’ve received your first webhook, you can:
- Handle inbound messages → Inbound Messages & Replies
- Track delivery and read receipts → Delivery Receipts & Message Status
- Send replies and outbound messages → Send a Message
- Set up WhatsApp templates for outbound messaging → WhatsApp Templates
- Manage contacts created by inbound messages → Contacts