Skip to main content
A webhook is an HTTPS POST from One Pay to your server when something happens: no polling needed.

Events

Each webhook’s body is an event; data.object is the payment as it was at that moment, exactly as the API returns it:
(data.object is shortened here.)

Add an endpoint

In the dashboard (API keys & webhooks → Add webhook), or by API:
Leave out events to receive every type. The answer includes the signing secret (whsec_...), shown once: store it with your API key.
  • Live endpoints must be https on a public address. Test endpoints may use http://localhost while you build.
  • Up to 10 endpoints per app and mode. Each app’s payments go to that app’s endpoints only.
  • DELETE /v1/webhook_endpoints/{id} stops deliveries at once, retries included.

Check the signature

Anyone can post to your URL. Before trusting a webhook, check it came from One Pay. Each one carries:
v1 is the HMAC-SHA256 of t, a dot and the raw request body, keyed with your endpoint’s secret. Refuse the webhook if the signature differs, or if t is more than 5 minutes from now.
Use the raw body. Parsing the JSON and serialising it again changes the bytes, and the signature will not match.
Every webhook also has the headers OnePay-Event-Id, OnePay-Event-Type and OnePay-Delivery-Attempt.

Answer fast, then work

  • Answer with any 2xx within 10 seconds. Do slow work (emails, invoices) after answering.
  • Anything else (an error, a timeout, a redirect) is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h: 8 tries over about two days.
  • An event can very rarely arrive twice: keep the ids you have handled and skip repeats.
  • Events can arrive out of order: trust data.object.status, not the order of arrival. When in doubt, read the payment with the API.

Replays and history

  • GET /v1/events lists every event, newest first; filter with ?type=payin.succeeded.
  • POST /v1/events/{id}/resend sends one again to every endpoint that wants it: useful after fixing your server.