Bijgewerkt op 29 oktober 2026
Wat kun je koppelen?
Met de API en webhooks wisselt andere software rechtstreeks gegevens uit met SimplyFact Cloud, bijvoorbeeld een webshop, kassasysteem, planningstool of het programma van je boekhouder. Alles draait op de eigen servers van SimplyFact, zonder tussenpartij.
| API | Webhooks | |
|---|---|---|
| Wat is het? | De andere software vraagt zelf gegevens op of stuurt ze door. | SimplyFact meldt het zelf meteen als er iets gebeurt. |
| Richting | Software → SimplyFact | SimplyFact → software |
| Voorbeeld | Elke nacht alle nieuwe facturen en betalingen ophalen. | Een seintje zodra een factuur definitief is of betaald werd. |
| Wat heb je nodig? | Een API-sleutel | Een https-ontvangstadres en het bijbehorende geheim |
De twee werken het best samen. Een webhook bevat alleen verwijzingen en bedragen. De volledige factuur, PDF of UBL haalt de software daarna op via de API.
Via de API worden facturen nooit definitief gemaakt of verstuurd. De API kan wel concepten aanmaken. Definitief maken en verzenden blijft een bewuste stap in SimplyFact.
Voor boekhouders
- Een API-sleutel geldt voor precies één administratie. Werk je voor meerdere klanten, dan maakt elke klant een eigen sleutel voor je aan. Zo blijft elke klant zelf baas over de toegang.
- Voor de boekhouding volstaan meestal leesrechten: Bedrijfsgegevens lezen, Facturen en creditnota’s lezen, Betalingen lezen en Aankoopfacturen lezen.
- Combineer met webhooks voor Factuur of creditnota definitief, Betaling geregistreerd en Aankoopfactuur ontvangen. Dan hoeft je software niet steeds opnieuw te vragen of er iets nieuws is.
- Elke factuur is via de API beschikbaar als PDF en als UBL 2.1 (EN 16931). De meeste Belgische boekhoudpakketten lezen UBL rechtstreeks in.
- Geen ontwikkelaar beschikbaar? Gebruik dan de gratis boekhouderstoegang en het exportpakket in SimplyFact (ZIP met PDF’s, UBL, dagboeken in Excel/CSV en btw-overzicht). Daarvoor hoef je niets te programmeren.
Een API-sleutel aanmaken
- Meld je aan als bedrijfsbeheerder van de administratie die je wilt koppelen. Open Bedrijfsinstellingen en kies het tabblad API en webhooks.
- Klik API-sleutel aanmaken. Geef de sleutel een herkenbare naam, zoals de naam van de software of van je boekhoudkantoor.
- Vink alleen de rechten aan die de software echt nodig heeft (zie Welke rechten kies je?). Kies bij voorkeur een vervaldatum.
- Klik Sleutel aanmaken. De sleutel (begint met sfk_) is maar één keer zichtbaar. Kopieer hem en geef hem langs een veilige weg aan wie de koppeling bouwt, bijvoorbeeld via een wachtwoordbeheerder. Mail hem niet zonder versleuteling.
- In hetzelfde scherm zie je wanneer een sleutel voor het laatst gebruikt werd. Stopt de samenwerking of lekte de sleutel uit? Klik Intrekken: de toegang stopt onmiddellijk.
Welke rechten kies je?
Een sleutel kan nooit meer dan de rechten die je aanvinkt, wat de maker van de sleutel zelf ook mag. Instellingen, gebruikers, wachtwoorden of koppelingsgegevens zijn via de API nooit bereikbaar.
| Recht | Technische naam | Geeft toegang tot |
|---|---|---|
| Bedrijfsgegevens lezen | company:read | GET /company |
| Klanten lezen | customers:read | GET /customers, GET /customers/{id} |
| Klanten aanmaken en wijzigen | customers:write | POST /customers, PUT /customers/{id} |
| Producten lezen | products:read | GET /products, GET /products/{id} |
| Producten aanmaken en wijzigen | products:write | POST /products, PUT /products/{id} |
| Facturen en creditnota’s lezen (incl. PDF/UBL) | documents:read | GET /documents, GET /documents/{id}, GET /documents/{id}/pdf, GET /documents/{id}/ubl |
| Conceptfacturen aanmaken | drafts:write | POST /drafts |
| Betalingen lezen | payments:read | GET /payments |
| Aankoopfacturen lezen | incoming:read | GET /incoming-invoices |
Een webhook instellen
- Vraag aan wie de koppeling bouwt een https-adres dat de berichten ontvangt.
- Klik in API en webhooks op Webhook toevoegen. Vul het adres in en vink de gebeurtenissen aan die je wilt doorsturen.
- Klik Webhook aanmaken. Het geheim (begint met whsec_) is maar één keer zichtbaar. Geef het op een veilige manier aan de ontwikkelaar: daarmee controleert die dat een bericht echt van SimplyFact komt.
- Klik Testbericht. Onder Recente leveringen zie je binnen ongeveer een halve minuut of het ontvangstadres het bericht aanvaard heeft.
- Met Pauzeren zet je de webhook tijdelijk stil, met Verwijderen definitief.
| Gebeurtenis | Technische naam | Wanneer? |
|---|---|---|
| Factuur, creditnota of offerte definitief | document.finalized | Een verkoopfactuur, creditnota of offerte is definitief gemaakt: met de hand of automatisch door een periodieke factuur. Haal het volledige document op met GET /documents/{documentId}. |
| Betaling geregistreerd | payment.registered | Een betaling op een verkoopfactuur is geregistreerd: met de hand of door een bankboeking te koppelen. Een herhaalde aanvraag met dezelfde Idempotency-Key geeft geen tweede bericht. |
| Aankoopfactuur ontvangen | incoming.received | Er is een nieuwe aankoopfactuur binnengekomen. Een dubbel ontvangen factuur geeft geen tweede bericht. |
| Testbericht | ping | Wordt alleen verstuurd als je in de instellingen op Testbericht klikt, ook als de webhook gepauzeerd is. Kan niet als gebeurtenis aangevinkt worden. |
Betalingen op aankoopfacturen geven nog geen webhook. Die haal je op via GET /payments.
Veiligheid en privacy
- SimplyFact bewaart van een API-sleutel alleen een onomkeerbare hash en van een webhookgeheim alleen een versleutelde kopie. Kwijt? Maak een nieuwe aan en trek de oude in.
- Elke aanvraag en elke wijziging via de API komt in het auditlog, op naam van de sleutel.
- Webhookberichten bevatten geen PDF- of UBL-inhoud en geen adresgegevens, alleen id’s, nummers, datums en bedragen.
- Webhooks gaan alleen naar openbare https-adressen. Interne netwerkadressen worden geweigerd en omleidingen niet gevolgd.
- In de demo zijn de API en webhooks uitgeschakeld.
Technische referentie: basis
Voor ontwikkelaars
| Onderdeel | Waarde |
|---|---|
| Basisadres | https://app.simplyfact.eu/api/v1 |
| OpenAPI 3.1 (JSON) | https://app.simplyfact.eu/api/v1/openapi.json |
| OpenAPI 3.1 (YAML) | https://app.simplyfact.eu/api/v1/openapi.yaml |
| Authenticatie | Header Authorization: Bearer sfk_… |
| Formaat | JSON in UTF-8 (Content-Type: application/json), body maximaal 1 MB. Onbekende velden worden geweigerd. |
| Bedragen | Bedragen, hoeveelheden en percentages zijn tekst met een punt als decimaalteken, bijvoorbeeld "822.80", zodat er nooit afrondingsfouten ontstaan. Lees ze in als decimaal getal, niet als float. |
| Datums | Datums als JJJJ-MM-DD; tijdstippen als ISO 8601 in UTC, bijvoorbeeld 2026-11-02T09:14:03.120Z. |
| Id’s | Alle id’s zijn UUID’s als tekst. Ze veranderen nooit. |
| Browsers | Geen cookies en geen CORS: roep de API vanaf een server aan, nooit vanuit een webpagina. Zo blijft de sleutel geheim. |
| Limiet | 120 aanvragen per minuut per sleutel. |
De OpenAPI-beschrijving bevat alle eindpunten, velden, voorbeelden en webhooks uit deze gids. Importeer openapi.yaml of openapi.json in Postman, Insomnia, Swagger Editor of een codegenerator om meteen aanvragen te kunnen doen.
curl "https://app.simplyfact.eu/api/v1/company" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"| Antwoordheader | Betekenis |
|---|---|
| X-RateLimit-Remaining | Hoeveel aanvragen je in deze minuut nog mag doen. |
| X-RateLimit-Reset | Aantal seconden tot de teller opnieuw begint. |
| Retry-After | Alleen bij 429: aantal seconden dat je moet wachten. |
| Idempotent-Replayed | true als je een eerder bewaard antwoord terugkrijgt (zie Idempotentie). |
| Content-Disposition | Bij PDF en UBL: de voorgestelde bestandsnaam, bijvoorbeeld F-2026-0042.pdf. |
| Cache-Control | Altijd no-store: antwoorden worden nergens tussentijds bewaard. |
Paginering: lijsten geven { "data": [...], "nextCursor": "…" }. Vraag de volgende pagina op met ?cursor=<nextCursor> (met dezelfde filters) tot nextCursor null is. limit kiest de paginagrootte, van 1 tot 100 (standaard 50).
cursor=""
while : ; do
page=$(curl -s "https://app.simplyfact.eu/api/v1/documents?kind=invoice&from=2026-11-01&to=2026-11-30&limit=100&cursor=$cursor" \
-H "Authorization: Bearer $SIMPLYFACT_KEY")
echo "$page" | jq -c '.data[]'
cursor=$(echo "$page" | jq -r '.nextCursor // empty')
[ -z "$cursor" ] && break
doneIdempotentie: stuur bij POST en PUT een Idempotency-Key van 8 tot 100 tekens (letters, cijfers en _ . : -), bijvoorbeeld je eigen ordernummer. Herhaal je dezelfde aanvraag met dezelfde sleutel binnen 24 uur, bijvoorbeeld na een time-out, dan krijg je het eerste antwoord terug met Idempotent-Replayed: true en wordt er niets dubbel aangemaakt. Dezelfde sleutel met een andere body wordt geweigerd (422).
Fouten volgen RFC 9457 en hebben Content-Type application/problem+json. Bij een validatiefout (422) staat in detail per veld wat er mis is, in de vorm pad: melding, gescheiden door een puntkomma. Welke status elk eindpunt kan geven, staat bij het eindpunt.
De onderstaande statuscodes gelden algemeen. Bij elk eindpunt staan de succescode en alleen de specifieke fouten. Codes voor een JSON-body gelden alleen bij POST en PUT.
| Status | Betekenis |
|---|---|
| 400 | Bij POST en PUT: Body is geen geldige JSON, of de Idempotency-Key heeft een ongeldig formaat. |
| 401 | Geen, een ongeldige, verlopen of ingetrokken API-sleutel. |
| 403 | De sleutel mist het vereiste recht dat bij het eindpunt staat. |
| 413 | Bij POST en PUT: Body groter dan 1 MB. |
| 415 | Bij POST en PUT: Content-Type is niet application/json. |
| 429 | Meer dan de toegestane aanvragen per minuut; wacht het aantal seconden uit Retry-After. |
| 500 | Onverwachte fout aan de kant van SimplyFact. Probeer later opnieuw. |
| Veld | Type | Uitleg |
|---|---|---|
type | tekst | Altijd about:blank. |
title | tekst | Korte omschrijving van de fout. |
status | geheel getal | HTTP-status. |
detail | tekst | Uitleg. Bij validatiefouten per veld: pad: melding, gescheiden door ; |
{
"type": "about:blank",
"title": "Onvoldoende rechten",
"status": 403,
"detail": "Deze API-sleutel mist het recht \"payments:read\" (Betalingen lezen)."
}{
"type": "about:blank",
"title": "Ongeldige gegevens",
"status": 422,
"detail": "vat: Controleer het Belgische btw-nummer en controlegetal.; lines.0.quantity: Gebruik een niet-negatief getal met maximaal zes decimalen."
}- 401, 403, 404, 409 en 422: herhaal de aanvraag niet ongewijzigd, maar los eerst de oorzaak op.
- 429, 500 of geen antwoord: probeer later opnieuw met dezelfde Idempotency-Key. Wacht bij 429 minstens Retry-After seconden.
Technische referentie: eindpunten
Voor ontwikkelaars
Per eindpunt: wat het doet, welk recht nodig is, de parameters, alle velden van de aanvraag en het antwoord, een volledig voorbeeld en de mogelijke statuscodes. Paden zijn relatief ten opzichte van het basisadres.
| Methode | Pad | Wat | Recht |
|---|---|---|---|
| GET | /company | Bedrijfsgegevens opvragen | company:read |
| GET | /customers | Klanten opvragen | customers:read |
| POST | /customers | Klant aanmaken | customers:write |
| GET | /customers/{id} | Eén klant opvragen | customers:read |
| PUT | /customers/{id} | Klant vervangen | customers:write |
| GET | /products | Producten opvragen | products:read |
| POST | /products | Product aanmaken | products:write |
| GET | /products/{id} | Eén product opvragen | products:read |
| PUT | /products/{id} | Product vervangen | products:write |
| GET | /documents | Definitieve documenten opvragen | documents:read |
| GET | /documents/{id} | Eén document met regels opvragen | documents:read |
| GET | /documents/{id}/pdf | PDF downloaden | documents:read |
| GET | /documents/{id}/ubl | UBL downloaden | documents:read |
| POST | /drafts | Concept aanmaken | drafts:write |
| GET | /payments | Betalingen opvragen | payments:read |
| GET | /incoming-invoices | Aankoopfacturen opvragen | incoming:read |
/companycompany:readBedrijfsgegevens opvragen
Gegevens van de administratie waar de sleutel bij hoort. Handig om na het instellen te controleren of je met de juiste administratie verbonden bent.
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/company" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"id": "e4c1b2a3-0f9e-4d8c-b7a6-123456789abc",
"name": "Voorbeeld Diensten BV",
"vat": "BE0000000097",
"peppolId": "0208:0000000097",
"email": "facturen@voorbeeld.invalid",
"street": "Voorbeeldlaan",
"houseNumber": "1",
"postcode": "9000",
"city": "Gent",
"country": "BE",
"currency": "EUR"
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Id van de administratie. |
name | tekst | Naam van het bedrijf. |
vat | tekst | Btw-nummer. |
peppolId | tekst | Peppol-adres, of leeg. |
email | tekst | E-mailadres van het bedrijf. |
street | tekst | Straat. |
houseNumber | tekst | Huisnummer. |
postcode | tekst | Postcode. |
city | tekst | Gemeente. |
country | tekst | Landcode, bijvoorbeeld BE. |
currency | tekst | Standaardmunt, bijvoorbeeld EUR. |
Succescode: 200. Algemene statuscodes en fouten.
/customerscustomers:readKlanten opvragen
Alle klanten van de administratie, per pagina.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
limit | query | geheel getal | nee | Aantal resultaten per pagina, 1 tot 100 (standaard 50). |
cursor | query | tekst | nee | nextCursor uit het vorige antwoord, voor de volgende pagina. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/customers" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"data": [
{
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": "",
"addressBox": ""
}
],
"nextCursor": "NTA"
}Antwoord
Een pagina: data is een lijst met de velden hieronder, nextCursor is de cursor voor de volgende pagina of null.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van de klant. |
name | tekst | Naam van de klant. |
kind | tekst | business = onderneming, person = particulier. Eén van: business, person |
vat | tekst | Btw-nummer zonder spaties of punten, of leeg. |
peppolId | tekst | Peppol-adres, of leeg. |
email | tekst | E-mailadres voor facturen, of leeg. |
phone | tekst | Telefoonnummer, of leeg. |
street | tekst | Straat. |
houseNumber | tekst | Huisnummer. |
addressBox | tekst | Busnummer. |
postcode | tekst | Postcode. |
city | tekst | Gemeente. |
country | tekst | Landcode. |
language | tekst | Taal van documenten. Eén van: nl, fr, en |
paymentDays | geheel getal | Betaaltermijn in dagen. |
contact | tekst | Contactpersoon, of leeg. |
note | tekst | Interne notitie, of leeg. |
Succescode: 200. Algemene statuscodes en fouten.
/customerscustomers:writeKlant aanmaken
Maakt een nieuwe klant aan. Het antwoord bevat de klant met zijn nieuwe id. Standaardkorting, betaalwijze en btw-uitzondering worden bewaard maar niet teruggegeven.
Aanvraag
Body als JSON. Velden die niet verplicht zijn mag je weglaten; dan geldt de standaardwaarde. Andere velden worden geweigerd.
| Veld | Type | Verplicht | Regels en uitleg |
|---|---|---|---|
name | tekst | ja | Naam van de klant: bedrijfsnaam of voor- en achternaam. 2–150 tekens |
kind | keuze | ja | business = onderneming, person = particulier. Een klant met btw-nummer is altijd een onderneming. Eén van: business, person |
country | keuze | ja | Land van het factuuradres als ISO-landcode. Eén van: AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK |
vat | tekst | ja | Btw-nummer met landcode, bijvoorbeeld BE0000000097; spaties en punten mogen. Bij een Belgische onderneming wordt het controlegetal gecontroleerd. Leeg voor particulieren. Een tweede klant met hetzelfde btw-nummer geeft 409. max. 30 tekens |
email | e-mailadres of leeg | ja | E-mailadres waar facturen naartoe gaan. |
phone | tekst | ja | Telefoonnummer. max. 40 tekens |
street | tekst | ja | Straat, zonder huisnummer. max. 180 tekens |
postcode | tekst | ja | Postcode. max. 12 tekens |
city | tekst | ja | Gemeente of stad. max. 100 tekens |
houseNumber | tekst | nee | Huisnummer. max. 20 tekens · standaard: "" |
addressBox | tekst | nee | Busnummer. max. 20 tekens · standaard: "" |
contact | tekst | ja | Naam van de contactpersoon. max. 120 tekens |
language | keuze | ja | Taal van documenten en e-mails voor deze klant. Eén van: nl, fr, en |
paymentDays | geheel getal | ja | Betaaltermijn in dagen. Bepaalt de vervaldatum als een factuur geen eigen vervaldatum heeft. 0–120 |
peppolId | tekst | ja | Peppol-adres als schema:nummer, bijvoorbeeld 0208:0000000097 (0208 = Belgisch ondernemingsnummer). Verplicht voor een Belgische onderneming met btw-nummer en moet dan bij dat btw-nummer horen. Anders leeg of een geldig Peppol-adres. max. 80 tekens |
note | tekst | ja | Interne notitie bij de klant. max. 1500 tekens |
discountPercent | tekst of leeg | nee | Standaardkorting voor deze klant. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
paymentMethod | keuze of leeg | nee | Standaard betaalwijze: bank-transfer = overschrijving, cash = contant, card = betaalkaart. Eén van: bank-transfer, cash, card |
taxExempt | true/false | nee | true als documenten voor deze klant standaard onder een btw-uitzondering vallen. |
taxExemptionCategory | keuze | nee | Btw-categorie van die uitzondering: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Eén van: S, Z, E, AE, K, G, O |
taxExemptionReason | tekst | nee | Wettelijke vermelding op het document bij die uitzondering. max. 500 tekens |
Voorbeeld
curl -X POST "https://app.simplyfact.eu/api/v1/customers" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: customers-create-0001" \
-d '{
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": ""
}'{
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": "",
"addressBox": ""
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van de klant. |
name | tekst | Naam van de klant. |
kind | tekst | business = onderneming, person = particulier. Eén van: business, person |
vat | tekst | Btw-nummer zonder spaties of punten, of leeg. |
peppolId | tekst | Peppol-adres, of leeg. |
email | tekst | E-mailadres voor facturen, of leeg. |
phone | tekst | Telefoonnummer, of leeg. |
street | tekst | Straat. |
houseNumber | tekst | Huisnummer. |
addressBox | tekst | Busnummer. |
postcode | tekst | Postcode. |
city | tekst | Gemeente. |
country | tekst | Landcode. |
language | tekst | Taal van documenten. Eén van: nl, fr, en |
paymentDays | geheel getal | Betaaltermijn in dagen. |
contact | tekst | Contactpersoon, of leeg. |
note | tekst | Interne notitie, of leeg. |
Succescode: 201. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 409 | Er bestaat al een klant met dit btw-nummer. |
| 422 | Validatiefout, bijvoorbeeld een ongeldig btw-nummer of Peppol-adres die niet bij elkaar horen. Of: Dezelfde Idempotency-Key werd al gebruikt voor een andere aanvraag. |
/customers/{id}customers:readEén klant opvragen
Eén klant op basis van zijn id.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van de klant. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/customers/7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": "",
"addressBox": ""
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van de klant. |
name | tekst | Naam van de klant. |
kind | tekst | business = onderneming, person = particulier. Eén van: business, person |
vat | tekst | Btw-nummer zonder spaties of punten, of leeg. |
peppolId | tekst | Peppol-adres, of leeg. |
email | tekst | E-mailadres voor facturen, of leeg. |
phone | tekst | Telefoonnummer, of leeg. |
street | tekst | Straat. |
houseNumber | tekst | Huisnummer. |
addressBox | tekst | Busnummer. |
postcode | tekst | Postcode. |
city | tekst | Gemeente. |
country | tekst | Landcode. |
language | tekst | Taal van documenten. Eén van: nl, fr, en |
paymentDays | geheel getal | Betaaltermijn in dagen. |
contact | tekst | Contactpersoon, of leeg. |
note | tekst | Interne notitie, of leeg. |
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Klant niet gevonden in deze administratie. |
/customers/{id}customers:writeKlant vervangen
Vervangt alle gegevens van een bestaande klant. Stuur altijd de volledige klant mee: velden die je weglaat krijgen hun standaardwaarde. De id blijft gelijk; bestaande documenten behouden de klantgegevens van toen.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van de klant. |
Aanvraag
Body als JSON. Velden die niet verplicht zijn mag je weglaten; dan geldt de standaardwaarde. Andere velden worden geweigerd.
| Veld | Type | Verplicht | Regels en uitleg |
|---|---|---|---|
name | tekst | ja | Naam van de klant: bedrijfsnaam of voor- en achternaam. 2–150 tekens |
kind | keuze | ja | business = onderneming, person = particulier. Een klant met btw-nummer is altijd een onderneming. Eén van: business, person |
country | keuze | ja | Land van het factuuradres als ISO-landcode. Eén van: AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK |
vat | tekst | ja | Btw-nummer met landcode, bijvoorbeeld BE0000000097; spaties en punten mogen. Bij een Belgische onderneming wordt het controlegetal gecontroleerd. Leeg voor particulieren. Een tweede klant met hetzelfde btw-nummer geeft 409. max. 30 tekens |
email | e-mailadres of leeg | ja | E-mailadres waar facturen naartoe gaan. |
phone | tekst | ja | Telefoonnummer. max. 40 tekens |
street | tekst | ja | Straat, zonder huisnummer. max. 180 tekens |
postcode | tekst | ja | Postcode. max. 12 tekens |
city | tekst | ja | Gemeente of stad. max. 100 tekens |
houseNumber | tekst | nee | Huisnummer. max. 20 tekens · standaard: "" |
addressBox | tekst | nee | Busnummer. max. 20 tekens · standaard: "" |
contact | tekst | ja | Naam van de contactpersoon. max. 120 tekens |
language | keuze | ja | Taal van documenten en e-mails voor deze klant. Eén van: nl, fr, en |
paymentDays | geheel getal | ja | Betaaltermijn in dagen. Bepaalt de vervaldatum als een factuur geen eigen vervaldatum heeft. 0–120 |
peppolId | tekst | ja | Peppol-adres als schema:nummer, bijvoorbeeld 0208:0000000097 (0208 = Belgisch ondernemingsnummer). Verplicht voor een Belgische onderneming met btw-nummer en moet dan bij dat btw-nummer horen. Anders leeg of een geldig Peppol-adres. max. 80 tekens |
note | tekst | ja | Interne notitie bij de klant. max. 1500 tekens |
discountPercent | tekst of leeg | nee | Standaardkorting voor deze klant. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
paymentMethod | keuze of leeg | nee | Standaard betaalwijze: bank-transfer = overschrijving, cash = contant, card = betaalkaart. Eén van: bank-transfer, cash, card |
taxExempt | true/false | nee | true als documenten voor deze klant standaard onder een btw-uitzondering vallen. |
taxExemptionCategory | keuze | nee | Btw-categorie van die uitzondering: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Eén van: S, Z, E, AE, K, G, O |
taxExemptionReason | tekst | nee | Wettelijke vermelding op het document bij die uitzondering. max. 500 tekens |
Voorbeeld
curl -X PUT "https://app.simplyfact.eu/api/v1/customers/7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: customers-replace-0001" \
-d '{
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": ""
}'{
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"kind": "business",
"country": "BE",
"vat": "BE0000000097",
"email": "boekhouding@voorbeeld.invalid",
"phone": "",
"street": "Voorbeeldstraat",
"houseNumber": "12",
"postcode": "9000",
"city": "Gent",
"contact": "",
"language": "nl",
"paymentDays": 30,
"peppolId": "0208:0000000097",
"note": "",
"addressBox": ""
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van de klant. |
name | tekst | Naam van de klant. |
kind | tekst | business = onderneming, person = particulier. Eén van: business, person |
vat | tekst | Btw-nummer zonder spaties of punten, of leeg. |
peppolId | tekst | Peppol-adres, of leeg. |
email | tekst | E-mailadres voor facturen, of leeg. |
phone | tekst | Telefoonnummer, of leeg. |
street | tekst | Straat. |
houseNumber | tekst | Huisnummer. |
addressBox | tekst | Busnummer. |
postcode | tekst | Postcode. |
city | tekst | Gemeente. |
country | tekst | Landcode. |
language | tekst | Taal van documenten. Eén van: nl, fr, en |
paymentDays | geheel getal | Betaaltermijn in dagen. |
contact | tekst | Contactpersoon, of leeg. |
note | tekst | Interne notitie, of leeg. |
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Klant niet gevonden in deze administratie. |
| 409 | Een andere klant heeft al dit btw-nummer. |
| 422 | Validatiefout. Of: Dezelfde Idempotency-Key werd al gebruikt voor een andere aanvraag. |
/productsproducts:readProducten opvragen
Alle producten en diensten, per pagina. Ook niet-actieve producten.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
limit | query | geheel getal | nee | Aantal resultaten per pagina, 1 tot 100 (standaard 50). |
cursor | query | tekst | nee | nextCursor uit het vorige antwoord, voor de volgende pagina. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/products" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"data": [
{
"id": "1f2e3d4c-5b6a-4789-8abc-def012345678",
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true,
"stockEnabled": false,
"serialTracked": false,
"warrantyMonths": 0,
"purchasePrice": "0.00",
"revision": 1,
"updatedAt": "2026-11-02T08:30:00.000Z"
}
],
"nextCursor": "NTA"
}Antwoord
Een pagina: data is een lijst met de velden hieronder, nextCursor is de cursor voor de volgende pagina of null.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het product. |
kind | tekst | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | Artikelcode. |
name | tekst | Naam. |
description | tekst | Korte omschrijving. |
ean | tekst | EAN/UPC/GTIN, of leeg. |
brand | tekst | Merk. |
manufacturerCode | tekst | Artikelnummer van de fabrikant. |
stockEnabled | true/false | Of voorraad bijgehouden wordt. |
serialTracked | true/false | Of elk exemplaar een serienummer heeft. |
warrantyMonths | geheel getal | Garantie in maanden. |
purchasePrice | getal (tekst) | Aankoopprijs exclusief btw. |
unitCode | tekst | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | getal (tekst) | Verkoopprijs per eenheid exclusief btw. |
vatRate | getal (tekst) | Btw-tarief in procent. |
taxCategory | tekst | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Niet altijd aanwezig. Eén van: S, E, AE, K, G, O, Z |
taxReason | tekst | Wettelijke vermelding bij een btw-uitzondering. Niet altijd aanwezig. |
active | true/false | false = niet meer voorgesteld bij nieuwe documenten. |
revision | geheel getal | Versienummer; stijgt bij elke wijziging. |
updatedAt | tijdstip (UTC) | Tijdstip van de laatste wijziging. |
Succescode: 200. Algemene statuscodes en fouten.
/productsproducts:writeProduct aanmaken
Maakt een nieuw product of nieuwe dienst aan.
Aanvraag
Body als JSON. Velden die niet verplicht zijn mag je weglaten; dan geldt de standaardwaarde. Andere velden worden geweigerd.
| Veld | Type | Verplicht | Regels en uitleg |
|---|---|---|---|
kind | keuze | ja | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | ja | Artikelcode, uniek binnen de administratie (hoofdletters tellen niet). Een dubbele code geeft 409. 1–60 tekens |
name | tekst | ja | Naam zoals op de documentregel. 1–200 tekens |
description | tekst | ja | Korte omschrijving. max. 2000 tekens |
ean | tekst | ja | EAN/UPC/GTIN-barcode van 8, 12, 13 of 14 cijfers met geldig controlegetal, of leeg. Moet uniek zijn (409). max. 14 tekens |
brand | tekst | ja | Merk. max. 100 tekens |
manufacturerCode | tekst | ja | Artikelnummer van de fabrikant. max. 100 tekens |
stockEnabled | true/false | nee | true om voorraad bij te houden. standaard: false |
serialTracked | true/false | nee | true als elk exemplaar een serienummer heeft. standaard: false |
warrantyMonths | geheel getal | nee | Garantie in maanden. 0–240 · standaard: 0 |
purchasePrice | tekst | nee | Aankoopprijs exclusief btw. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
details | object | nee | Uitgebreide productinformatie. |
details.longDescription | tekst | nee | Lange omschrijving. max. 20000 tekens · standaard: "" |
details.specifications | lijst | nee | Technische specificaties. max. 300 elementen |
details.specifications[].group | tekst | ja | Groep, bijvoorbeeld Afmetingen. max. 150 tekens |
details.specifications[].name | tekst | ja | Naam van de eigenschap. max. 150 tekens |
details.specifications[].value | tekst | ja | Waarde van de eigenschap. max. 500 tekens |
details.images | lijst | nee | Id’s van productafbeeldingen die al in SimplyFact staan. Uploaden kan niet via de API. max. 6 elementen |
unitCode | keuze | ja | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | tekst | ja | Verkoopprijs per eenheid exclusief btw. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
vatRate | tekst | ja | Btw-tarief. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
taxCategory | keuze | nee | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Weglaten = standaard. Eén van: S, Z, E, AE, K, G, O |
taxReason | tekst | nee | Wettelijke vermelding bij een btw-uitzondering. max. 500 tekens |
active | true/false | ja | false = niet meer voorgesteld bij nieuwe documenten. |
Voorbeeld
curl -X POST "https://app.simplyfact.eu/api/v1/products" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: products-create-0001" \
-d '{
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true
}'{
"id": "1f2e3d4c-5b6a-4789-8abc-def012345678",
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true,
"stockEnabled": false,
"serialTracked": false,
"warrantyMonths": 0,
"purchasePrice": "0.00",
"revision": 1,
"updatedAt": "2026-11-02T08:30:00.000Z"
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het product. |
kind | tekst | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | Artikelcode. |
name | tekst | Naam. |
description | tekst | Korte omschrijving. |
ean | tekst | EAN/UPC/GTIN, of leeg. |
brand | tekst | Merk. |
manufacturerCode | tekst | Artikelnummer van de fabrikant. |
stockEnabled | true/false | Of voorraad bijgehouden wordt. |
serialTracked | true/false | Of elk exemplaar een serienummer heeft. |
warrantyMonths | geheel getal | Garantie in maanden. |
purchasePrice | getal (tekst) | Aankoopprijs exclusief btw. |
unitCode | tekst | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | getal (tekst) | Verkoopprijs per eenheid exclusief btw. |
vatRate | getal (tekst) | Btw-tarief in procent. |
taxCategory | tekst | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Niet altijd aanwezig. Eén van: S, E, AE, K, G, O, Z |
taxReason | tekst | Wettelijke vermelding bij een btw-uitzondering. Niet altijd aanwezig. |
active | true/false | false = niet meer voorgesteld bij nieuwe documenten. |
revision | geheel getal | Versienummer; stijgt bij elke wijziging. |
updatedAt | tijdstip (UTC) | Tijdstip van de laatste wijziging. |
Succescode: 201. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 409 | Deze artikelcode of EAN bestaat al. |
| 422 | Validatiefout, bijvoorbeeld een EAN met een fout controlegetal. Of: Dezelfde Idempotency-Key werd al gebruikt voor een andere aanvraag. |
/products/{id}products:readEén product opvragen
Eén product op basis van zijn id.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van het product. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/products/1f2e3d4c-5b6a-4789-8abc-def012345678" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"id": "1f2e3d4c-5b6a-4789-8abc-def012345678",
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true,
"stockEnabled": false,
"serialTracked": false,
"warrantyMonths": 0,
"purchasePrice": "0.00",
"revision": 1,
"updatedAt": "2026-11-02T08:30:00.000Z"
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het product. |
kind | tekst | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | Artikelcode. |
name | tekst | Naam. |
description | tekst | Korte omschrijving. |
ean | tekst | EAN/UPC/GTIN, of leeg. |
brand | tekst | Merk. |
manufacturerCode | tekst | Artikelnummer van de fabrikant. |
stockEnabled | true/false | Of voorraad bijgehouden wordt. |
serialTracked | true/false | Of elk exemplaar een serienummer heeft. |
warrantyMonths | geheel getal | Garantie in maanden. |
purchasePrice | getal (tekst) | Aankoopprijs exclusief btw. |
unitCode | tekst | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | getal (tekst) | Verkoopprijs per eenheid exclusief btw. |
vatRate | getal (tekst) | Btw-tarief in procent. |
taxCategory | tekst | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Niet altijd aanwezig. Eén van: S, E, AE, K, G, O, Z |
taxReason | tekst | Wettelijke vermelding bij een btw-uitzondering. Niet altijd aanwezig. |
active | true/false | false = niet meer voorgesteld bij nieuwe documenten. |
revision | geheel getal | Versienummer; stijgt bij elke wijziging. |
updatedAt | tijdstip (UTC) | Tijdstip van de laatste wijziging. |
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Product niet gevonden in deze administratie. |
/products/{id}products:writeProduct vervangen
Vervangt alle gegevens van een bestaand product; revision stijgt met 1. Stuur het volledige product mee. Bestaande documenten veranderen niet.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van het product. |
Aanvraag
Body als JSON. Velden die niet verplicht zijn mag je weglaten; dan geldt de standaardwaarde. Andere velden worden geweigerd.
| Veld | Type | Verplicht | Regels en uitleg |
|---|---|---|---|
kind | keuze | ja | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | ja | Artikelcode, uniek binnen de administratie (hoofdletters tellen niet). Een dubbele code geeft 409. 1–60 tekens |
name | tekst | ja | Naam zoals op de documentregel. 1–200 tekens |
description | tekst | ja | Korte omschrijving. max. 2000 tekens |
ean | tekst | ja | EAN/UPC/GTIN-barcode van 8, 12, 13 of 14 cijfers met geldig controlegetal, of leeg. Moet uniek zijn (409). max. 14 tekens |
brand | tekst | ja | Merk. max. 100 tekens |
manufacturerCode | tekst | ja | Artikelnummer van de fabrikant. max. 100 tekens |
stockEnabled | true/false | nee | true om voorraad bij te houden. standaard: false |
serialTracked | true/false | nee | true als elk exemplaar een serienummer heeft. standaard: false |
warrantyMonths | geheel getal | nee | Garantie in maanden. 0–240 · standaard: 0 |
purchasePrice | tekst | nee | Aankoopprijs exclusief btw. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
details | object | nee | Uitgebreide productinformatie. |
details.longDescription | tekst | nee | Lange omschrijving. max. 20000 tekens · standaard: "" |
details.specifications | lijst | nee | Technische specificaties. max. 300 elementen |
details.specifications[].group | tekst | ja | Groep, bijvoorbeeld Afmetingen. max. 150 tekens |
details.specifications[].name | tekst | ja | Naam van de eigenschap. max. 150 tekens |
details.specifications[].value | tekst | ja | Waarde van de eigenschap. max. 500 tekens |
details.images | lijst | nee | Id’s van productafbeeldingen die al in SimplyFact staan. Uploaden kan niet via de API. max. 6 elementen |
unitCode | keuze | ja | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | tekst | ja | Verkoopprijs per eenheid exclusief btw. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
vatRate | tekst | ja | Btw-tarief. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
taxCategory | keuze | nee | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Weglaten = standaard. Eén van: S, Z, E, AE, K, G, O |
taxReason | tekst | nee | Wettelijke vermelding bij een btw-uitzondering. max. 500 tekens |
active | true/false | ja | false = niet meer voorgesteld bij nieuwe documenten. |
Voorbeeld
curl -X PUT "https://app.simplyfact.eu/api/v1/products/1f2e3d4c-5b6a-4789-8abc-def012345678" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: products-replace-0001" \
-d '{
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true
}'{
"id": "1f2e3d4c-5b6a-4789-8abc-def012345678",
"kind": "service",
"code": "CONSULT-UUR",
"name": "Consultancy per uur",
"description": "",
"ean": "",
"brand": "",
"manufacturerCode": "",
"unitCode": "HUR",
"unitPrice": "85.00",
"vatRate": "21",
"active": true,
"stockEnabled": false,
"serialTracked": false,
"warrantyMonths": 0,
"purchasePrice": "0.00",
"revision": 2,
"updatedAt": "2026-11-02T08:30:00.000Z"
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het product. |
kind | tekst | goods = fysiek product, labor = werkuren, service = opdracht / dienst, contract = contractuele prestatie. Eén van: goods, labor, service, contract |
code | tekst | Artikelcode. |
name | tekst | Naam. |
description | tekst | Korte omschrijving. |
ean | tekst | EAN/UPC/GTIN, of leeg. |
brand | tekst | Merk. |
manufacturerCode | tekst | Artikelnummer van de fabrikant. |
stockEnabled | true/false | Of voorraad bijgehouden wordt. |
serialTracked | true/false | Of elk exemplaar een serienummer heeft. |
warrantyMonths | geheel getal | Garantie in maanden. |
purchasePrice | getal (tekst) | Aankoopprijs exclusief btw. |
unitCode | tekst | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
unitPrice | getal (tekst) | Verkoopprijs per eenheid exclusief btw. |
vatRate | getal (tekst) | Btw-tarief in procent. |
taxCategory | tekst | Btw-categorie: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Niet altijd aanwezig. Eén van: S, E, AE, K, G, O, Z |
taxReason | tekst | Wettelijke vermelding bij een btw-uitzondering. Niet altijd aanwezig. |
active | true/false | false = niet meer voorgesteld bij nieuwe documenten. |
revision | geheel getal | Versienummer; stijgt bij elke wijziging. |
updatedAt | tijdstip (UTC) | Tijdstip van de laatste wijziging. |
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Product niet gevonden in deze administratie. |
| 409 | Een ander product heeft al deze artikelcode of EAN. |
| 422 | Validatiefout. Of: Dezelfde Idempotency-Key werd al gebruikt voor een andere aanvraag. |
/documentsdocuments:readDefinitieve documenten opvragen
Definitieve facturen, creditnota’s en offertes, in de volgorde waarin ze definitief werden. Concepten zijn niet zichtbaar. Filter op documentdatum met from en to.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
limit | query | geheel getal | nee | Aantal resultaten per pagina, 1 tot 100 (standaard 50). |
cursor | query | tekst | nee | nextCursor uit het vorige antwoord, voor de volgende pagina. |
from | query | datum | nee | Alleen vanaf deze datum (JJJJ-MM-DD, inbegrepen). |
to | query | datum | nee | Alleen tot en met deze datum (JJJJ-MM-DD). |
kind | query | tekst | nee | Alleen dit soort document. Eén van: invoice, credit-note, quote |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/documents?kind=invoice&from=2026-11-01&to=2026-11-30&limit=100" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"data": [
{
"id": "3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21",
"number": "F-2026-0042",
"kind": "invoice",
"issueDate": "2026-11-02",
"dueDate": "2026-12-02",
"reference": "Order 1042",
"currency": "EUR",
"buyer": {
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"vat": "BE0000000097",
"country": "BE"
},
"totals": {
"net": "680.00",
"vat": "142.80",
"total": "822.80",
"payable": "822.80"
},
"balance": "822.80",
"finalizedAt": "2026-11-02T09:14:03.120Z"
}
],
"nextCursor": "NTA"
}Antwoord
Een pagina: data is een lijst met de velden hieronder, nextCursor is de cursor voor de volgende pagina of null.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het document. |
number | tekst | Documentnummer, bijvoorbeeld F-2026-0042. Verandert nooit meer. |
kind | tekst | Soort document. Eén van: invoice, credit-note, quote |
issueDate | datum | Documentdatum. |
dueDate | datum of leeg | Vervaldatum, of leeg. |
reference | tekst | Referentie van de klant of order, of leeg. |
currency | tekst | Munt (ISO 4217), bijvoorbeeld EUR. |
buyer | object | Klant zoals vastgelegd op het moment van definitief maken. |
buyer.id | id (uuid) | Id van de klant (GET /customers/{id}). |
buyer.name | tekst | Naam van de klant. |
buyer.vat | tekst | Btw-nummer van de klant, of leeg. |
buyer.country | tekst | Landcode van de klant. |
totals | object | Totalen in de munt van het document. |
totals.net | bedrag (tekst) | Totaal exclusief btw. |
totals.vat | bedrag (tekst) | Btw-bedrag. |
totals.total | bedrag (tekst) | Totaal inclusief btw. |
totals.payable | bedrag (tekst) | Te betalen: totaal min een eventueel ontvangen voorschot. |
balance | bedrag (tekst) | Nog openstaand bedrag na betalingen en creditnota’s. Alleen bij facturen. Niet altijd aanwezig. |
finalizedAt | tijdstip (UTC) | Tijdstip waarop het document definitief werd. |
Succescode: 200. Algemene statuscodes en fouten.
/documents/{id}documents:readEén document met regels opvragen
Hetzelfde als in de lijst, aangevuld met de documentregels en de verwijzing naar de oorspronkelijke factuur.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van het document. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/documents/3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"id": "3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21",
"number": "F-2026-0042",
"kind": "invoice",
"issueDate": "2026-11-02",
"dueDate": "2026-12-02",
"reference": "Order 1042",
"currency": "EUR",
"buyer": {
"id": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"name": "Voorbeeld Bouw BV",
"vat": "BE0000000097",
"country": "BE"
},
"totals": {
"net": "680.00",
"vat": "142.80",
"total": "822.80",
"payable": "822.80"
},
"balance": "822.80",
"finalizedAt": "2026-11-02T09:14:03.120Z",
"lines": [
{
"description": "Consultancy oktober",
"quantity": "8",
"unitPrice": "85.00",
"vatRate": "21",
"unitCode": "HUR",
"discountPercent": "0"
}
],
"precedingInvoice": ""
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Vaste id van het document. |
number | tekst | Documentnummer, bijvoorbeeld F-2026-0042. Verandert nooit meer. |
kind | tekst | Soort document. Eén van: invoice, credit-note, quote |
issueDate | datum | Documentdatum. |
dueDate | datum of leeg | Vervaldatum, of leeg. |
reference | tekst | Referentie van de klant of order, of leeg. |
currency | tekst | Munt (ISO 4217), bijvoorbeeld EUR. |
buyer | object | Klant zoals vastgelegd op het moment van definitief maken. |
buyer.id | id (uuid) | Id van de klant (GET /customers/{id}). |
buyer.name | tekst | Naam van de klant. |
buyer.vat | tekst | Btw-nummer van de klant, of leeg. |
buyer.country | tekst | Landcode van de klant. |
totals | object | Totalen in de munt van het document. |
totals.net | bedrag (tekst) | Totaal exclusief btw. |
totals.vat | bedrag (tekst) | Btw-bedrag. |
totals.total | bedrag (tekst) | Totaal inclusief btw. |
totals.payable | bedrag (tekst) | Te betalen: totaal min een eventueel ontvangen voorschot. |
balance | bedrag (tekst) | Nog openstaand bedrag na betalingen en creditnota’s. Alleen bij facturen. Niet altijd aanwezig. |
finalizedAt | tijdstip (UTC) | Tijdstip waarop het document definitief werd. |
lines | lijst | Documentregels. |
lines[].productId | id (uuid) | Id van het product, als de regel aan een product gekoppeld is. Niet altijd aanwezig. |
lines[].description | tekst | Omschrijving van de regel. |
lines[].quantity | getal (tekst) | Hoeveelheid. |
lines[].unitPrice | getal (tekst) | Prijs per eenheid exclusief btw. |
lines[].vatRate | getal (tekst) | Btw-tarief in procent. |
lines[].unitCode | tekst | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
lines[].discountPercent | getal (tekst) | Korting op de regel in procent. |
lines[].taxCategory | tekst | Btw-categorie van de regel: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Niet altijd aanwezig. Eén van: S, E, AE, K, G, O, Z |
lines[].taxReason | tekst | Wettelijke vermelding bij een btw-uitzondering. Niet altijd aanwezig. |
lines[].warrantyMonths | geheel getal | Garantie in maanden. Niet altijd aanwezig. |
lines[].productDescription | tekst | Extra productomschrijving onder de regel. Niet altijd aanwezig. |
lines[].showDetails | true/false | Of productinformatie op het document getoond wordt. Niet altijd aanwezig. |
precedingInvoice | tekst | Bij een creditnota: nummer van de oorspronkelijke factuur, anders leeg. |
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Document niet gevonden in deze administratie. |
/documents/{id}/pdfdocuments:readPDF downloaden
De PDF van het document zoals die bij het definitief maken gearchiveerd werd.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van het document. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/documents/3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21/pdf" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-o F-2026-0042.pdfBinaire PDF. Content-Disposition: attachment; filename="F-2026-0042.pdf"Het PDF-bestand.
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Document niet gevonden in deze administratie. |
/documents/{id}/ubldocuments:readUBL downloaden
Het document als UBL 2.1-bestand volgens EN 16931 (Peppol BIS Billing 3.0), om rechtstreeks in een boekhoudpakket in te lezen.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
id | pad | id (uuid) | ja | Id van het document. |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/documents/3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21/ubl" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-o F-2026-0042.xml<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" …>
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ID>F-2026-0042</cbc:ID>
<cbc:IssueDate>2026-11-02</cbc:IssueDate>
…
</Invoice>Het XML-bestand, met Content-Disposition: attachment; filename="<nummer>.xml".
Succescode: 200. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 404 | Document niet gevonden in deze administratie. |
| 409 | Voor dit document kan geen geldige UBL gemaakt worden, bijvoorbeeld door ontbrekende verplichte gegevens. detail zegt wat er ontbreekt. |
/draftsdrafts:writeConcept aanmaken
Maakt een conceptfactuur, -creditnota of -offerte aan. Het concept verschijnt in SimplyFact, waar een gebruiker het nakijkt, definitief maakt en verstuurt. Pas dan krijgt het een nummer en is het zichtbaar via GET /documents (en via de webhook document.finalized). Voorraad toewijzen kan niet via de API.
Aanvraag
Body als JSON. Velden die niet verplicht zijn mag je weglaten; dan geldt de standaardwaarde. Andere velden worden geweigerd.
| Veld | Type | Verplicht | Regels en uitleg |
|---|---|---|---|
kind | keuze | ja | invoice = factuur, credit-note = creditnota, quote = offerte. Eén van: invoice, credit-note, quote |
customerId | tekst | ja | Id van een klant uit deze administratie (GET /customers). 1–80 tekens |
issueDate | datum | ja | Documentdatum. |
dueDate | datum of leeg | ja | Vervaldatum, of leeg: dan berekent SimplyFact ze bij het definitief maken uit de betaaltermijn. |
precedingDocumentId | id (uuid) | nee | Alleen bij een creditnota: id van de oorspronkelijke factuur van dezelfde klant (GET /documents). precedingInvoice moet dan het nummer van die factuur zijn. |
reference | tekst | ja | Referentie, bijvoorbeeld een ordernummer. Staat op het document en in de UBL. max. 150 tekens |
precedingInvoice | tekst | ja | Bij een creditnota: nummer van de oorspronkelijke factuur. Anders leeg. max. 150 tekens |
note | tekst | ja | Vrije tekst op het document. max. 2000 tekens |
discountPercent | tekst | nee | Korting op het hele document. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
taxExempt | true/false | nee | true als het hele document onder een btw-uitzondering valt. standaard: false |
taxExemptionCategory | keuze | nee | Btw-categorie van de uitzondering: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Eén van: S, Z, E, AE, K, G, O · standaard: "S" |
taxExemptionReason | tekst | nee | Wettelijke vermelding bij de uitzondering. max. 500 tekens · standaard: "" |
paymentMethod | keuze | nee | Betaalwijze: bank-transfer = overschrijving, cash = contant, card = betaalkaart. Eén van: bank-transfer, cash, card · standaard: "bank-transfer" |
useCustomerSettings | true/false | nee | Of SimplyFact de instellingen van de klant (betaaltermijn, korting, betaalwijze, btw-uitzondering) toepast wanneer het concept in SimplyFact verder bewerkt wordt. Via de API gelden de waarden die je meestuurt. standaard: true |
cashDiscountPercent | tekst | nee | Korting voor snelle betaling (niet bij een creditnota). Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
cashDiscountDays | geheel getal | nee | Binnen hoeveel dagen betaald moet worden voor de korting voor snelle betaling. 0–365 |
prepaidAmount | tekst | nee | Al ontvangen voorschot, alleen bij een factuur. Bedrag als tekst met maximaal twee decimalen; niet hoger dan het factuurtotaal. |
prepaidDate | datum of leeg | nee | Datum van het voorschot. |
lines | lijst | ja | Documentregels. 1–40 elementen |
lines[].productId | tekst | nee | Id van een product uit deze administratie (GET /products). Weglaten voor een vrije regel. max. 80 tekens |
lines[].description | tekst | ja | Omschrijving van de regel. 1–300 tekens |
lines[].quantity | tekst | ja | Hoeveelheid, groter dan 0, maximaal zes decimalen. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
lines[].warrantyMonths | geheel getal | nee | Garantie in maanden. 0–240 |
lines[].productDescription | tekst | nee | Extra productomschrijving onder de regel. max. 2000 tekens |
lines[].details | object | nee | Productinformatie met dezelfde opbouw als details bij een product. |
lines[].showDetails | true/false | nee | true om de productinformatie op het document te tonen. |
lines[].unitPrice | tekst | ja | Prijs per eenheid exclusief btw. Decimaal getal als tekst met een punt, bijvoorbeeld "85.00"; een komma wordt ook aanvaard. |
lines[].vatRate | tekst | ja | Btw-tarief. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
lines[].taxCategory | keuze | nee | Btw-categorie van de regel: S = standaard / geen uitzondering, E = vrijgesteld, AE = btw verlegd, K = intracommunautair, G = export, O = buiten btw-scope, Z = nultarief. Eén van: S, Z, E, AE, K, G, O |
lines[].taxReason | tekst | nee | Wettelijke vermelding bij een btw-uitzondering. max. 500 tekens |
lines[].unitCode | keuze | ja | Eenheid: C62 = stuk, HUR = uur, DAY = dag (UN/ECE Recommendation 20). Eén van: C62, HUR, DAY |
lines[].discountPercent | tekst | nee | Korting op deze regel. Percentage als tekst van 0 tot 100 met maximaal twee decimalen, bijvoorbeeld "21" of "5.5". |
Voorbeeld
curl -X POST "https://app.simplyfact.eu/api/v1/drafts" \
-H "Authorization: Bearer $SIMPLYFACT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: drafts-create-0001" \
-d '{
"kind": "invoice",
"customerId": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"issueDate": "2026-11-02",
"dueDate": "",
"reference": "Order 1042",
"precedingInvoice": "",
"note": "",
"lines": [
{
"description": "Consultancy oktober",
"quantity": "8",
"unitPrice": "85.00",
"vatRate": "21",
"unitCode": "HUR"
}
]
}'{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"kind": "invoice",
"revision": 1,
"note": "Concept aangemaakt. Definitief maken gebeurt in SimplyFact."
}Antwoord
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Id van het nieuwe concept. |
kind | tekst | Soort document. Eén van: invoice, credit-note, quote |
revision | geheel getal | Versienummer van het concept (1). |
note | tekst | Uitleg over de volgende stap. |
Succescode: 201. Algemene statuscodes en fouten.
Specifieke fouten
| Status | Betekenis |
|---|---|
| 422 | Validatiefout, een onbekende klant of product, of een creditnota die niet bij de oorspronkelijke factuur past. Of: Dezelfde Idempotency-Key werd al gebruikt voor een andere aanvraag. |
/paymentspayments:readBetalingen opvragen
Geregistreerde betalingen op verkoop- en aankoopfacturen, met de hand ingevoerd of uit gekoppelde bankboekingen. Filter op betaaldatum met from en to. Een terugboeking is een aparte betaling met een negatief bedrag en reversalOf.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
limit | query | geheel getal | nee | Aantal resultaten per pagina, 1 tot 100 (standaard 50). |
cursor | query | tekst | nee | nextCursor uit het vorige antwoord, voor de volgende pagina. |
from | query | datum | nee | Alleen vanaf deze datum (JJJJ-MM-DD, inbegrepen). |
to | query | datum | nee | Alleen tot en met deze datum (JJJJ-MM-DD). |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/payments?from=2026-11-01&to=2026-11-30" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"data": [
{
"id": "c2f4d7a1-8a8e-4f0e-9c1b-6f5e2d3a4b10",
"documentId": "3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21",
"direction": "incoming-payment",
"documentNumber": "F-2026-0042",
"amount": "822.80",
"cashDiscount": "0.00",
"date": "2026-11-20",
"method": "bank-transfer",
"reversalOf": null
}
],
"nextCursor": "NTA"
}Antwoord
Een pagina: data is een lijst met de velden hieronder, nextCursor is de cursor voor de volgende pagina of null.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Id van de betaling. |
documentId | id (uuid) | Id van de verkoopfactuur (GET /documents/{id}) of aankoopfactuur. |
direction | tekst | incoming-payment = ontvangen op een verkoopfactuur, outgoing-payment = betaald op een aankoopfactuur. Eén van: incoming-payment, outgoing-payment |
documentNumber | tekst | Nummer van de factuur waarop betaald werd. |
amount | bedrag (tekst) | Betaald bedrag. Negatief bij een terugboeking. |
cashDiscount | bedrag (tekst) | Toegekende korting voor snelle betaling. |
date | datum | Betaaldatum. |
method | tekst | Betaalwijze: bank-transfer = overschrijving, cash = contant, card = betaalkaart. Eén van: bank-transfer, cash, card |
reversalOf | tekst of null | Bij een terugboeking: id van de betaling die teruggedraaid wordt, anders null. |
Succescode: 200. Algemene statuscodes en fouten.
/incoming-invoicesincoming:readAankoopfacturen opvragen
Ontvangen aankoopfacturen en -creditnota’s, via Peppol, UBL, de factuurmailbox of handmatige invoer. Filter op factuurdatum met from en to.
Parameters
| Parameter | Waar | Type | Verplicht | Uitleg |
|---|---|---|---|---|
limit | query | geheel getal | nee | Aantal resultaten per pagina, 1 tot 100 (standaard 50). |
cursor | query | tekst | nee | nextCursor uit het vorige antwoord, voor de volgende pagina. |
from | query | datum | nee | Alleen vanaf deze datum (JJJJ-MM-DD, inbegrepen). |
to | query | datum | nee | Alleen tot en met deze datum (JJJJ-MM-DD). |
Voorbeeld
curl "https://app.simplyfact.eu/api/v1/incoming-invoices?from=2026-11-01&to=2026-11-30" \
-H "Authorization: Bearer $SIMPLYFACT_KEY"{
"data": [
{
"id": "5a9d3c1e-2b4f-4e6a-8d7c-1e0f9a8b7c65",
"kind": "invoice",
"number": "INV-88731",
"issueDate": "2026-11-03",
"dueDate": "2026-12-03",
"currency": "EUR",
"supplier": {
"name": "Voorbeeld Leverancier NV",
"vat": "BE0000000097"
},
"totals": {
"net": "100.00",
"vat": "21.00",
"total": "121.00",
"payable": "121.00"
},
"reviewed": false
}
],
"nextCursor": "NTA"
}Antwoord
Een pagina: data is een lijst met de velden hieronder, nextCursor is de cursor voor de volgende pagina of null.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Id van de aankoopfactuur. |
kind | tekst | Factuur of creditnota. Eén van: invoice, credit-note |
number | tekst | Nummer van de leverancier. |
issueDate | datum | Factuurdatum. |
dueDate | datum of leeg | Vervaldatum, of leeg. |
currency | tekst | Munt (ISO 4217). |
supplier | object | Leverancier. |
supplier.name | tekst | Naam van de leverancier. |
supplier.vat | tekst | Btw-nummer van de leverancier, of leeg. |
totals | object | Totalen in de munt van het document. |
totals.net | bedrag (tekst) | Totaal exclusief btw. |
totals.vat | bedrag (tekst) | Btw-bedrag. |
totals.total | bedrag (tekst) | Totaal inclusief btw. |
totals.payable | bedrag (tekst) | Te betalen: totaal min een eventueel ontvangen voorschot. |
reviewed | true/false | true als de aankoopfactuur in SimplyFact nagekeken is. |
Succescode: 200. Algemene statuscodes en fouten.
Technische referentie: webhooks
Voor ontwikkelaars
SimplyFact stuurt een POST met JSON naar je adres. Een antwoord met status 2xx geldt als ontvangen; de inhoud van je antwoord wordt genegeerd. Antwoord snel en verwerk het bericht daarna: na 10 seconden zonder verbinding of 20 seconden in totaal wordt de poging als mislukt beschouwd. Omleidingen (3xx) worden niet gevolgd.
| Header | Inhoud |
|---|---|
| Content-Type | application/json |
| SimplyFact-Event | De gebeurtenis, bijvoorbeeld document.finalized |
| SimplyFact-Delivery | Unieke id van deze levering (gelijk aan id in de body) |
| SimplyFact-Signature | t=<unix-seconden>,v1=<hex HMAC-SHA256 van t + "." + body, met het volledige geheim whsec_… als sleutel> |
Elk bericht heeft dezelfde omslag; alleen data verschilt per gebeurtenis. Berichten bevatten alleen verwijzingen en bedragen. Haal de volledige gegevens op via de API.
| Veld | Type | Uitleg |
|---|---|---|
id | id (uuid) | Unieke id van de levering, gelijk aan de header SimplyFact-Delivery. Gebruik hem om dubbele berichten te herkennen. |
type | tekst | De gebeurtenis, gelijk aan de header SimplyFact-Event. |
createdAt | tijdstip (UTC) | Tijdstip waarop de gebeurtenis plaatsvond. |
companyId | id (uuid) | Id van de administratie (zelfde als id in GET /company). |
data | object | Gegevens van de gebeurtenis; zie hieronder per gebeurtenis. |
document.finalizedFactuur, creditnota of offerte definitief
Een verkoopfactuur, creditnota of offerte is definitief gemaakt: met de hand of automatisch door een periodieke factuur. Haal het volledige document op met GET /documents/{documentId}.
| Veld | Type | Uitleg |
|---|---|---|
data.documentId | id (uuid) | Id van het document. |
data.number | tekst | Documentnummer. |
data.kind | tekst | Soort document. Eén van: invoice, credit-note, quote |
data.issueDate | datum | Documentdatum. |
data.customerId | id (uuid) | Id van de klant. |
data.currency | tekst | Munt. |
data.total | bedrag (tekst) | Totaal inclusief btw. |
{
"id": "9f8e7d6c-5b4a-4321-8fed-cba987654321",
"type": "document.finalized",
"createdAt": "2026-11-02T09:14:03.200Z",
"companyId": "e4c1b2a3-0f9e-4d8c-b7a6-123456789abc",
"data": {
"documentId": "3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21",
"number": "F-2026-0042",
"kind": "invoice",
"issueDate": "2026-11-02",
"customerId": "7d1c2a40-5b7e-4c55-9a43-3f0f6f0c1a11",
"currency": "EUR",
"total": "822.80"
}
}payment.registeredBetaling geregistreerd
Een betaling op een verkoopfactuur is geregistreerd: met de hand of door een bankboeking te koppelen. Een herhaalde aanvraag met dezelfde Idempotency-Key geeft geen tweede bericht.
| Veld | Type | Uitleg |
|---|---|---|
data.paymentId | id (uuid) | Id van de betaling (zie GET /payments). |
data.documentId | id (uuid) | Id van de factuur. |
data.documentNumber | tekst | Nummer van de factuur. |
data.amount | bedrag (tekst) | Betaald bedrag. |
data.date | datum | Betaaldatum. |
data.method | tekst | Betaalwijze. Eén van: bank-transfer, cash, card |
data.source | tekst | manual = met de hand ingevoerd, bank = uit een gekoppelde bankboeking. Eén van: manual, bank |
{
"id": "9f8e7d6c-5b4a-4321-8fed-cba987654321",
"type": "payment.registered",
"createdAt": "2026-11-02T09:14:03.200Z",
"companyId": "e4c1b2a3-0f9e-4d8c-b7a6-123456789abc",
"data": {
"paymentId": "c2f4d7a1-8a8e-4f0e-9c1b-6f5e2d3a4b10",
"documentId": "3b0e9a52-1f1d-4a8e-8f43-2f6b1d0c9e21",
"documentNumber": "F-2026-0042",
"amount": "822.80",
"date": "2026-11-20",
"method": "bank-transfer",
"source": "bank"
}
}incoming.receivedAankoopfactuur ontvangen
Er is een nieuwe aankoopfactuur binnengekomen. Een dubbel ontvangen factuur geeft geen tweede bericht.
| Veld | Type | Uitleg |
|---|---|---|
data.incomingId | id (uuid) | Id van de aankoopfactuur (zie GET /incoming-invoices). |
data.number | tekst | Factuurnummer van de leverancier. |
data.supplier | tekst | Naam van de leverancier. |
data.total | bedrag (tekst) | Totaal inclusief btw. |
data.source | tekst | peppol = via Peppol, ubl = UBL-bestand opgeladen, email = via de factuurmailbox, manual = met de hand ingevoerd, subscription = factuur van je SimplyFact-abonnement. Eén van: peppol, ubl, email, manual, subscription |
{
"id": "9f8e7d6c-5b4a-4321-8fed-cba987654321",
"type": "incoming.received",
"createdAt": "2026-11-02T09:14:03.200Z",
"companyId": "e4c1b2a3-0f9e-4d8c-b7a6-123456789abc",
"data": {
"incomingId": "5a9d3c1e-2b4f-4e6a-8d7c-1e0f9a8b7c65",
"number": "INV-88731",
"supplier": "Voorbeeld Leverancier NV",
"total": "121.00",
"source": "peppol"
}
}pingTestbericht
Wordt alleen verstuurd als je in de instellingen op Testbericht klikt, ook als de webhook gepauzeerd is. Kan niet als gebeurtenis aangevinkt worden.
| Veld | Type | Uitleg |
|---|---|---|
data.message | tekst | Vaste testtekst. |
{
"id": "9f8e7d6c-5b4a-4321-8fed-cba987654321",
"type": "ping",
"createdAt": "2026-11-02T09:14:03.200Z",
"companyId": "e4c1b2a3-0f9e-4d8c-b7a6-123456789abc",
"data": {
"message": "Testbericht van SimplyFact"
}
}- Controleer altijd de handtekening op de onbewerkte body (niet op opnieuw opgebouwde JSON) en weiger berichten met een tijdstempel ouder dan 5 minuten.
- Ontdubbel op SimplyFact-Delivery: in zeldzame gevallen kan hetzelfde bericht twee keer aankomen.
- Berichten worden snel na de gebeurtenis verstuurd, maar de volgorde is niet gegarandeerd. Haal bij twijfel de actuele toestand op via de API.
- Mislukt een levering, dan volgt een nieuwe poging na 1 min, 5 min, 30 min, 2 u, 6 u, 12 u, 24 u. Daarna wordt de levering opgegeven. Na 20 mislukte leveringen op rij wordt de webhook gepauzeerd; de beheerder kan hem weer activeren.
import express from 'express';
import { verify } from './verify.js'; // zie hieronder
const app = express();
const seen = new Set(); // in productie: een tabel met de delivery-id als unieke sleutel
// express.text houdt de body onbewerkt; dat is nodig voor de handtekening
app.post('/simplyfact', express.text({ type: 'application/json' }), (req, res) => {
if (!verify(process.env.SIMPLYFACT_WEBHOOK_SECRET, req.get('SimplyFact-Signature') ?? '', req.body)) return res.sendStatus(401);
const event = JSON.parse(req.body);
res.sendStatus(204); // eerst antwoorden, dan verwerken
if (seen.has(event.id)) return;
seen.add(event.id);
if (event.type === 'document.finalized') importDocument(event.data.documentId); // jouw code: GET /documents/{id}
});
app.listen(3000);import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: de onbewerkte body als string, header: SimplyFact-Signature
export function verify(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(',').map(part => part.split('=')));
if (!parts.t || !parts.v1 || Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = createHmac('sha256', secret).update(parts.t + '.' + rawBody).digest('hex');
return parts.v1.length === expected.length && timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}function verifySimplyFact(string $secret, string $header, string $rawBody): bool {
parse_str(str_replace(',', '&', $header), $parts);
if (!isset($parts['t'], $parts['v1']) || abs(time() - (int) $parts['t']) > 300) return false;
$expected = hash_hmac('sha256', $parts['t'] . '.' . $rawBody, $secret);
return hash_equals($expected, $parts['v1']);
}
$rawBody = file_get_contents('php://input');
$ok = verifySimplyFact(getenv('SIMPLYFACT_WEBHOOK_SECRET'), $_SERVER['HTTP_SIMPLYFACT_SIGNATURE'] ?? '', $rawBody);import hashlib, hmac, time
def verify(secret: str, header: str, raw_body: bytes) -> bool:
parts = dict(part.split('=', 1) for part in header.split(',') if '=' in part)
if 't' not in parts or 'v1' not in parts or abs(time.time() - int(parts['t'])) > 300:
return False
expected = hmac.new(secret.encode(), parts['t'].encode() + b'.' + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts['v1'])Wat (nog) niet kan
- Facturen definitief maken, verzenden of verwijderen via de API.
- Kant-en-klare koppelingen met specifieke boekhoudpakketten. Die kunnen later volgen bovenop UBL en deze API.
- IP-beperking per sleutel en het automatisch vernieuwen van sleutels. Wil je een sleutel vervangen, maak dan eerst een nieuwe aan en trek daarna de oude in.
- Webhooks voor betalingen op aankoopfacturen.