Concepts · Concepts

Webhooks

rafiqPay calls your server with a signed event when a payment, refund or payout changes. Verify the signature on the raw body, answer with a 2xx, and make fulfilling safe to repeat.

Events

Add an endpoint in the dashboard (Developers, Webhooks) and choose its events. Test and live events go to endpoints made in that mode. Events are: checkout.session.completed (fulfil an order on this one), checkout.session.expired, checkout.session.late_payment (the customer paid after the checkout closed: the money is credited and you decide whether to fulfil or refund), charge.succeeded, charge.refunded, refund.succeeded, refund.failed, payout.paid, payout.failed (both carry your merchantReference when you gave one), invoice.created, invoice.part_paid, invoice.paid, invoice.overdue, invoice.voided, subscription.created, subscription.renewed, subscription.past_due, subscription.paused, subscription.resumed, subscription.canceled, transfer.held, transfer.accepted, transfer.returned, transfer.refunded_by_provider, payment_method.saved, payment_method.removed, mandate.active, mandate.cancelled, and webhook.test.

An event is recorded in the same database transaction as the change it announces, so it is never sent for something that did not happen, and never lost for something that did.

Verify the signature

Each delivery carries RafiqPay-Signature: t=<unix seconds>,v1=<hex>. The v1 value is the HMAC-SHA256, keyed with your endpoint signing secret, of the text <t>.<raw body>. Check it against the raw request body exactly as received, before parsing anything. Refuse a timestamp more than five minutes old, so a captured delivery cannot be replayed.

Verify a delivery
cURL · v1
# Compute the expected signature for a saved delivery
printf '%s.%s' "$T" "$RAW_BODY" | openssl dgst -sha256 -hmac "$RAFIQPAY_WEBHOOK_SECRET" -hex

Delivery and retries

Answer any 2xx quickly. Any other answer, no answer within 10 seconds, or a refused connection is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and a day: eight tries in all, then the delivery is marked failed. A redirect counts as a failure and is not followed.

The same event can arrive more than once, so make fulfilling safe to repeat: record the event id, or check the order is not already paid. A delivery can be replayed from the dashboard at any time.

An endpoint that fails 40 deliveries in a row is switched off. Addresses must be https and on the public internet: addresses on private networks are refused.

Do not trust the redirect page

The page a customer returns to after paying only displays a result. Fulfil an order from checkout.session.completed, or by retrieving the session, never from the customer arriving.