Skip to content
Last updated

Webhook Quick-Start

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, then read on WhatsApp)

Webhooks are configured at the account level and delivered on a best-effort basis.


What is a webhook?

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:

  1. Create an HTTPS endpoint
  2. Configure the webhook URL in Admin → API
  3. Receive JSON events in real-time

Types of webhook events

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 TypeDescription
message.inboundA customer sends a message to your SMS, WhatsApp, Messenger or RCS agent
message.statusEach delivery outcome for an outbound message

Your webhook handler should be idempotent. In rare failure scenarios, duplicate events may occur.


1. Configure your webhook URL

Webhooks are configured once per account and apply to all API-sent messages.

https://yourapp.com/webhooks/instamessage

Your endpoint must:

  • Be publicly accessible
  • Accept POST requests
  • 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.


2. Example webhook payloads

Inbound message event

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_id to correlate replies to prior outbound messages
  • Inbound messages may include media fields depending on channel and message type

Delivery status event

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: read is 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.


3. Webhook delivery behaviour

  • 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.


5. Write a webhook receiver

Your webhook endpoint can be implemented in any language or framework that can accept HTTPS POST requests.

Your webhook handler should:

  • Accept POST requests
  • 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"
  }'

6. Test webhooks locally

Most developers use a tunneling tool such as:

  • ngrok
  • Cloudflare Tunnel
  • LocalTunnel

Example with ngrok:

ngrok http 3000

ngrok will give you a public HTTPS URL such as:

https://abc123.ngrok.io/webhooks/instamessage

Use that URL in your InstaMessage webhook configuration to receive real events during development.


7. Securing your webhook endpoint

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_type value
  • Ensuring the message_id or event_id exists in your system
  • Restricting the endpoint to InstaMessage IP ranges (optional; ask support)

Signature validation will be added soon.


Next steps

Once you’ve received your first webhook, you can: