Skip to main content
Webhooks push payment and refund state changes to your server the moment they happen, so you can fulfil orders, update your database, and notify customers without polling.

Setup

  1. In the Merchant Portal, open Developers → Webhooks and add an endpoint URL (HTTPS required, publicly reachable).
  2. Select the events you want to receive (or all of them).
  3. Copy the endpoint’s signing secret (whsec_...). You will use it to verify that events really come from Flowlix.
Endpoints are configured per mode: test-mode events go to your test endpoints, live-mode events to your live endpoints.

Events

Event payload

Every delivery is a POST with a JSON envelope; data contains the full current object exactly as GET /v1/payments/{id} would return it:
Refund events carry data.refund (and data.refund.payment_id links back to the payment).

Verifying signatures

Every delivery includes a Flowlix-Signature header:
To verify:
  1. Split the header into t (Unix timestamp) and v1 (hex signature).
  2. Compute HMAC-SHA256(signing_secret, "{t}.{raw_request_body}").
  3. Compare your result to v1 with a constant-time comparison.
  4. Reject the event if the signature does not match or t is more than 5 minutes old (replay protection).
Always verify the signature before trusting an event. Anyone can send JSON to a public URL.

Delivery semantics

  • Respond fast with 2xx. Acknowledge within 10 seconds — persist the event and process it asynchronously if your handling is slow. Any non-2xx response (or a timeout) counts as a failed delivery.
  • Retries. Failed deliveries are retried with exponential backoff for up to 24 hours. After that the delivery is marked failed; you can inspect and replay deliveries from the Merchant Portal.
  • At-least-once. The same event can be delivered more than once. Make your handler idempotent — deduplicate by the event id.
  • Ordering is not guaranteed. Events may arrive out of order. Don’t apply state from the event blindly; either rely on the full object in data (which is always the current state at delivery time) or re-fetch via GET /v1/payments/{id}.
Webhooks complement, not replace, polling: keep a slow reconciliation loop with GET /v1/payments for payments that somehow missed an event (your endpoint was down longer than the retry window, a network partition, etc.).