Skip to main content
When you pass a webhook URL to Generate Payment, Flouci calls it once the payment reaches a final state. Every call carries an X-Flouci-Signature header computed with your app’s private token, so you can reject any request that does not come from Flouci before acting on it. You choose the format per payment with the webhook_version field:
Verify the signature before you trust a webhook, then confirm the payment with Verify Payment before you deliver goods. Without the check, anyone who knows your webhook URL can send you a fake success=True.

Delivery

Both versions are delivered the same way: The signature is always HMAC-SHA256(private_token, "<t>.<signed content>"). Only the signed content differs between the versions: Compare the result to v1 in constant time, and reject timestamps older than a few minutes to block replays.

Version 1 — signed GET (default)

string
required
The payment concerned, as returned by Generate Payment.
string
required
True when the payment succeeded, False when it failed. The first letter is uppercase; use the value exactly as received when you compute the signature.

Version 2 — signed JSON events

Send "webhook_version": 2 with Generate Payment to receive a POST instead:
string
required
payment.succeeded or payment.failed. Also sent in the X-Flouci-Event header.
string
required
Unique per payment and event, and unchanged when a delivery is retried. Store it and ignore an event you have already processed.
timestamp
required
When the event was emitted.
string
required
The payment concerned, as returned by Generate Payment.
string
The developer_tracking_id you sent with Generate Payment.
integer
required
Amount of the payment in millimes.
string
required
Always TND. A payment requested in another currency is converted to TND when it is created.
string
required
card, flouci (wallet) or mpayment. NA when no payment method was used, for example when the payment session expired.
The signature check is the same as for subscription events: HMAC-SHA256 over "<t>.<raw body>". See the Python and Node.js samples in Subscription Webhooks.
Sign over the raw request body, not a re-serialized JSON object: any whitespace or key-order difference changes the digest. In Express, use express.raw({ type: "application/json" }) for the webhook route.

Moving from version 1 to version 2

1

Add the signature check to your GET handler

This protects your existing integration right away, with no change to your Generate Payment calls.
2

Deploy a POST handler on the same URL

Accept both methods during the migration: verify the signature with the matching rule, then de-duplicate on payment_id or event_id.
3

Send webhook_version 2

Add "webhook_version": 2 to your Generate Payment calls. Payments created before the switch keep the version they were created with.

Limitations

Only payment webhooks are signed. Payout (send money), partner and POS webhooks are not signed yet. Confirm their outcome with the matching status endpoint before acting on them.