Webhooks
Coinetic meldt wijzigingen in een factuur met een POST-request aan uw server. Een webhook is een signaal ‘bekijk de factuur’, geen bewijs van betaling.
Instellen
- Dashboard → ‘Sleutels en webhooks’ → ‘Toevoegen’. De URL is alleen
https://naar een publiek adres op poort 443 (in de sandbox ookhttp://localhost). - Het secret van het endpoint wordt één keer getoond. Maximaal 5 actieve endpoints: elk event gaat naar allemaal.
Request
POST /webhooks/coinetic HTTP/1.1
Content-Type: application/json
User-Agent: cryptopay-webhooks/1
X-Webhook-Id: evt_3f9c…
X-Webhook-Timestamp: 1760000000
X-Webhook-Signature: v1=5d1e…
{"id":"evt_3f9c…","type":"invoice.paid","created_at":"2026-10-12T15:04:05Z","livemode":true,"data":{"invoice_id":"inv_x7k2…","order_id":"ORDER-1001","status":"paid","paid_amount":"49990000"}}X-Webhook-Id blijft gelijk bij retries. Tijdens de rotatie van een secret staan er in X-Webhook-Signature twee handtekeningen, gescheiden door een komma. De technische namen (cryptopay-webhooks/1) zijn historisch; u hoeft ze aan uw kant niet aan te passen.
De handtekening verifiëren
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))- Neem de ruwe body — de bytes vóór het parsen van de JSON.
- Controleer dat
X-Webhook-Timestampniet meer dan 5 minuten afwijkt van de huidige tijd. - Splits
X-Webhook-Signatureop de komma. De handtekening is geldig als een willekeurig deel overeenkomt met de verwachte waarde (vergelijken in constante tijd). - Geen overeenkomst — antwoord met
401en doe verder niets.
Referentie: secret whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, body {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.
Verwerking
handtekening verifiëren → dedupliceren op X-Webhook-Id → GET /v1/invoices/{invoice_id}
→ order bijwerken op basis van de status uit de API (precies één keer leveren) → antwoorden met 2xx- Deduplicatie. Hetzelfde event kan meerdere keren binnenkomen. Sla verwerkte
X-Webhook-Id's op; zet de vlag ‘geleverd’ in dezelfde transactie als de levering zelf. - Antwoord snel — binnen 10 seconden. Zet langdurig werk in een queue.
- Responscodes:
2xx— geaccepteerd;410 Gone— deze levering niet opnieuw proberen; elke andere code (ook3xx— redirects worden niet gevolgd) of een timeout — retry. - Negeer onbekende velden en eventtypes — de lijst wordt nog uitgebreid.
Kant-en-klare handlers in vier talen vindt u in de snelstart.
Retries
10 s → 30 s → 2 min → 10 min → 30 min → 1 u → 3 u ×7 → 1 u, met een kleine spreiding. De laatste poging volgt na ongeveer een etmaal. Een mislukte levering kunt u opnieuw versturen: dashboard → ‘Webhooks’ → ‘Opnieuw verzenden’.
Volgorde
Events van één factuur worden in volgorde aan het endpoint geleverd: het volgende gaat pas weg als de vorige levering niet meer op een retry wacht. Of die levering nu is geslaagd of niet — daarna gaan de volgende events. Baseer u daarom op de status uit GET /v1/invoices/{id}, niet op de volgorde van de events. Events van verschillende facturen zijn onafhankelijk van elkaar.
Eventtypes
| Event | Wanneer |
|---|---|
invoice.detected | De betaling is zichtbaar in het netwerk |
invoice.confirming | De betaling staat in een blok, de bevestigingen lopen |
invoice.paid | Betaald en bevestigd — u kunt leveren (na een extra controle). data.late: true — de stablecoin kwam na de vervaldatum binnen en is automatisch verrekend |
invoice.overpaid | Betaald met een overschot |
invoice.underpaid | Minder bevestigd dan nodig |
invoice.awaiting_payment | De factuur wacht weer op betaling (bijvoorbeeld na een reorg van de enige betaling) |
invoice.expired | De looptijd is verstreken zonder betaling |
invoice.late_payment | Betaling in een volatiele asset na de vervaldatum |
invoice.manual_review | De betaling wordt gecontroleerd op AML |
invoice.payment_held | De betaling is door AML vastgehouden (quarantaine) |
invoice.reorged | Het blok met de betaling is teruggedraaid, de status is herberekend (bijvoorbeeld paid → confirming) |
invoice.payment_after_close | Een betaling op een al gesloten factuur: die betaalt de order niet, maar kan worden terugbetaald |
invoice.cancelled | De factuur is zonder betaling gesloten door het uitvoeren van een terugbetaling |
refund.sent | De terugbetaling is uitgevoerd; in data.refund staan het bedrag, het adres en de tx_hash |
Facturerings-events (billing.*) gaan over de facturen voor de platformcommissie: uitgegeven, betaald, achterstallig, opschorting en het opheffen daarvan.
invoice.reorgedEen reorg na paid is zeldzaam, maar komt voor. Levert u het product direct, abonneer u dan op dit event en geef zulke gevallen door aan uw support.Rotatie van het secret
Dashboard → ‘Secret wijzigen’: Coinetic ondertekent vanaf dan met beide secrets.
- Zet het nieuwe secret op uw server (accepteer beide).
- Klik op ‘Rotatie voltooien’ — het oude wordt verwijderd.
- Verwijder het oude secret van uw server.