Payment webhooks
When a checkout reaches an outcome, Apiosk Pay posts a signed event to thewebhook_url on your marketplace. It fires on paid, failed and cancelled.
The destination is frozen onto the checkout at creation, so changing your
webhook URL mid-flight does not redirect events for payments already in progress.
Headers
Body
merchant_id is the
canonical Connect merchant UUID, the same value seller.id returned at creation.
Verifying
The signature isHMAC-SHA256 over the string "{t}.{raw body}", keyed with
your Connect webhook secret, hex encoded.
- Verify over the raw bytes. Parsing the JSON and re-serialising it reorders keys and changes the signature. Capture the body before your framework touches it.
- Check
t. The timestamp is what makes a captured event unusable later. Ignoring it gives up replay protection entirely. - Compare in constant time. A byte-by-byte early return leaks the expected signature over enough attempts.
If the platform has no webhook secret configured, delivery is skipped, not
sent unsigned. An unsigned webhook is indistinguishable from a forged one.
Delivery is best-effort
One attempt, a 5 second timeout, no retries. It is a nudge to go and look, and your integration must be correct without it.Not the same as merchant.activated
Connect’s ownmerchant.activated webhook, fired by the gateway when a seller
finishes onboarding, uses the same header names but a bare HMAC of the body
with no timestamp, and retries three times. If you verify both in one handler,
do not share the verification code: a bare-HMAC verifier will reject every
payment event, and a timestamped verifier will reject every activation.
Related links
- Lifecycle: /pay/lifecycle
- API reference: /pay/checkout-api
- Connect (marketplace): /guides/connect-marketplace