webhook URL you gave at creation as an HTTP POST with a JSON body and an HMAC signature. Webhooks are the way to learn about renewals: they happen while your customer is not on your site, so there is no redirect to catch.
Delivery
The one-off payment webhook is unchanged: a payment created with Generate Payment still receives the legacy
GET <webhook>?payment_id=<id>&success=<true|false> call. Only subscription events use the signed POST described here.Payload
string
required
One of the event names below.
string
required
Unique per event. Store it and ignore a body you have already processed.
timestamp
required
When the event happened.
string
required
The subscription concerned.
string | null
The charge concerned, when the event is about a charge.
null for lifecycle-only events such as subscription.updated.string
required
The subscription’s status after the event.
string
required
Your reference for the subscription.
integer
required
Amount of the charge in millimes.
string
required
Always
TND.date | null
First day of the period the charge pays for.
date | null
Last day (exclusive) of that period.
integer | null
0 for the first attempt of a period, 1–3 for retries.string
required
flouci (wallet) or card.Events
A single charge can produce two events (for example
subscription.charge.succeeded then subscription.reactivated). Each carries its own event_id.
Verifying the signature
The signature isHMAC-SHA256 over the string "<t>.<raw body>" — the timestamp from the header, a dot, and the exact bytes of the request body — keyed with your app’s private token (the second half of your Authorization: Bearer <public>:<private> credential). Compare it to v1 in constant time and reject timestamps older than a few minutes.
Handling events safely
1
Acknowledge fast
Verify the signature, store the event, answer
200, then process. Slow handlers are retried and produce duplicates.2
De-duplicate on event_id
Retries and the occasional double delivery mean you must treat
event_id as the idempotency key.3
Trust the status, confirm the money
status is authoritative for access. For accounting, confirm a charge with Verify Payment using its payment_id — the same rule as for one-off payments.