Developers
Webhooks
Een webhook vertelt u dat een order van status is veranderd. Het vervangt het lezen van de order niet: het is een melding, geen bron van waarheid.
Gepubliceerd contract, nog niet open
Webhooks worden vandaag niet verzonden. Hun vorm, handtekening en herhalingsbeleid zijn hier vastgesteld en gepubliceerd, zodat uw ontvanger vooraf kan worden geschreven en getest.
Gebeurtenissen
Elke gebeurtenis heeft dezelfde envelop: een id, een type, een tijdstempel en een data-object. Abonneer u op de typen die u afhandelt en negeer de rest stilzwijgend — er zullen nieuwe typen worden toegevoegd, en een ontvanger die faalt op een onbekend type, breekt zichzelf.
| Type | Wat het betekent |
|---|---|
order.created | De order is aangemaakt en de koers is vastgelegd. Het stortingsadres is toegewezen. |
order.deposit_detected | Een inkomende transactie wordt op het netwerk gezien, vóór bevestiging. Gebruik dit evenement om de gebruiker gerust te stellen, nooit om iets te leveren. |
order.confirming | De bevestigingsteller vordert. Uitgezonden bij elke stap, niet bij elk blok. |
order.deposit_confirmed | Het aantal bevestigingen dat door het netwerk wordt vereist, is bereikt. |
order.underpaid | Het ontvangen bedrag ligt onder het verwachte bedrag buiten tolerantie. De order is niet verloren: deze wacht op een keuze tussen bijstorten, doorgaan met het ontvangen bedrag of een terugbetaling. |
order.overpaid | Het ontvangen bedrag overschrijdt het verwachte bedrag. Het oorspronkelijke bedrag blijft tegen de vastgelegde koers; het overschot wordt apart afgehandeld. |
order.payout_sent | De overschrijving is vertrokken via het betaalnetwerk. Let op: verzonden is niet ontvangen — de resterende vertraging hangt af van de bank van de begunstigde. |
order.completed | De afwikkeling is bevestigd door het betaalnetwerk. Eindtoestand. |
order.payout_failed | Het betaalnetwerk heeft de overschrijving afgewezen of geretourneerd, met de reden. Er wordt geen automatische herpoging gedaan bij een retour van de bank: de oorzaak zit bijna altijd in de details. |
order.refunded | De fondsen zijn teruggeboekt, uitsluitend naar het oorspronkelijke adres, na aftrek van netwerkvergoedingen. |
De payload
Een constante envelop, ongeacht het type.
{
"id": "evt_01J9ZQF3K8N2M4X7",
"type": "order.payout_sent",
"created": 1788356981,
"data": {
"reference": "K7Q4-M2XB",
"state": "PAYOUT_SENT",
"railId": "sepa_instant",
"netMinor": 91228,
"currency": "EUR",
"sentAt": "2026-09-02T12:21:44Z"
}
}Handtekening
Elke levering bevat een handtekeningheader: een tijdstempel en een HMAC-SHA256 berekend over dat tijdstempel, een punt en de RUWE aanvraagbody.
Fiatside-Signature: t=<timestamp unix>,v1=<hex hmac-sha256>import { createHmac, timingSafeEqual } from 'node:crypto'
// IMPORTANT : le corps doit etre le corps BRUT, avant tout parsing JSON.
// Re-serialiser l'objet change l'ordre des cles et invalide la signature.
export function verify(rawBody: string, header: string, secret: string): boolean {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=') as [string, string]))
const timestamp = Number(parts['t'])
const signature = parts['v1']
if (!timestamp || !signature) return false
// Rejeu : une signature valide capturee hier ne doit pas etre rejouable aujourd'hui.
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
const a = Buffer.from(expected, 'hex')
const b = Buffer.from(signature, 'hex')
// Comparaison a temps constant : un === laisse fuiter la signature octet par octet.
return a.length === b.length && timingSafeEqual(a, b)
}- Onderteken de ruwe body, vóór enig parsen. Het opnieuw serialiseren van het JSON-object verandert de volgorde van de sleutels en de witruimte: de handtekening komt niet meer overeen en u zult lang zoeken.
- Vergelijk in constante tijd. Een ===-vergelijking stopt bij de eerste verschillende byte, waardoor een aanvaller de verwachte handtekening byte voor byte kan meten.
- Wijs af buiten het 300-seconden tolerantievenster. Zonder die controle blijft een geldig verzoek dat gisteren is vastgelegd vandaag herspeelbaar.
- Antwoord 200 vóór verwerking. Plaats de gebeurtenis in uw wachtrij en handel deze daarna af: lange verwerking veroorzaakt een time-out en dus een herhaling, ook al hebt u de gebeurtenis wel ontvangen.
Herhalingen en volgorde
Elke niet-2xx-status, of geen antwoord, veroorzaakt een herhaling volgens het onderstaande schema.
| Poging | Vertraging |
|---|---|
| 1 | onmiddellijk |
| 2 | 30 s |
| 3 | 2 min |
| 4 | 10 min |
| 5 | 1 h |
| 6 | 6 h |
- De aankomstvolgorde is niet gegarandeerd. Een uitbetalingsgebeurtenis kan aankomen vóór de bevestigingsgebeurtenis die er logisch aan voorafgaat: vertrouw op de orderstatus, niet op de volgorde van ontvangst.
- Hetzelfde evenement kan twee keer aankomen. Bewaar de evenement-id en negeer een id dat al is afgehandeld: idempotentie aan uw kant is uw verantwoordelijkheid, en het is gemakkelijk te realiseren.
- Vertrouw nooit op bedragen in de payload om iets aan uw kant te crediteren. Lees de order opnieuw via de API: de payload zegt dat er iets is gebeurd, de API zegt precies wat.
- Na de laatste poging wordt het evenement verwijderd en blijft het zichtbaar in uw evenementenlogboek. U kunt het handmatig opnieuw afspelen.