Webhooks
Webhooks stream real-time pass lifecycle updates directly to your servers. Each delivery is signed with a unique secret (whsec_…) to ensure authenticity and prevent replay attacks.
Event catalogue
Passyn delivers structured events for state changes across passes, turnstiles, and payouts:
pass.purchasedTransaction succeeded; access record created.
pass.activatedAccess flipped to ACTIVE; countdown clock started.
pass.expiredAccess window ended or maximum entries consumed.
pass.revokedManually revoked by merchant operator or dispute.
settlement.paidPayout to connected merchant bank completed.
Payload schema
Every payload contains the event type, timestamp, unique delivery ID, and full entity details:
{"id": "evt_8f2c91d4a07b","event": "pass.expired","createdAt": "2026-06-11T09:00:00.000Z","data": {"accessId": "acc_cm4abc1298ef","userId": "usr_cm4ghi3456jk","passId": "pass_day_gym_24h","passName": "Gym Day Pass","passType": "DAY","status": "EXPIRED","activatedAt": "2026-06-10T09:00:00.000Z","expiresAt": "2026-06-11T09:00:00.000Z","usageCount": 3}}
Signature verification
Headers include Passyn-Signature: t=<timestamp>,v1=<hmac>. Compute the HMAC-SHA256 signature over ${t}.${rawBody} and compare using constant-time equality:
import { createHmac, timingSafeEqual } from "crypto";function verifyPassynWebhook(body: string, header: string, secret: string): boolean {// Passyn-Signature: t=1781168400,v1=9f82...const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));const t = Number(parts.t);// Enforce 5-minute replay attack tolerance windowif (Math.abs(Date.now() / 1000 - t) > 300) return false;const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));}
Delivery & retry guarantees
8-second timeout: Deliveries time out after 8 seconds; any non-2xx status triggers automatic backoff retries.
Idempotency: Handlers must be idempotent. Deduplicate using the event id.
Manual replay: Any failed delivery can be manually replayed directly from the developer console logs.