Webhooks
When something happens in Reshta (a contact is created, a deal is won, an order is placed) Reshta sends a signed POST request to your URL. No need to keep polling the API.
- Only HTTPS URLs on public addresses are accepted; private network addresses are refused and redirects are not followed.
- Only events that happen after the webhook is created are sent.
- Records that come from file imports or sample data do not send webhook events.
Event catalogue
18 eventsEach event is named object.verb. The body carries only IDs (and, for updates, the names of the changed fields); read the record through the API for details.
POST https://example.com/reshta/webhookContent-Type: application/jsonUser-Agent: Reshta-Webhooks/1Reshta-Event: deal.wonReshta-Delivery: 0192c5a1-3a5b-7c6d-8e7f-90a1b2c3d4e5Reshta-Signature: t=1793022003,v1=b5230efdbd5ecead2c10e5373c02395791808788f66ebe612cd0bf9557a6bfc6{ "id": "0192c5a1-2f4e-7a10-8b3c-1d2e3f405162", "type": "deal.won", "created_at": "2026-10-26T14:20:03.000Z", "data": { "deal_id": "0192c5a0-9e8d-7c6b-5a49-382716051f2e" }}Every event has the same envelope: a unique event id for de-duplication, type, created_at and data. The Reshta-Event and Reshta-Delivery headers carry the event name and the delivery ID.
The sample signature is computed over this exact body with the secret whsec_example.
Verify signatures
Every request carries a Reshta-Signature header: t is the send time (Unix seconds) and v1 is the HMAC-SHA256 signature with that webhook’s signing secret.
Reshta-Signature: t=1793022003,v1=b5230efdbd5ecead2c10e5373c02395791808788f66ebe612cd0bf9557a6bfc6- 1Split t and v1 out of the header.
- 2Compute HMAC-SHA256 of “t, a dot, the raw body” with the signing secret (hex).
- 3Compare the result with v1 in constant time.
- 4Our advice: reject the request if t is more than 5 minutes from your clock; t is inside the signed string, so it cannot be forged.
import crypto from "node:crypto";// rawBody: the request body exactly as received (a string or Buffer).export function verify(rawBody, header, secret) { const p = Object.fromEntries(header.split(",").map((kv) => kv.split("="))); const expected = crypto .createHmac("sha256", secret) .update(`${p.t}.${rawBody}`) .digest("hex"); const fresh = Math.abs(Date.now() / 1000 - Number(p.t)) < 300; const a = Buffer.from(expected), b = Buffer.from(p.v1 ?? ""); return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);}Retries & delivery history
If your URL does not answer 2xx, Reshta resends the same event at these intervals; about 24 hours in total.
- 1First sendnow
- 21 minlater
- 35 minlater
- 430 minlater
- 52 hlater
- 66 hlater
- 715 hlater
- ✕Failedkept in history
Delivery history in the app
| Event | Status | Attempts | Last response | Created | Replay |
|---|---|---|---|---|---|
| deal.won | Delivered | 1 of 7 | 200 | Today 14:20 | |
| order.created | Retrying | 3 of 7 | 503 | Today 14:05 | |
| contact.created | Failed | 7 of 7 | 500 | Yesterday 09:12 | Replay |
| deal.stage_changed | Delivered | 2 of 7 | 200 | Yesterday 08:40 | Replay |
| form.submitted | Waiting to send | 0 of 7 | — | Today 14:21 |