Platform
Listen for webhooks
Be told when something happens, instead of polling for it.
Most of what you want to know happens after your request returns: a payment settles, a payout fails, a dispute is raised. A webhook is how you hear about it without asking.
Say where to send events and which ones you want. Subscribe narrowly, every event you accept is one you have to be able to process.
curl -X POST "https://api.tst.au.apgpay.dev/bezel/webhooks" \
-H "Authorization: Bearer $API_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/april",
"events": [
"TransactionPaid",
"TransactionFailed",
"PayoutFailed"
],
"description": "Checkout service",
"metadata": null,
"secret": "whsec-replace-with-32-random-characters",
"merchantId": null,
"marketplaceId": null,
"type": "WebhookCmdCreate"
}'What our calls look like
Each webhook is an HTTP/1.1 POST with Content-Type: application/json and User-Agent: APG-Webhooks/1.0. In production it comes from 35.189.57.237. If a firewall, WAF or bot rule sits in front of your endpoint, allow that address and user agent, and keep verifying the signature.
Answer with a 2xx once you have the event. We do not follow redirects: a 3xx is a failed attempt, retried like a 5xx, and its Location is recorded so you can point the subscription at it. A 401, 403, 408 or 429 is retried too: the first two usually come from something in front of your endpoint that you can fix within the delivery window, and the last two ask us to come back later. Any other 4xx means you rejected the event, and it is not retried.
Registrations accumulate. This is how you find the one still pointing at a hostname you decommissioned.
curl -X GET "https://api.tst.au.apgpay.dev/bezel/webhooks" \
-H "Authorization: Bearer $API_SECRET_KEY"Suspended rather than deleted while you are debugging. A deleted registration takes its history with it, and suspending HOLDS what is owed rather than dropping it: we keep retrying against our own side and call you again when you reactivate, so a few minutes of maintenance costs you nothing. The delivery window still applies, so anything left suspended past it is abandoned as usual.
curl -X PATCH "https://api.tst.au.apgpay.dev/bezel/webhooks/<useWebhookIdFromStep1>" \
-H "Authorization: Bearer $API_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "Suspended",
"type": "WebhookUpdateStatus"
}'Every delivery is recorded against the subscription. Filter by status=Failed to find the ones your endpoint did not accept, or by event to follow one type.
curl -X GET "https://api.tst.au.apgpay.dev/bezel/webhooks/<useWebhookIdFromStep1>/deliveries" \
-H "Authorization: Bearer $API_SECRET_KEY"Reading one
status says where a delivery got to. Delivered means your endpoint accepted it. Failed means it answered and refused, and lastStatusCode is what it said. Abandoned means we stopped trying, either because the delivery window ran out or because the subscription was suspended when its turn came, and lastError tells you which. Pending and PendingRetry are still owed.
lastSentTo is the url we actually called. We read it from the subscription at the moment of the call rather than fixing it when the event happened, which is what lets you correct a wrong endpoint and redeliver without losing the body. It is also the answer to "are you sure you sent it to us".
lastResponseBody and lastResponseHeaders are who answered the most recent call, success included, and are absent when that call got no answer. A delivery recorded as Delivered that your application never saw was accepted by something in front of it, and headers such as server, cfRay or amznRequestId name what.
Three instants make the timing readable. eventPublishedAt is when the thing happened, createdAt is when we picked it up, and lastAttemptAt is when we called you. The first gap is ours; the second is the queue's. attempts counts what we tried rather than what reached you, so an attempt made while the subscription was suspended is counted but never arrived.
Once the endpoint is fixed. You receive the body we tried to send before, not one rebuilt from the event, so a redelivery is what you missed rather than what is true now.
curl -X PATCH "https://api.tst.au.apgpay.dev/bezel/webhooks/<useWebhookIdFromStep1>/deliveries/<useWebhookDeliveryIdFromStep4>" \
-H "Authorization: Bearer $API_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "WebhookDeliveryUpdRedeliver"
}'