GET /transactions, register an HTTPS endpoint and PeerPesa sends a signed POST request for every event you subscribe to. This page covers managing endpoints, the event catalog, signature verification, and retries.
How webhooks work
1
Register an endpoint
Enter your webhook URL in the dashboard. PeerPesa checks that the URL is valid and returns
200, then gives you a webhook key.2
Receive events
When an event occurs, PeerPesa sends a
POST with a JSON body, signed with your webhook key in the X-Signature and X-Timestamp headers.3
Verify and acknowledge
Verify the signature, return a
2xx status within 10 seconds, then process the event asynchronously.Sandbox and production have separate webhook URLs and separate webhook keys. Register a URL in each environment, and verify each environment’s events with that environment’s webhook key.
Set up your webhook in the dashboard
1
Prepare your endpoint
Deploy a URL on your server that accepts
POST requests and responds with HTTP 200. It must be a valid, publicly reachable URL.2
Enter the URL
In the PeerPesa dashboard, open Settings > Webhooks and enter your webhook URL.
3
Pass URL validation
PeerPesa validates the URL format and sends a test request to it. The URL is saved only if your endpoint returns
200.4
Copy your webhook key
After the URL is saved, the dashboard shows your webhook key. Store it securely, for example in an environment variable such as
PEERPESA_WEBHOOK_KEY. You use it to verify signatures.Manage webhook endpoints
Register your webhook URL and get your webhook key in the dashboard, as described above. The endpoints below let you manage webhooks with the API. The same URL rules apply: the URL must be valid and return200.
POST /webhooks
Registers a new endpoint.string
required
Public HTTPS URL that receives events.
string[]
required
Event types to subscribe to. Use
["*"] to receive every event.string
Label to identify the endpoint.
Response
Other endpoints
Event types
Transactions
Deposits and wallets
Quotes, beneficiaries, and account
Recurring payments
Event payload
Every event uses the same envelope.data.object contains the full resource at the time of the event.
transaction.completed
string
Unique event ID. Use it to deduplicate.
string
Event type from the tables above.
boolean
true for production, false for sandbox.object
The resource the event describes.
Signature verification
Every webhook PeerPesa sends is signed so you can confirm it came from PeerPesa and was not modified in transit. Signed webhooks include two headers:
The signature is computed with the webhook key shown in the dashboard after you saved your webhook URL:
Signature formula
X-Timestamp is 1784784828000 and the body is {"id":"evt_2p9x4m",...}, the signed string is 1784784828000.{"id":"evt_2p9x4m",...}.
1
Read the headers
Get
X-Signature and X-Timestamp from the request. Reject the request if either is missing.2
Build the signed string
Join the
X-Timestamp value, a period (.), and the raw JSON request body exactly as received.3
Compute the expected signature
Compute HMAC-SHA256 of the signed string using your webhook key, and hex-encode the result.
4
Compare and check freshness
Compare your result with
X-Signature using a constant-time comparison. Reject events whose X-Timestamp is more than 5 minutes from your server time to block replayed requests.The webhook key is separate from your API keys. Never use it to authenticate API requests, and never expose it in client-side code. If you change your webhook URL or the key is regenerated in the dashboard, update the key in your handler.
Retries and best practices
- Return a
2xxstatus within 10 seconds. Any other response or a timeout counts as a failure. - Failed deliveries are retried with exponential backoff for up to 3 days (about 1m, 5m, 30m, 2h, 6h, then every 12h).
- After repeated failures, the endpoint is set to
disabledand you are notified by email. Re-enable it withPATCH /webhooks/{id}. - Events can arrive more than once or out of order. Deduplicate on event
idand re-fetch the resource with the API if you need the latest state. - Only accept requests with a valid signature, and use HTTPS for every endpoint.
