Introduction
PesaHub notifies your application of payment and payout status changes by sending an HTTPPOST request to the callback_url configured on your API token. Each request body is a JSON payload with an event field identifying what happened.
Payment events:
payment.received— a payment completed successfullypayment.failed— a payment attempt failed
payout.completed— a payout was paid out to the beneficiarypayout.failed— a payout failedpayout.refunded— a payout was refunded by the providerpayout.reversed— a payout was reversed by the provider
event field to branch your handling logic. Your endpoint should respond with a 2xx status once it has accepted the webhook — a non-2xx response or timeout is treated as a failed delivery and retried.
Checksum verification
Every delivery is signed with an HMAC-SHA256 signature so you can confirm a webhook is genuinely came from PesaHub and wasn’t altered in transit.Setting up your passphrase
Signing is enabled per API token. Set a passphrase on the token under Settings > API Access — this is the secret key used to sign every webhook delivered for that token.If no passphrase is set, webhooks are still sent to your
callback_url, but without a signature.The signature header
Signed webhooks include aPesahub-Signature header alongside the JSON body:
The algorithm
The signature is computed over the JSON payload as follows:1
Canonicalize
Recursively sort object keys alphabetically at every nesting level. Sequential (list) arrays keep their original order; only associative objects are sorted.
2
Serialize
JSON-encode the canonicalized payload with slashes unescaped and no extra whitespace.
3
Hash
Compute
HMAC-SHA256(json, passphrase) and take the 64-character hex digest.Verifying a webhook
1
Read the request
Read the raw JSON body and the
Pesahub-Signature header.2
Decode the payload
Decode the JSON body into an associative array/object.
3
Recompute the signature
Recompute the signature over the payload using your
passphrase as the key.4
Compare signatures
Compare the recomputed value against
Pesahub-Signature using a timing-safe comparison (e.g. hash_equals in PHP).5
Reject on mismatch
Reject the request (401/403) if they don’t match, or if the header is missing while you have a passphrase configured.
Notes
- If you rotate your passphrase, PesaHub immediately starts signing new deliveries with the new value — update your verification code at the same time.
- Retried webhooks carry the same payload and therefore the same signature — a repeated signature does not indicate a replay attack.