A webhook is PocketPass telling your system something happened, instead of your system asking us over and over. You give us a URL, we POST to it whenever one of the events below occurs.
The events
| Event | Fires when |
|---|---|
customer.created | A golfer is added, whether by sync, signup page, or by hand |
customer.updated | A golfer's details change |
customer.deleted | A golfer is deleted |
wallet_pass.installed | A pass is added to Apple Wallet or saved to Google Wallet |
house_account.transaction.created | Money moves on a golfer's own house account |
shared_account.transaction.created | Money moves on a shared account. Includes the shared account and the member who made the transaction |
merchant.closing | Your account is scheduled for closure: when an owner asks, then 30, 7 and 1 days before its data is deleted. Includes the deletion date |
You choose which events each endpoint receives, so a receiver that only cares about installs isn't woken up by every detail change.
Setting one up
- Open Settings → Developers.
- Add an endpoint: the URL to POST to, and the events it should receive.
- Copy the signing secret shown for that endpoint and store it with your other secrets.
Your endpoint needs to be reachable over HTTPS at a public address and should reply 2xx quickly. Do the real work afterwards, not before you reply - a slow endpoint gets treated as a failed one. Redirects aren't followed, and addresses on private networks are refused.
Verifying a delivery is genuine
Your webhook URL is open to the internet, so anyone who learns it could POST to it. Every delivery carries a signature that proves it came from PocketPass and that nothing was changed in transit.
The header looks like:
Golfpass-Signature: t=1758592800,v1=<hex hmac>
To verify it:
- Read
t(a Unix timestamp) andv1(the signature) from the header. - Build the signed input: the timestamp, a literal full stop, then the exact raw request body -
t + "." + body. - Compute HMAC-SHA256 over that input using your endpoint's signing secret, and hex-encode it.
- Compare with
v1using a constant-time comparison, not==. - Reject anything where
tis more than about five minutes old, which stops an old delivery being replayed at you.
Sign the raw body exactly as received. If your framework parses the JSON and you re-serialise it before checking, key order or spacing can change and the signature will never match. Capture the raw body first.
When your endpoint is down
Deliveries are retried, so a short outage doesn't lose anything:
- Any reply that isn't
2xx, and any timeout past 10 seconds, counts as a failure. - PocketPass retries up to 5 times, waiting 1 minute, 5 minutes, 30 minutes, 2 hours, then 12 hours - roughly 14 hours of trying.
- After the fifth attempt the delivery is marked failed.
- An endpoint that fails five times in a row is disabled automatically, so one permanently broken receiver doesn't hold up the queue. Fix it, then re-enable it in Settings → Developers.
Designing a receiver that behaves
- Expect duplicates. A retry can arrive after your system already handled the first attempt. Make handling an event twice harmless, keyed on the event's id.
- Don't assume order.
customer.updatedcan arrive beforecustomer.createdif the first delivery was retried. Treat each event as a statement about the current state. - Reply first, work after. Acknowledge with
2xx, then process. Slow processing turns into retries and eventually a disabled endpoint.
Webhooks from automations
An automation can also send a webhook as one of its steps, for example "when a golfer reaches their 5th visit, post them to our CRM". Those requests are signed with the same Golfpass-Signature scheme above, using a signing secret that belongs to the automation (admins can see and rotate it on the step). Each request also carries:
Golfpass-Event: automation.stepGolfpass-Delivery: the same value on every retry of one step for one golfer, so you can ignore repeats.
A failed automation webhook is tried up to 5 times over about 3 hours, and every attempt and response shows on the automation's Activity tab.
Building this for the first time? Point the endpoint at a request-inspection service, trigger a change in the dashboard, and look at a real delivery before you write any verification code.