Skip to content

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

  1. Provide your endpoint URL in the Merchant Console or via POST /webhook-endpoints.
  2. Store the shared signing secret securely; rotate it every 90 days.
  3. 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.