Webhook

Event delivery to your endpoint

​

Roster POSTs each subscribed event to your registered endpoint, signed with the endpoint's whsec_ secret:

Roster-Signature: t={unix_seconds},v1={hex hmac_sha256("{t}.{raw_body}", secret)}

The HMAC key is the whole secret string, whsec_ prefix included, as UTF-8 bytes: do not strip the prefix or decode the rest. Verify by recomputing the HMAC over {t}.{raw body} and comparing in constant time; reject the delivery when t is more than 300 seconds away from your clock, in either direction, even when the HMAC matches.

Every delivery, the test one included, identifies itself with User-Agent: Roster-Webhooks/1.0; allow it if a firewall filters the calls to your receiver. It also names the endpoint it was sent to in Roster-Webhook-Endpoint, the we_ id, so two endpoints on the same URL can be told apart. The signature covers only t and the raw body, not the headers: use the id to pick the endpoint's secret, and trust it only once the signature verifies with that secret.

Answer with any 2xx within 3 seconds. A slower answer, any other status, a redirect (Roster never follows redirects) or a failed connection counts as a failed attempt.

Delivery is at-least-once — deduplicate by event_id. A retry goes only to the endpoints that have not accepted the event yet, so a failing endpoint does not multiply deliveries to the others. An endpoint that answered 2xx can still receive a duplicate, for example when its answer did not reach Roster in time. Retries come in rounds. The first round starts right away, with attempts about one minute apart: 5 in production and 100 in the sandbox. If every attempt in a round fails, a new round starts within about an hour. No new round starts later than 24 hours after the event was first queued for delivery; after that, automatic retries stop.

Delivery order is not guaranteed: a retried or delayed notice can arrive after a newer one, so do not use arrival order as business order. Use GET /v1/events for activity changes or GET /v1/financial_events for donation, donor and refund updates when recovering missed notices.

Headers

  • t={unix_seconds},v1={hmac_sha256("{t}.{body}", secret)}, keyed with the whole whsec_ secret as UTF-8 — reject a t more than 300 seconds away from your clock, in either direction. The header carries one t and one or more v1, comma-separated: today exactly one, and you accept the delivery when any v1 matches, so a delivery signed with more than one secret (for example during a secret rotation) still verifies.

  • Id of the endpoint this delivery was sent to (we_...), as POST /v1/webhook_endpoints returned it. It is not a secret, and it is not covered by Roster-Signature: use it to pick that endpoint's secret, and trust it only after the signature verifies with that secret.

Body

required
application/json

Responses

  • Return any 2xx to acknowledge the delivery.

Request Example for postpartnerEvent
{
  "event_id": "",
  "event_type": "partner_session.created",
  "occurred_at": "",
  "church_id": "",
  "entity_id": "",
  "livemode": true,
  "payload": {}
}
No Body