Skip to content

Conventions

TopicRule
AmountsAlways integer øre (125000 = DKK 1,250.00). Never floats.
TimesUTC, ISO-8601 (2026-07-27T09:00:00Z).
LanguageField names and error codes are English and never translated. Documents we send (invoices, reminders) follow the debtor’s language.
Success envelope{ "data": … }, optionally { "data": …, "meta": … }
Error envelope{ "error": { "code": "…", "requestId": "…" } } — validation errors (400/422) add details: [{ "field": "…", "message": "…" }] so you can see exactly which field failed. Auth errors are deliberately detail-free.
Request idEvery response carries X-Request-Id. Include it when contacting support.
VersioningPath-versioned (/api/v1). Additive changes only; breaking changes get a new version with a published deprecation window.
HTTPcodeMeaning
400invalid_requestBody failed validation
400invalid_idempotency_keyMissing/malformed Idempotency-Key header (required on all POST/PATCH/PUT/DELETE)
400invalid_cursorTampered or expired pagination cursor
401invalid_api_keyMissing, malformed, unknown, expired or revoked key (deliberately indistinguishable)
403insufficient_scopeKey lacks the scope the route requires
403api_not_includedYour plan does not include API access
404case_not_found / customer_not_found / invoice_not_found / …Unknown id — or another tenant’s id (same neutral answer)
409idempotency_conflictSame idempotency key, different payload
409idempotency_in_progressSame key is being processed right now — retry after Retry-After
413payload_too_largeBody over the route’s size limit
422case_rejectedPayload valid but rejected by domain rules
422invoice_not_editable / invoice_already_issued / invoice_not_issued / customer_email_missingLifecycle rule violated (see Invoices)
422external_reference_in_use / sku_in_use / account_number_in_useUnique value already taken within your organisation
429rate_limitedBudget exhausted — honour Retry-After
503temporarily_unavailable / audit_unavailableTransient; retry with backoff

Budgets are per organisation, split by load class so a polling-heavy reader can never starve your writes:

ClassApplies toBudget
readGET/HEAD1200/min
writePOST/PATCH/DELETE300/min
documentPDF/document generation routes120/min

Every response carries RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset; a 429 adds Retry-After (seconds). Back off exponentially and respect Retry-After.

Every POST/PATCH/PUT/DELETE requires an Idempotency-Key header (8–128 chars, A-Za-z0-9._:-). Generate one key per logical operation (e.g. your order id), not per HTTP attempt. The contract:

  • Retrying with the same key + same payload replays the original response unchanged (marked with the Idempotency-Replay: true header) — safe against network failures.
  • The same key with a different payload returns 409 idempotency_conflict.
  • Two concurrent requests with the same key: one wins, the other gets 409 idempotency_in_progress — wait Retry-After seconds and retry.
  • Responses are stored for 24 hours. Server errors (5xx) are never stored — retry immediately with the same key.