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)}
Verify by recomputing the HMAC over {t}.{raw body} and comparing in
constant time; reject t older than 300 seconds even when the
HMAC matches.
Delivery is at-least-once with limited retries — deduplicate by
event_id, and use GET /v1/events as the reconciliation source of
truth. Answer 2xx quickly; anything else (or a timeout) counts as
failure and triggers a retry, which may re-deliver events you already
accepted.
- Type: stringRoster
- Signature requiredt={unix_seconds},v1={hmac_sha256("{t}.{body}", secret)}— reject timestamps older than 300 seconds.
Event envelope — identical on the pull feed and on webhook deliveries. payload carries only the allowlisted fields of each type (for example enrollment.created → {enrollment_id, church_id, mode, value}; enrollment.activated → {enrollment_id}).
- Type: stringchurch
_id required - Type: stringevent
_id requiredGlobally unique — the deduplication key.
- Type: string · enumevent
_type requiredEvent types visible to the partner (feed and webhooks).
values- partner
_session .created - partner
_session .opened - partner
_session .completed - partner
_session .expired - church
.created
- Type: string Format: date-timeoccurred
_at requiredBusiness time of the event.
- Type: objectpayloadrequired
Field-allowlisted projection, per event type.
- 200
Return any 2xx to acknowledge the delivery.
{
"event_id": "",
"event_type": "partner_session.created",
"occurred_at": "",
"church_id": "",
"payload": {}
}