Webhooks

A webhook tells your own system what happened, the moment it happens, so you never have to poll for changes. **Choosing what you hear about.** Every webhook has one or more template-scoped `rules`. A rule always names its `template_id`; optional `actions` and `addresses` narrow that template to action names and action signers. Empty lists mean every action or signer for that template. Rules are ORed and fields inside a rule are ANDed. There are no organization-wide webhooks. **What arrives.** One `POST` to your address per matching action, carrying `{ id, type, event, when_created }` and three headers: | Header | What it holds | | --- | --- | | `X-Webhook-ID` | Which of your webhooks matched | | `X-Event-ID` | The delivery's identifier, the same on every retry | | `X-Webhook-Signature` | Proof the request really came from us | **Checking it is really us.** The signature looks like `t=<unix seconds>,v1=<hex>`. Take the signing key you received when you created the webhook, decode it from hex, and compute an HMAC-SHA256 over the exact text `{timestamp}.{body}` — using the body bytes as they arrived, not a re-encoded copy. Compare the result with the `v1` value using a constant-time comparison, and turn away anything whose timestamp is more than about five minutes old. **When something goes wrong.** Answer with any `2xx` within ten seconds and the delivery is done. Anything else is a failure, and we try again up to three more times, waiting roughly 2, 4 and 8 minutes in between. After that the delivery is marked `failed` and left alone. Answer `410 Gone` to stop the retries at once — the polite way to say you no longer want this webhook. A long outage can leave a pile of failed deliveries behind: replay each one with `POST /webhooks/{webhookId}/events/{eventId}/redeliver` once you are back. Three failed or dead-lettered deliveries within a rolling hour switch the webhook off, so `is_active: false` is a sign to inspect your endpoint. Because we retry, the same event can reach you more than once. Use `X-Event-ID` to recognise a repeat and ignore it. **Your address.** It has to be an ordinary public `https` address, with no username or password built into the URL. Addresses on a private or internal network are refused, both when you save them and again when we dial them. An organization can have up to 5 webhooks. Every action is delivered separately to each one that matches, so a few well-aimed webhooks beat many broad ones.

Base URLhttps://api.dual.network
AuthBearer JWTx-api-key

Endpoints (8)