Webhooks
VRP Billing sends webhook notifications to keep your systems synchronised without polling. Webhooks are delivered as HTTPS POST
requests with JSON payloads signed using HMAC-SHA256.
Endpoint Configuration
- Provide your endpoint URL in the Merchant Console or via
POST /webhook-endpoints
. - Store the shared signing secret securely; rotate it every 90 days.
- Configure retries and alerting on your side to handle delivery failures.
Delivery behaviour
- Webhooks are delivered at least once. Deduplicate using the
event_id
field. - We retry for up to 24 hours using exponential backoff (up to 9 attempts).
- Responses must be acknowledged with any
2xx
status within 10 seconds.
Signature Verification
Each request includes an X-VRP-Signature
header containing a timestamp and signature string (t=timestamp,v1=signature
).
Example verification in Python:
import hmac
import hashlib
payload = request.data
secret = bytes(os.environ["VRP_WEBHOOK_SECRET"], "utf-8")
header = request.headers["X-VRP-Signature"]
timestamp = header.split(",")[0].split("=")[1]
expected = hmac.new(secret, f"{timestamp}.{payload.decode()}".encode("utf-8"), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, header.split("v1=")[1]):
raise ValueError("Invalid webhook signature")
Reject requests older than five minutes to prevent replay attacks.
Event Types
Event | Description |
---|---|
mandate.created |
A mandate was accepted but is pending SCA completion. |
mandate.activated |
Mandate is active and can be used for payments. |
mandate.revoked |
Mandate revoked by merchant, customer, or bank. |
mandate.suspended |
Risk or compliance controls have suspended the mandate. |
payment.submitted |
A payment has been submitted to the bank. |
payment.settled |
The payment cleared successfully. |
payment.failed |
Payment failed; see failure_code . |
payment.refunded |
A refund was issued against the payment. |
refund.created |
A refund was requested and is pending settlement. |
refund.settled |
Refund has cleared and funds returned to the customer. |
Example Payload
{
"event_id": "evt_123",
"event_type": "payment.settled",
"created_at": "2024-02-21T09:22:01Z",
"data": {
"id": "pay_789",
"mandate_id": "mandate_f9d3",
"amount": "42.50",
"currency": "GBP",
"status": "settled",
"settlement_date": "2024-02-22"
}
}
Handling Failures
If your endpoint returns a non-2xx status code or times out, we retry with backoff. After the retry window expires the event is marked delivery_failed
and visible in the Merchant Console. You can trigger manual retries via POST /webhook-events/{event_id}/retry
.
Testing
Use the sandbox to generate test events:
curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
https://sandbox.api.vrpbilling.com/v1/webhooks/test \
-d '{"event_type": "payment.settled"}'
Sandbox webhooks are delivered to registered endpoints prefixed with https://sandbox.
and include the header X-VRP-Sandbox: true
for filtering.