Register an endpoint
Register endpoints per environment in the dashboard under Settings → Developers → Webhooks. You choose a URL and the events to subscribe to. Creation also returns an endpointsecret; keep it, but see Verify the signature for which key actually signs payment deliveries.
For local development, expose your machine through an HTTPS tunnel and register the tunnel URL on the sandbox.
Manage endpoints with the API
Endpoint management uses a merchant session token, because it is a dashboard operation.secret appears only in this response. Setting isActive to false pauses delivery without deleting the endpoint. Deleting an endpoint stops future deliveries but keeps its delivery history for audit.
What Vestrapay sends
Each delivery is an HTTP POST with a JSON body. Webhook bodies are not wrapped in the success envelope.Events
The list of subscribable events is returned by GET
/v1/merchants/webhooks/events. It also includes account-level events beyond payments, such as KYB outcomes. Subscribe an endpoint only to the events you handle, and always ignore an event name you do not recognise by returning 200 without acting on it, so new events never break your handler.
Each event is delivered once per matching endpoint. If two active endpoints subscribe to the same event, both receive it.
Verify the signature
Anyone who learns your URL could post to it, so check the signature on every request. For payment and other environment-scoped deliveries, Vestrapay signs the body with the merchant’s active secret API key for that environment (sk_test_… in sandbox, sk_live_… in live). That is the same secret key you use for initialise and verify. The endpoint secret returned when you create a webhook is only used as a fallback when no active encrypted secret key can be resolved for the environment.
Compute the HMAC-SHA256 of the exact raw bytes of the request body with that key, hex-encode it, prefix it with sha256=, and compare it to the X-Vestrapay-Signature header with a constant-time comparison. Reject the request with 401 if it does not match.
Security notes
- Keep the secret API key in a secrets manager. Treat it like a password.
- Use a constant-time comparison, as in the samples. A plain string comparison leaks timing information.
- Reject requests with a missing or malformed signature header before doing any work.
- Do not trust the body for fulfilment. Verify the reference with your secret key, even when the signature is valid.
- If a secret key is exposed, rotate it in Settings → Developers and update every verifier that checks webhook signatures.
Respond quickly
Return a 2xx status as soon as the signature checks out and the event is safely queued. Do the slow work, which is verification, database writes, emails and fulfilment, in a background worker.Delivery, timeouts and retries
Because deliveries are retried, you can receive the same event more than once, and events can arrive out of order. Handle both:
- Be idempotent. Key your handling on the reference and the event. Ignore an event for an order that is already in a final state.
- Do not rely on order. Retries can delay one event past another for the same payment. Always verify the reference rather than inferring state from the sequence of events.
- Do not depend on webhooks alone. If your endpoint was down for longer than the retry window, call verify for any order still pending. A periodic reconciliation job over unpaid orders is a sensible safety net.
Troubleshooting
Open the delivery history for the endpoint, in the dashboard or via GET/v1/merchants/webhooks/{webhookId}/deliveries. Each attempt records the URL, request body, response status, response body, attempt number and result.