Set up an endpoint
- In the Merchant Portal, select your merchant and the intended mode, then open Developers → Webhooks endpoints.
- Choose Add endpoint, enter a publicly reachable HTTPS URL, and select the event types your integration handles.
- Store the returned signing secret in your server-side secrets manager. It is shown when the endpoint is created; do not put it in frontend code, logs, screenshots, or support messages.
- Confirm that the endpoint is enabled. Create a Sandbox payment and verify that your server receives and acknowledges its subscribed events.
https://shop.example.com/webhooks/flowlix. URLs cannot contain credentials,
query parameters, or fragments, and must resolve to public addresses.
Redirects are not followed. Your endpoint authenticates Flowlix using the
signature below, not a browser session or an API key in the URL.
Sandbox and Live destinations, events, and signing secrets are separate.
Verify with the secret for the destination and mode receiving the request.
Event types
A Payout can move directly from
PENDING to SUCCEEDED or FAILED,
without a payout.processing event. Do not require every intermediate event
or assume delivery order. Use Payout retrieval
to reconcile its current state.
Refund-related Payment events describe changes to refund totals; they do not
add Payment statuses. A refunded Payment remains SUCCEEDED. Use
amount_refunded, amount_refundable, and the individual Refund statuses.
Safely acknowledge valid event types you do not handle, so compatible additions
do not break your endpoint.
Event payload
Each delivery is an HTTPSPOST with Content-Type: application/json and a
Flowlix-Signature header. The envelope contains an immutable snapshot of
the resource when the event occurred, not the latest state at delivery time.
request: null is normal for an automatic or provider-caused event; do not
substitute the request that originally created the Payment or Payout. A Payout
snapshot has no separate livemode field; use the envelope’s mode.
For a Refund, use
data.object.payment_id to retrieve its parent Payment.
Verify the signature
The header has the formt=<Unix seconds>,v1=<64 lowercase hexadecimal characters>.
Its timestamp belongs to this delivery attempt, not to event.created_at.
- Read the raw request body as bytes, before parsing or reserializing JSON.
- Prefix those bytes with the header’s timestamp and a period:
timestamp + "." + body. - Compute HMAC-SHA256 using the signing secret’s UTF-8 bytes, including the
whsec_prefix. Do not base64-decode the secret or remove its prefix. - Compare the expected and received signature with a constant-time comparison.
- Reject stale timestamps. The example below uses a recommended five-minute tolerance in either direction; keep your server clock synchronized.
Acknowledge and process safely
Return a small, complete2xx response promptly, after durably accepting the
event. Do not perform slow business work before acknowledgement. A non-2xx
response, a redirect, a connection failure, or a timeout is a failed attempt.
Use a database uniqueness constraint on the Event id, scoped to your
merchant integration if your storage serves multiple merchants. In one
transaction, insert the event and a durable processing job. Commit before
returning 2xx; if you cannot persist the event, return a non-2xx response.
A duplicate already durably accepted can receive 2xx without a second job.
The worker processes accepted events and retries its own failures. Protect
external side effects, such as fulfilment, with their own idempotency key;
receiving an event once does not make a business action exactly-once.
Automatic retries
Failed deliveries use the following scheduled offsets from creation of the delivery, including the initial attempt:
Retries include positive jitter of up to 10% of the interval since the previous
slot. These are scheduling offsets, not exact arrival guarantees. Missed retry
slots can be skipped rather than replayed in a burst after downtime. Delivery
stops after acknowledgement or exhaustion of the available retry slots.
The same Event ID and snapshot can arrive more than once, with a fresh signature
timestamp for a new attempt. Events can arrive out of order; do not overwrite a
newer order state blindly with an older snapshot. Retrieve the current Payment
when you need the latest state, and use its
refunds array to reconcile Refunds.
Keep a slower reconciliation loop for payments your system still considers
pending. Webhook delivery and your business processing are separate: a 2xx
response confirms receipt, not successful fulfilment.