# Get notified with outbound webhooks

> An outbound webhook makes SkedX Flow POST a signed JSON message to your HTTPS address when events happen. Create it in Settings → Developers → Outbound Webhooks → + New webhook: a Name and “Where should we send it?”; the signing secret is shown once. Choose events under “What should we tell them about?” — for example message.received (A customer sends a message), message.delivered, message.read, message.failed, conversation.assigned, conversation.resolved, contact.tagged, template.status_changed — or Everything. Optional: one channel, one brand, extra headers, and a custom body. The standard body is {"event", "org_id", "data"}, with X-Webhook-Signature (hex HMAC-SHA256 of the raw body), X-Flow-Event and X-Flow-Delivery headers. Answer 2xx within 2 seconds; failures are retried after 30 s, 5 min, 30 min and 2 h, every attempt is logged with Send again, and 410 Gone switches the webhook off.

Product: SkedX Flow · Topic: APIs & Developers · Draft — steps not yet re-verified in the live product

Instead of your system asking Flow “anything new?” every minute, Flow tells it the moment something happens: a customer writes in, a message is delivered or read, a template is approved, a conversation is assigned. You give Flow an address and choose the events; Flow sends each one, signed, within seconds. About eight minutes.

## Step 1: Create the webhook

In Flow, go to **Settings -> Developers -> Outbound Webhooks** and click **+ New webhook**. Give it a **Name** you’ll recognise, paste your system’s address under **Where should we send it?** — use an `https://` address — and click **Create**. Flow shows the **signing secret** once, starting `whsec_`: copy it into your system’s settings now. It proves each delivery came from Flow.
Open it directly: https://flow.skode.ai/settings/?tab=webhooks

## Step 2: Choose what to hear about

Open the new webhook in the list. Under **What should we tell them about?** tick the events you need — each shows a plain name and its code name, and a ticked box is an event Flow will send. A new webhook starts with A customer sends a message. The ones most teams use:

- **A customer sends a message** (`message.received`)
- **A message is delivered**, **is read**, **fails to send** (`message.delivered`, `.read`, `.failed`)
- **A conversation is assigned**, **is resolved**, **goes quiet** (`conversation.assigned`, `.resolved`, `.idle`)
- **A contact gets a tag**, **opts out** (`contact.tagged`, `contact.opted_out`)
- **A template is approved, paused or rejected** (`template.status_changed`)

There are events for campaigns, complaints, orders and lead ads too, or pick **Everything, including new events we add later**.

## Step 3: Send only what matters

**Only from one channel? · optional** limits the webhook to WhatsApp, Instagram or another channel; **Only for one brand? · optional** to one of your brands. Events that don’t belong to a channel or brand are then not sent. Click **Save changes**, and make sure **On** is ticked — only switched-on webhooks receive events.

## Step 4: What arrives

Each event is a **POST** with a JSON body — the event’s name, your workspace id, and a `data` object with the contact, the conversation and the event’s own details. For A customer sends a message that includes the `text`, `message_type` and `message_id`; for delivered, read or failed, the `status` and time; for templates, the name, `status` and `previous_status`. The headers say which event it is (`X-Flow-Event`), give the delivery an id (`X-Flow-Delivery`) and sign it (`X-Webhook-Signature`).

```json
{
  "event": "message.received",
  "org_id": "…",
  "data": {
    "eventMeta": {"type": "message.received", "timestamp": "…"},
    "contact": {"id": "…", "name": "Meera Nair", "firstName": "Meera", "phone": "…", "tags": ["batch-108"]},
    "conversation": {"id": "…", "channel": "whatsapp", "status": "OPEN", "assigneeStatus": "unassigned"},
    "channel": "whatsapp",
    "message_id": "…",
    "message_type": "text",
    "text": "Is class on today?"
  }
}
```

## Step 5: Change the shape they receive (optional)

If the other app expects its own format, write it under **What we’ll send them · empty = the standard envelope**. Put each value in as a token without quotes — `{{contact.name}}`, `{{contact.phone | digits}}`, `{{text | truncate: 200}}` — and Flow writes it in correctly, text or number. Tidy-ups: `digits`, `e164`, `upper`, `lower`, `trim`, `date`, `truncate`, `json`, `default`, `prefix`. Need an API key in the request for their gateway? Add it under **Extra details their app needs to let us in · optional**.

```text
{
  "name":   {{contact.name}},
  "mobile": {{contact.phone | digits}},
  "note":   {{text | truncate: 200}}
}
```

## Step 6: Answer fast; failures retry by themselves

Reply with any `2xx` within 2 seconds, then do slow work afterwards. If your system is down or slow, Flow tries again after 30 seconds, 5 minutes, 30 minutes and 2 hours. The webhook’s delivery log shows every attempt — **Event**, **Result**, **Speed**, **Try** — and **Send again** on any that didn’t get through. After 10 failures in a row Flow pauses for 30 seconds (“Paused — their app failed … times in a row”), and an address that answers `410 Gone` switches the webhook off.

## Step 7: Check each delivery is genuine

Before acting on a delivery, check its signature and skip ids you’ve already handled. The right signature passes; a wrong one, or a body changed on the way, fails — [Check that a webhook really came from Flow](https://skode.ai/help/flow/developers/check-a-webhook-came-from-flow/) has the code for Node, Python and PHP.

## Common questions

### Is there a “send test event” button?

Not yet. Make the event happen once — for A customer sends a message, message your business number from your own phone — and watch it arrive in the delivery log and at your end.

### Can I match delivery updates to the template I sent over the API?

By conversation and contact, yes: each update names them. It doesn’t carry the `id` or `callback_data` from the send request.

### How long is the delivery log kept?

It shows the last 100 deliveries per webhook, each with its attempts — including any that still failed after the last retry, which you can **Send again**. Older ones drop off the list.

### Can I pause a webhook?

Yes — untick **On** and save. Nothing is sent until you tick it again; events in between aren’t queued.

### Can I connect it to Zapier or n8n?

Yes — paste Zapier’s **Catch Hook** URL or n8n’s **Webhook** node address as the destination. [Zapier](https://skode.ai/help/flow/developers/connect-flow-to-zapier/) · [n8n](https://skode.ai/help/flow/developers/connect-flow-to-n8n/).

## Useful links
- Outbound Webhooks in Flow — Settings → Developers → Outbound Webhooks: https://flow.skode.ai/settings/?tab=webhooks
- Flow API reference — the full event list and headers: https://flow.skode.ai/docs/

Videos and screenshots © 2026 SkedX, with sample data only. Share and link to them freely; copying the SkedX product or its design is not allowed. Terms: https://skode.ai/terms/

## Related guides
- Check that a webhook really came from Flow: https://skode.ai/help/flow/developers/check-a-webhook-came-from-flow/
- Connect Flow to Zapier: https://skode.ai/help/flow/developers/connect-flow-to-zapier/
- Connect Flow to n8n: https://skode.ai/help/flow/developers/connect-flow-to-n8n/
- Pause an automation in a chat when someone on your team replies: https://skode.ai/help/flow/automation/automations-pause-when-your-team-replies/

Source: https://skode.ai/help/flow/developers/outbound-webhooks/