{"openapi":"3.1.0","info":{"title":"Katsjing API","version":"1.0.0","summary":"Create and read invoices and relations, and subscribe to invoice events.","description":"REST API for connecting a webshop, Zapier or custom software to a Katsjing administration. Every call is scoped to the administration the API key belongs to; there is no administration id in any URL or body. Amounts are strings with two decimals, dates are `YYYY-MM-DD`, timestamps are ISO-8601 UTC.","contact":{"name":"Katsjing","url":"https://www.katsjing.nl/contact"}},"servers":[{"url":"https://www.katsjing.nl","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Invoices","description":"Create and read sales invoices."},{"name":"Relations","description":"Create and read customers and suppliers."},{"name":"Webhooks","description":"Manage webhook subscriptions. This is the REST hooks pattern Zapier expects: subscribe with POST, unsubscribe with DELETE."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key issued under Settings → API & webhooks. Send it as `Authorization: Bearer ksj_…`. Keys are shown once; we store only a SHA-256 hash."}},"schemas":{"Fout":{"type":"object","description":"The single error shape of this API.","properties":{"fout":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code. This is an external contract: existing codes are never renamed. Branch on this, not on the message."},"melding":{"type":"string","description":"Human-readable explanation, in English, aimed at the developer."},"details":{"type":"object","description":"Present on `VALIDATION_FAILED`: the flattened field errors of the request body.","additionalProperties":true}},"required":["code","melding"]}},"required":["fout"]},"FactuurSamenvatting":{"type":"object","description":"An invoice without its lines. This is the exact shape used in webhook payloads, so what a consumer receives is what the GET returns.","properties":{"id":{"type":"string","format":"uuid","description":"Invoice id."},"factuurnummer":{"type":["string","null"],"description":"The issued invoice number. `null` while the invoice is still a draft — a draft has no number yet, and the internal placeholder is never exposed."},"status":{"type":"string","enum":["CONCEPT","VERZONDEN","GEDEELTELIJK_BETAALD","BETAALD","VERVALLEN","ONINBAAR","GECREDITEERD"],"description":"Invoice status."},"isCreditnota":{"type":"boolean","description":"True for a credit note. Credit notes carry negative amounts."},"factuurdatum":{"type":"string","format":"date","examples":["2026-08-14"],"description":"Invoice date; drives the financial year the entry is booked in."},"vervaldatum":{"type":"string","format":"date","examples":["2026-08-14"],"description":"Due date, derived from the invoice date and the payment term."},"betaaltermijnDagen":{"type":"integer","description":"Payment term in days."},"referentie":{"type":["string","null"],"description":"Your own reference, e.g. a webshop order number."},"valuta":{"type":"string","description":"ISO 4217 currency code. Always `EUR`; the bookkeeping is euro-only."},"subtotaalExclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Total excluding VAT."},"totaalBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"VAT total, rounded half-up per VAT rate group."},"totaalInclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Total including VAT."},"betaaldBedrag":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Amount received so far."},"openstaandBedrag":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Amount still outstanding: total plus collection costs and interest, minus payments and any written-off amount, floored at zero."},"definitiefOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice was finalised: numbered, booked and irreversible. `null` for drafts."},"verzondenOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice e-mail was first sent successfully. `null` means it has never been e-mailed — a finalised invoice can be booked without ever being sent."},"betaaldOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice became fully paid."},"relatie":{"type":"object","description":"The customer this invoice was issued to.","properties":{"id":{"type":"string","description":"Relation id."},"naam":{"type":"string","description":"Relation name."}},"required":["id","naam"]},"aangemaaktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Creation timestamp."},"bijgewerktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Last modification timestamp."}},"required":["id","factuurnummer","status","isCreditnota","factuurdatum","vervaldatum","betaaltermijnDagen","referentie","valuta","subtotaalExclBtw","totaalBtw","totaalInclBtw","betaaldBedrag","openstaandBedrag","definitiefOp","verzondenOp","betaaldOp","relatie","aangemaaktOp","bijgewerktOp"]},"FactuurRegel":{"type":"object","description":"A single invoice line.","properties":{"id":{"type":"string","format":"uuid","description":"Line id."},"volgorde":{"type":"integer","description":"Position of the line on the invoice, ascending."},"omschrijving":{"type":"string","description":"Line description as printed on the invoice."},"aantal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Quantity."},"prijsPerStukExclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Unit price excluding VAT."},"btwPercentage":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"VAT percentage applied to this line, e.g. `21.00`."},"btwTariefId":{"type":["string","null"],"format":"uuid","description":"Id of the VAT rate used, within this administration."},"regelExclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Line total excluding VAT."},"regelBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"VAT on this line."},"regelInclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Line total including VAT."}},"required":["id","volgorde","omschrijving","aantal","prijsPerStukExclBtw","btwPercentage","btwTariefId","regelExclBtw","regelBtw","regelInclBtw"]},"Factuur":{"type":"object","description":"An invoice including its lines.","properties":{"id":{"type":"string","format":"uuid","description":"Invoice id."},"factuurnummer":{"type":["string","null"],"description":"The issued invoice number. `null` while the invoice is still a draft — a draft has no number yet, and the internal placeholder is never exposed."},"status":{"type":"string","enum":["CONCEPT","VERZONDEN","GEDEELTELIJK_BETAALD","BETAALD","VERVALLEN","ONINBAAR","GECREDITEERD"],"description":"Invoice status."},"isCreditnota":{"type":"boolean","description":"True for a credit note. Credit notes carry negative amounts."},"factuurdatum":{"type":"string","format":"date","examples":["2026-08-14"],"description":"Invoice date; drives the financial year the entry is booked in."},"vervaldatum":{"type":"string","format":"date","examples":["2026-08-14"],"description":"Due date, derived from the invoice date and the payment term."},"betaaltermijnDagen":{"type":"integer","description":"Payment term in days."},"referentie":{"type":["string","null"],"description":"Your own reference, e.g. a webshop order number."},"valuta":{"type":"string","description":"ISO 4217 currency code. Always `EUR`; the bookkeeping is euro-only."},"subtotaalExclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Total excluding VAT."},"totaalBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"VAT total, rounded half-up per VAT rate group."},"totaalInclBtw":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Total including VAT."},"betaaldBedrag":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Amount received so far."},"openstaandBedrag":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","examples":["121.00"],"description":"Amount still outstanding: total plus collection costs and interest, minus payments and any written-off amount, floored at zero."},"definitiefOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice was finalised: numbered, booked and irreversible. `null` for drafts."},"verzondenOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice e-mail was first sent successfully. `null` means it has never been e-mailed — a finalised invoice can be booked without ever being sent."},"betaaldOp":{"type":["string","null"],"format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the invoice became fully paid."},"relatie":{"type":"object","description":"The customer this invoice was issued to.","properties":{"id":{"type":"string","description":"Relation id."},"naam":{"type":"string","description":"Relation name."}},"required":["id","naam"]},"aangemaaktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Creation timestamp."},"bijgewerktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Last modification timestamp."},"regels":{"type":"array","items":{"$ref":"#/components/schemas/FactuurRegel"},"description":"The invoice lines, in printing order."}},"required":["id","factuurnummer","status","isCreditnota","factuurdatum","vervaldatum","betaaltermijnDagen","referentie","valuta","subtotaalExclBtw","totaalBtw","totaalInclBtw","betaaldBedrag","openstaandBedrag","definitiefOp","verzondenOp","betaaldOp","relatie","aangemaaktOp","bijgewerktOp","regels"]},"FactuurLijst":{"type":"object","description":"A page of invoices.","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FactuurSamenvatting"}},"volgendeCursor":{"type":["string","null"],"format":"uuid","description":"Pass as `cursor` to fetch the next page. `null` means this was the last page."}},"required":["data","volgendeCursor"]},"Relatie":{"type":"object","description":"A customer or supplier.","properties":{"id":{"type":"string","format":"uuid","description":"Relation id."},"soort":{"type":"string","enum":["ZAKELIJK","CONSUMENT"],"description":"Business or consumer. This drives VAT treatment and whether an e-invoice (UBL) is generated: consumers never get one."},"isKlant":{"type":"boolean","description":"Can be invoiced (appears in accounts receivable)."},"isLeverancier":{"type":"boolean","description":"Can send us purchase invoices (appears in accounts payable)."},"naam":{"type":"string","description":"Relation name."},"contactpersoon":{"type":["string","null"],"description":"Contact person."},"contactpersoonEmail":{"type":["string","null"],"description":"Personal address of the contact person. Never used for document delivery — see `factuurEmail`."},"factuurEmail":{"type":["string","null"],"description":"The address every outgoing document goes to: invoices, quotes, reminders, dunning letters and the customer-portal link. There is deliberately no fallback to `contactpersoonEmail`."},"telefoon":{"type":["string","null"],"description":"Phone number."},"straat":{"type":["string","null"],"description":"Street."},"huisnummer":{"type":["string","null"],"description":"House number."},"postcode":{"type":["string","null"],"description":"Postal code."},"plaats":{"type":["string","null"],"description":"City."},"land":{"type":"string","description":"ISO 3166-1 alpha-2 country code, uppercase."},"iban":{"type":["string","null"],"description":"IBAN of the relation."},"btwNummer":{"type":["string","null"],"description":"VAT identification number."},"kvkNummer":{"type":["string","null"],"description":"Dutch Chamber of Commerce number."},"documenttaal":{"type":["string","null"],"description":"Language its documents are issued in. `null` means: follow the administration default."},"standaardBetaaltermijnDagen":{"type":["integer","null"],"description":"Default payment term in days, used when an invoice does not specify one."},"aangemaaktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Creation timestamp."},"bijgewerktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Last modification timestamp."}},"required":["id","soort","isKlant","isLeverancier","naam","contactpersoon","contactpersoonEmail","factuurEmail","telefoon","straat","huisnummer","postcode","plaats","land","iban","btwNummer","kvkNummer","documenttaal","standaardBetaaltermijnDagen","aangemaaktOp","bijgewerktOp"]},"RelatieLijst":{"type":"object","description":"A page of relations.","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Relatie"}},"volgendeCursor":{"type":["string","null"],"format":"uuid","description":"Pass as `cursor` to fetch the next page. `null` means this was the last page."}},"required":["data","volgendeCursor"]},"WebhookAbonnement":{"type":"object","description":"A webhook subscription. The signing secret is never returned here.","properties":{"id":{"type":"string","format":"uuid","description":"Subscription id."},"url":{"type":"string","format":"uri","description":"Endpoint that receives the POST."},"omschrijving":{"type":["string","null"],"description":"Free-text label."},"gebeurtenissen":{"type":"array","items":{"type":"string","enum":["factuur.verzonden","factuur.betaald"]},"description":"Events this endpoint is subscribed to."},"actief":{"type":"boolean","description":"Disabled subscriptions receive nothing."},"aangemaaktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Creation timestamp."}},"required":["id","url","omschrijving","gebeurtenissen","actief","aangemaaktOp"]},"WebhookAbonnementMetGeheim":{"type":"object","description":"A freshly created subscription. This is the only response that ever carries `geheim` — store it now; we keep it encrypted and cannot show it again.","properties":{"id":{"type":"string","format":"uuid","description":"Subscription id."},"url":{"type":"string","format":"uri","description":"Endpoint that receives the POST."},"omschrijving":{"type":["string","null"],"description":"Free-text label."},"gebeurtenissen":{"type":"array","items":{"type":"string","enum":["factuur.verzonden","factuur.betaald"]},"description":"Events this endpoint is subscribed to."},"actief":{"type":"boolean","description":"Disabled subscriptions receive nothing."},"aangemaaktOp":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"Creation timestamp."},"geheim":{"type":"string","description":"Signing secret (`whsec_…`). Shown exactly once."}},"required":["id","url","omschrijving","gebeurtenissen","actief","aangemaaktOp","geheim"]},"WebhookLijst":{"type":"object","description":"All webhook subscriptions of this administration (no paging).","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookAbonnement"}}},"required":["data"]},"WebhookPayload":{"type":"object","description":"The body we POST to your endpoint.","properties":{"id":{"type":"string","format":"uuid","description":"Delivery id. Delivery is at-least-once — deduplicate on this value."},"gebeurtenis":{"type":"string","enum":["factuur.verzonden","factuur.betaald"],"description":"Which event this is."},"tijdstip":{"type":"string","format":"date-time","examples":["2026-08-14T10:00:00.000Z"],"description":"When the event occurred (not when this attempt was made)."},"administratieId":{"type":"string","format":"uuid","description":"The administration the event belongs to."},"data":{"type":"object","properties":{"factuur":{"$ref":"#/components/schemas/FactuurSamenvatting"}},"required":["factuur"],"description":"A snapshot taken at the moment of the event. A retry never recomputes it, so a redelivery carries the original values."}},"required":["id","gebeurtenis","tijdstip","administratieId","data"]},"MaakFactuur":{"type":"object","properties":{"relatieId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"handelsnaamId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"factuurdatum":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"betaaltermijnDagen":{"type":"integer","minimum":0,"maximum":365},"referentie":{"type":"string","maxLength":200},"opmerking":{"type":"string","maxLength":2000},"definitiefMaken":{"default":false,"type":"boolean"},"regels":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"object","properties":{"omschrijving":{"type":"string","minLength":1,"maxLength":500},"aantal":{"anyOf":[{"type":"string"},{"type":"number"}]},"prijsPerStukExclBtw":{"anyOf":[{"type":"string"},{"type":"number"}]},"btwCode":{"type":"string","enum":["HOOG_21","LAAG_9","VRIJGESTELD","VERLEGD","NUL_0"]},"btwTariefId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["omschrijving","aantal","prijsPerStukExclBtw"]}}},"required":["relatieId","regels"],"description":"A line needs either `btwCode` or `btwTariefId` — that rule is a Zod refinement and cannot be expressed in JSON Schema, so it is stated here."},"MaakRelatie":{"type":"object","properties":{"naam":{"type":"string","minLength":1,"maxLength":200},"soort":{"default":"ZAKELIJK","type":"string","enum":["ZAKELIJK","CONSUMENT"]},"isKlant":{"default":true,"type":"boolean"},"isLeverancier":{"default":false,"type":"boolean"},"contactpersoon":{"type":"string","maxLength":200},"contactpersoonEmail":{"type":"string","maxLength":320,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"factuurEmail":{"type":"string","maxLength":320,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"telefoon":{"type":"string","maxLength":50},"straat":{"type":"string","maxLength":200},"huisnummer":{"type":"string","maxLength":20},"postcode":{"type":"string","maxLength":20},"plaats":{"type":"string","maxLength":100},"land":{"default":"NL","type":"string","minLength":2,"maxLength":2},"iban":{"type":"string","maxLength":34},"btwNummer":{"type":"string","maxLength":20},"kvkNummer":{"type":"string","maxLength":12},"standaardBetaaltermijnDagen":{"type":"integer","minimum":0,"maximum":365}},"required":["naam"]},"MaakWebhook":{"type":"object","properties":{"url":{"type":"string","maxLength":500},"gebeurtenissen":{"minItems":1,"type":"array","items":{"type":"string","enum":["factuur.verzonden","factuur.betaald"]}},"omschrijving":{"type":"string","maxLength":200}},"required":["url","gebeurtenissen"]}}},"paths":{"/api/v1/facturen":{"get":{"operationId":"lijstFacturen","summary":"List invoices","description":"Newest invoice date first. Use `cursor` for paging; do not compute offsets yourself.","tags":["Invoices"],"parameters":[{"name":"status","in":"query","description":"Only invoices with this status.","schema":{"type":"string","enum":["CONCEPT","VERZONDEN","GEDEELTELIJK_BETAALD","BETAALD","VERVALLEN","ONINBAAR","GECREDITEERD"]}},{"name":"relatieId","in":"query","description":"Only invoices for this customer.","schema":{"type":"string","format":"uuid"}},{"name":"vanaf","in":"query","description":"Invoice date on or after this date.","schema":{"type":"string","format":"date"}},{"name":"tot","in":"query","description":"Invoice date on or before this date.","schema":{"type":"string","format":"date"}},{"name":"limiet","in":"query","description":"Page size, 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","description":"The `volgendeCursor` value from the previous page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"A page of invoices.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FactuurLijst"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"422":{"description":"An unknown status, a malformed date or a malformed cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}},"post":{"operationId":"maakFactuur","summary":"Create an invoice","description":"Creates a draft by default. With `definitiefMaken: true` the invoice is numbered, booked into the ledger, given an EPC payment QR code and — for business customers — an e-invoice (UBL/NLCIUS), through exactly the same services the app itself uses.\n\nNothing is e-mailed from the API. Sending stays a deliberate act in the app (or your own order confirmation); the `factuur.verzonden` webhook tells you when the invoice mail has gone out.\n\nTotals are always computed from the lines, rounded half-up per VAT rate group. Do not send a total.","tags":["Invoices"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaakFactuur"},"example":{"relatieId":"0f7a5d2c-9b1e-4a63-8f5b-2d3c4e5f6a7b","referentie":"order-8471","definitiefMaken":true,"regels":[{"omschrijving":"Order #8471 — 2× wandlamp Nova","aantal":"2","prijsPerStukExclBtw":"50.00","btwCode":"HOOG_21"}]}}}},"responses":{"201":{"description":"The created invoice, including its lines.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Factuur"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The plan's monthly invoice limit has been reached (`PLAN_LIMIT_REACHED`), the plan does not include this (`UPGRADE_REQUIRED`), or the administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"422":{"description":"Invalid body, an unknown `relatieId`, a VAT code without an active rate in this administration, or an invoice date inside a closed financial year.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}},"/api/v1/facturen/{factuurId}":{"get":{"operationId":"haalFactuur","summary":"Get an invoice","tags":["Invoices"],"parameters":[{"name":"factuurId","in":"path","required":true,"description":"Invoice id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The invoice, including its lines.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Factuur"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"404":{"description":"`NOT_FOUND` — no invoice with this id in this administration. An invoice belonging to another administration is indistinguishable from one that does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}},"/api/v1/relaties":{"get":{"operationId":"lijstRelaties","summary":"List relations","description":"Newest first.","tags":["Relations"],"parameters":[{"name":"isKlant","in":"query","description":"Only customers (`true`) or only non-customers (`false`).","schema":{"type":"boolean"}},{"name":"isLeverancier","in":"query","description":"Only suppliers (`true`) or only non-suppliers (`false`).","schema":{"type":"boolean"}},{"name":"zoek","in":"query","description":"Case-insensitive substring match on the name.","schema":{"type":"string"}},{"name":"limiet","in":"query","description":"Page size, 1–100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"cursor","in":"query","description":"The `volgendeCursor` value from the previous page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"A page of relations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelatieLijst"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"422":{"description":"A malformed cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}},"post":{"operationId":"maakRelatie","summary":"Create a relation","description":"The webshop path: create the customer, then the invoice. There is deliberately **no** find-or-create on e-mail address — silently matching would attach invoices to the wrong customer. Store the returned `id` on your side.","tags":["Relations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaakRelatie"},"example":{"naam":"Jansen Interieur BV","soort":"ZAKELIJK","factuurEmail":"facturen@jansen-interieur.nl","straat":"Keizersgracht","huisnummer":"42","postcode":"1015 CS","plaats":"Amsterdam","land":"NL"}}}},"responses":{"201":{"description":"The created relation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relatie"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"422":{"description":"Invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}},"/api/v1/relaties/{relatieId}":{"get":{"operationId":"haalRelatie","summary":"Get a relation","tags":["Relations"],"parameters":[{"name":"relatieId","in":"path","required":true,"description":"Relation id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The relation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relatie"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"404":{"description":"`NOT_FOUND` — no relation with this id in this administration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}},"/api/v1/webhooks":{"get":{"operationId":"lijstWebhooks","summary":"List webhook subscriptions","tags":["Webhooks"],"responses":{"200":{"description":"All subscriptions, without their secrets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookLijst"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}},"post":{"operationId":"maakWebhook","summary":"Subscribe to events","description":"The response carries `geheim` exactly once — that is the signing secret you verify deliveries with. The endpoint must be https and may not point at a loopback, private or link-local address.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaakWebhook"},"example":{"url":"https://shop.example.com/hooks/katsjing","gebeurtenissen":["factuur.betaald"],"omschrijving":"Order fulfilment"}}}},"responses":{"201":{"description":"The created subscription, including the signing secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookAbonnementMetGeheim"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"409":{"description":"At most 20 subscriptions per administration (`CONFLICT`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"422":{"description":"Invalid body, or a URL that fails the https/private-address check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"503":{"description":"Webhooks are unavailable on this environment because the encryption key is not configured (`WEBHOOKS_UNAVAILABLE`). We never store a signing secret in plain text.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}},"/api/v1/webhooks/{webhookId}":{"get":{"operationId":"haalWebhook","summary":"Get a webhook subscription","tags":["Webhooks"],"parameters":[{"name":"webhookId","in":"path","required":true,"description":"Subscription id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookAbonnement"}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"404":{"description":"`NOT_FOUND` — no subscription with this id in this administration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}},"delete":{"operationId":"verwijderWebhook","summary":"Unsubscribe","description":"The REST hooks unsubscribe path — Zapier calls this when a Zap is turned off. Pending deliveries for this subscription are removed with it.","tags":["Webhooks"],"parameters":[{"name":"webhookId","in":"path","required":true,"description":"Subscription id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The subscription was removed.","content":{"application/json":{"schema":{"type":"object","properties":{"verwijderd":{"type":"boolean","enum":[true]}},"required":["verwijderd"]}}}},"401":{"description":"Missing key (`UNAUTHENTICATED`) or unknown/revoked key (`INVALID_API_KEY`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"403":{"description":"The administration is scheduled for deletion (`ADMINISTRATION_PENDING_DELETION`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"404":{"description":"`NOT_FOUND` — no subscription with this id in this administration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"description":"Rate limit exceeded (`RATE_LIMITED`): more than 240 requests per minute for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"500":{"description":"Unexpected server error (`INTERNAL_ERROR`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}}},"webhooks":{"factuur.verzonden":{"post":{"operationId":"webhook_factuur_verzonden","summary":"Invoice e-mail sent","description":"Sent every time an invoice e-mail goes out successfully, including a second send of the same invoice.","tags":["Webhooks"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPayload"}}}},"responses":{"200":{"description":"Answer 2xx within 10 seconds. Anything else — a timeout, a 4xx or a 5xx — counts as failed and is retried with backoff 1, 5, 15, 60, 360 and 1440 minutes (6 attempts total)."}}}},"factuur.betaald":{"post":{"operationId":"webhook_factuur_betaald","summary":"Invoice fully paid","description":"Sent on the transition to fully paid, via any route: a payment entered by hand, a matched bank transaction, an online payment in the customer portal, or a direct debit collection. It fires on the transition, not on every payment.","tags":["Webhooks"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPayload"}}}},"responses":{"200":{"description":"Answer 2xx within 10 seconds. Anything else — a timeout, a 4xx or a 5xx — counts as failed and is retried with backoff 1, 5, 15, 60, 360 and 1440 minutes (6 attempts total)."}}}}}}