Webhooks
De NovaFisko-gebeurtenissen op uw server ontvangen, een eindpunt aanmaken en testen, de leveringspogingen begrijpen en het logboek raadplegen.
Een webhook is een HTTP-aanroep die NovaFisko naar uw server stuurt wanneer er een gebeurtenis plaatsvindt: een geïmporteerde factuur, een gevalideerde boeking, een gevalideerde btw-aangifte. U hoeft de API niet meer te bevragen om te weten of er iets nieuws is.
De webhooks worden ingesteld op het niveau van het kantoor en dekken al zijn dossiers. Alleen de beheerders en de managers van het kantoor kunnen ze beheren.
Werking
- U registreert een URL en kiest de gebeurtenissen die u wilt ontvangen.
- NovaFisko bezorgt u een ondertekeningsgeheim, één enkele keer.
- Bij elke gebeurtenis plaatst NovaFisko een levering in de wachtrij en stuurt daarna, uiterlijk binnen de minuut, een ondertekende
POST-request naar uw URL. - Uw server verifieert de handtekening en antwoordt met een status
2xxin minder dan 10 seconden. - Bij een mislukking probeert NovaFisko het opnieuw met een oplopende wachttijd.
Een eindpunt aanmaken
curl -X POST https://api.novafisko.com/v1/firms/Fd7hQ2mN8sXa/webhooks \
-H "Authorization: Bearer $NOVAFISKO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://erp.atelier.example/hooks/novafisko",
"description": "ERP Atelier, production",
"events": ["document.imported", "document.booked", "entry.posted"],
"is_active": true
}'
| Veld | Verplicht | Beschrijving |
|---|---|---|
url |
ja | Ontvangst-URL, max. 500 tekens. HTTPS verplicht in productie |
description |
nee | Vrije omschrijving, max. 190 tekens |
events |
ja | Lijst van gebeurtenissen, of ["*"] voor alle |
is_active |
nee | Standaard true |
Antwoord 201:
{
"webhook": {
"id": 14,
"url": "https://erp.atelier.example/hooks/novafisko",
"description": "ERP Atelier, production",
"events": ["document.imported", "document.booked", "entry.posted"],
"is_active": true,
"secret_hint": "whsec_…x9Qd",
"last_delivery_at": null,
"last_status": null,
"created_at": "2026-10-05T09:20:00+00:00",
"updated_at": "2026-10-05T09:20:00+00:00"
},
"secret": "whsec_Zp3kV8nQ1bT6yR0mW4sH7cJ2dL9fA5gE1uXox9Qd"
}
Het secret wordt alleen bij het aanmaken teruggegeven. Sla het onmiddellijk op in uw secrets manager. De volgende leesbewerkingen tonen alleen secret_hint, de laatste vier tekens ervan.
Beperkingen voor de URL
- Het schema moet
httpszijn. - De URL mag geen inloggegevens bevatten (
https://user:pass@...). - De host mag niet
localhostzijn, niet eindigen op.localof.internalen niet naar een privé-, loopback- of gereserveerd adres verwijzen. - Omleidingen worden niet gevolgd.
Een geweigerde URL antwoordt 422 met de code webhook_url_refused. Een kantoor kan maximaal 20 eindpunten registreren (webhook_limit_reached).
De eindpunten beheren
| Actie | Request | Antwoord |
|---|---|---|
| Oplijsten | GET /v1/firms/{firm}/webhooks |
{"data": [...]} |
| Wijzigen | PATCH /v1/firms/{firm}/webhooks/{id} |
{"webhook": {...}} |
| Verwijderen | DELETE /v1/firms/{firm}/webhooks/{id} |
204 |
| Testen | POST /v1/firms/{firm}/webhooks/{id}/test |
202 en de levering |
| Logboek | GET /v1/firms/{firm}/webhooks/{id}/deliveries |
Gepagineerde lijst |
| Catalogus | GET /v1/webhooks/events |
Lijst van de gebeurtenissen en beschrijvingen |
Een eindpunt pauzeren zonder het te verwijderen:
curl -X PATCH https://api.novafisko.com/v1/firms/Fd7hQ2mN8sXa/webhooks/14 \
-H "Authorization: Bearer $NOVAFISKO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_active": false}'
Een gebruiker die lid is van het kantoor maar de vereiste rol niet heeft, krijgt 403. Een gebruiker van buiten het kantoor krijgt 404.
De ontvangen request
POST /hooks/novafisko HTTP/1.1
Host: erp.atelier.example
Content-Type: application/json
User-Agent: NovaFisko-Webhooks/1.0
X-Novafisko-Event: entry.posted
X-Novafisko-Delivery: 90412
X-Novafisko-Signature: t=1791191400,v1=5f2b8c1e0a7d4f6b9c3e2a1d8f7b6c5a4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b
{"id":"evt_01jb6z3m8q2v7k4n5p9r0s1t2w","event":"entry.posted","api_version":"v1","created_at":"2026-10-05T09:23:20Z","firm":{"public_token":"Fd7hQ2mN8sXa","name":"Fiduciaire Exemple"},"company":{"public_token":"k3Jd9fPq2LmX","name":"Le Comptoir Montois SRL"},"data":{"id":1842,"reference":"ACH 2026/000212"}}
| Header | Inhoud |
|---|---|
X-Novafisko-Signature |
Tijdstempel en HMAC-SHA256-handtekening. Zie Handtekeningen verifiëren |
X-Novafisko-Event |
Naam van de gebeurtenis |
X-Novafisko-Delivery |
Identificator van de levering, identiek bij elke poging |
User-Agent |
NovaFisko-Webhooks/1.0 |
Envelop
Alle gebeurtenissen delen dezelfde envelop.
| Veld | Beschrijving |
|---|---|
id |
Unieke identificator van de gebeurtenis, met het prefix evt_. Gebruik hem om te ontdubbelen |
event |
Naam van de gebeurtenis |
api_version |
v1 |
created_at |
Datum van de gebeurtenis, ISO 8601 in UTC |
firm |
public_token en naam van het kantoor |
company |
public_token en naam van het dossier, of null voor een kantoorgebeurtenis |
data |
Inhoud eigen aan de gebeurtenis |
Gebeurtenissen
| Gebeurtenis | Trigger |
|---|---|
document.imported |
Een document komt in het dossier binnen (importmodule, Novadesko, Peppol) |
document.booked |
Een document wordt geboekt |
entry.posted |
Een boeking wordt gevalideerd |
entry.reversed |
Een boeking wordt tegengeboekt |
bank.transaction_imported |
Een bankverrichting wordt geïmporteerd |
vat.declaration_validated |
Een btw-aangifte wordt gevalideerd |
fiscal_year.closed |
Een boekjaar wordt afgesloten |
peppol.status_changed |
De Peppol-status van het dossier verandert |
third_party.created |
Een derde wordt aangemaakt |
third_party.updated |
Een derde wordt gewijzigd |
webhook.test |
Testverzending, op aanvraag |
De onderstaande voorbeelden tonen het veld data van elke gebeurtenis. De envelop is weggelaten.
document.imported en document.booked
{
"id": 7741,
"source": "novafisko",
"origin": "novafisko",
"type": "purchases",
"direction": "purchase",
"is_credit_note": false,
"number": "F-2026-0918",
"document_date": "2026-10-02",
"due_date": "2026-11-01",
"third_party_id": 41,
"third_party_name": "Brasserie des Collines SA",
"third_party_vat": "BE0999900134",
"currency": "EUR",
"amount_net": "1250.00",
"amount_vat": "262.50",
"amount_gross": "1512.50",
"status": "pending",
"journal_entry_id": null
}
Voor document.booked heeft status de waarde booked en bevat journal_entry_id de identificator van de boeking.
entry.posted en entry.reversed
{
"id": 1842,
"reference": "ACH 2026/000212",
"journal_code": "ACH",
"fiscal_year_code": "2026",
"number": 212,
"entry_date": "2026-10-02",
"due_date": "2026-11-01",
"label": "Brasserie des Collines SA",
"document_reference": "F-2026-0918",
"status": "posted",
"origin": "manual",
"third_party_id": 41,
"total_debit": "1512.50",
"total_credit": "1512.50",
"lines_count": 3,
"reversed_entry_id": null,
"reversed_by_entry_id": null
}
Voor entry.reversed heeft de gebeurtenis betrekking op de oorspronkelijke boeking: status heeft de waarde reversed en reversed_by_entry_id verwijst naar de tegenboeking. De tegenboeking zelf veroorzaakt haar eigen entry.posted, met reversed_entry_id ingevuld. De lijnen zijn niet inbegrepen: lees ze met GET entries/{id}.
bank.transaction_imported
{
"id": 30418,
"source": "novadesko",
"account_iban": "BE68539007547034",
"value_date": "2026-10-03",
"amount": "-1512.50",
"currency": "EUR",
"counterpart_name": "Brasserie des Collines SA",
"counterpart_iban": "BE71096123456769",
"communication": "+++091/8202/60018+++",
"status": "pending"
}
vat.declaration_validated
{
"id": 88,
"period_type": "quarterly",
"year": 2026,
"period": 3,
"label": "3T 2026",
"starts_on": "2026-07-01",
"ends_on": "2026-09-30",
"amount_due": "4218.36",
"amount_refund": "0.00",
"status": "validated",
"validated_at": "2026-10-05T09:31:02+00:00",
"journal_entry_id": 1860
}
fiscal_year.closed
{
"id": 6,
"code": "2025",
"starts_on": "2025-01-01",
"ends_on": "2025-12-31",
"closed_at": "2026-03-14T10:22:05+00:00"
}
peppol.status_changed
{
"id": 57,
"participant_id": "0208:0999900134",
"full_id": "iso6523-actorid-upis::0208:0999900134",
"status": "active",
"previous_status": "pending",
"incoming_enabled": true,
"activated_at": "2026-10-05T09:02:11+00:00"
}
previous_status heeft de waarde null bij de eerste registratie.
third_party.created en third_party.updated
{
"id": 215,
"type": "supplier",
"code": "MARBOR",
"name": "Maraîchers du Borinage SC",
"vat_number": "BE0999900233",
"enterprise_number": "0999.900.233",
"country": "BE",
"email": "info@maraichers-borinage.example",
"peppol_identifier": "0208:0999900233",
"peppol_registered": true,
"changed": ["email", "phone"]
}
Het veld changed, dat alleen aanwezig is voor third_party.updated, somt de gewijzigde velden op. De technische controles (VIES, Peppol) veroorzaken op zich geen gebeurtenis.
webhook.test
{
"message": "Test event sent from NovaFisko.",
"webhook_id": 14
}
Voor deze gebeurtenis heeft company de waarde null.
Pogingen en wachttijden
Uw server moet met een status 2xx antwoorden in minder dan 10 seconden. Elk ander antwoord, een time-out of een verbindingsfout telt als een mislukking.
| Poging | Wachttijd na de vorige mislukking |
|---|---|
| 1 | Onmiddellijk, binnen de minuut na de gebeurtenis |
| 2 | 1 minuut |
| 3 | 2 minuten |
| 4 | 4 minuten |
| 5 | 8 minuten |
| 6 | 16 minuten |
| 7 | 32 minuten |
| 8 | 64 minuten |
Na de achtste poging, dus iets meer dan twee uur, krijgt de levering de status failed en wordt ze niet meer opnieuw geprobeerd. Een eindpunt dat faalt, wordt niet automatisch uitgeschakeld: houd last_status in het oog.
De leveringen vertrekken vanuit een verwerking die elke minuut is ingepland. Een gebeurtenis komt dus aan met een vertraging van enkele seconden tot een minuut. De leveringen van een gepauzeerd eindpunt blijven in de wachtrij en vertrekken zodra het opnieuw wordt geactiveerd.
Testen
curl -X POST https://api.novafisko.com/v1/firms/Fd7hQ2mN8sXa/webhooks/14/test \
-H "Authorization: Bearer $NOVAFISKO_TOKEN"
De gebeurtenis webhook.test wordt onmiddellijk verstuurd, zonder nieuwe poging bij een mislukking. Het antwoord is altijd 202 en bevat de levering met de verkregen status, delivered of failed. De route is beperkt tot 12 tests per minuut.
{
"delivery": {
"id": 90455,
"event_id": "evt_01jb6zb1t4c8h2m6q0x3y7z9a5",
"event": "webhook.test",
"status": "delivered",
"attempts": 1,
"next_attempt_at": null,
"response_status": 200,
"response_excerpt": "ok",
"duration_ms": 184,
"delivered_at": "2026-10-05T09:40:12+00:00",
"created_at": "2026-10-05T09:40:12+00:00",
"payload": {"id": "evt_01jb6zb1t4c8h2m6q0x3y7z9a5", "event": "webhook.test", "api_version": "v1", "created_at": "2026-10-05T09:40:12Z", "firm": {"public_token": "Fd7hQ2mN8sXa", "name": "Fiduciaire Exemple"}, "company": null, "data": {"message": "Test event sent from NovaFisko.", "webhook_id": 14}}
}
}
Leveringslogboek
curl "https://api.novafisko.com/v1/firms/Fd7hQ2mN8sXa/webhooks/14/deliveries?status=failed&per_page=25" \
-H "Authorization: Bearer $NOVAFISKO_TOKEN"
| Parameter | Beschrijving |
|---|---|
status |
pending, delivered of failed |
event |
Naam van een gebeurtenis |
per_page |
Standaard 25, maximaal 100 |
page |
Paginanummer |
{
"data": [
{
"id": 90412,
"event_id": "evt_01jb6z3m8q2v7k4n5p9r0s1t2w",
"event": "entry.posted",
"status": "failed",
"attempts": 8,
"next_attempt_at": null,
"response_status": 500,
"response_excerpt": "Internal Server Error",
"duration_ms": 412,
"delivered_at": null,
"created_at": "2026-10-05T09:23:20+00:00",
"payload": {"id": "evt_01jb6z3m8q2v7k4n5p9r0s1t2w", "event": "entry.posted"}
}
],
"meta": {"current_page": 1, "last_page": 1, "per_page": 25, "total": 1}
}
response_excerpt bevat de eerste 2000 tekens van het antwoord van uw server, of de foutmelding van de verbinding. payload is de exacte body die is verstuurd: u kunt hem zelf opnieuw afspelen nadat u een storing hebt verholpen. De afgeronde leveringen (delivered of failed) worden 30 dagen bewaard.
Goede praktijken
- Verifieer altijd de handtekening voordat u iets verwerkt. Zie Handtekeningen verifiëren.
- Antwoord snel. Bevestig de ontvangst met een
200, plaats de gebeurtenis in een wachtrij en verwerk ze daarna. Een lange verwerking veroorzaakt time-outs en dubbels. - Ontdubbel op
id. Eenzelfde levering kan u meerdere keren bereiken als uw antwoord verloren is gegaan. Bewaar deid's van de gebeurtenissen die al zijn verwerkt. - Ga niet uit van een volgorde. Twee gebeurtenissen kort na elkaar kunnen in een andere volgorde aankomen, vooral na een nieuwe poging. Steun op
created_aten lees de resource opnieuw bij twijfel. - Behandel de gebeurtenis als een signaal. De inhoud van
datais een samenvatting. Roep de API aan voor de volledige en actuele toestand. - Negeer onbekende gebeurtenissen. Er kunnen nieuwe gebeurtenissen en nieuwe velden verschijnen zonder versiewijziging. Antwoord
200op wat u niet kent. - Houd rekening met pieken. Een massa-import (CODA-afschrift, Novadesko-synchronisatie) levert één levering op per document of per verrichting.
- Combineer met
sync/pull. Gebruik de webhook als trigger en de wijzigingsstroom als bron van waarheid. Zie Continu synchroniseren.
Het demokantoor verstuurt geen enkele webhook en het beheer van de eindpunten is er geblokkeerd (403, code demo_mode).