De technische referentie is in het Engels en gebruikt dezelfde bron als OpenAPI. Vouw een aanroep of schema open voor parameters, velden en foutcodes.
get
/api/v1/clients
Find clients
Clients in the account default administration, newest first. Search name/email with q. No pagination. Ask the user when multiple clients match.
Required permission: clients:read
Parameters
[
{
"name": "q",
"in": "query",
"required": false,
"description": "Case-insensitive name or email search.",
"schema": {
"type": "string"
}
}
]
Responses and errors
{
"200": {
"description": "Matching clients.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"clients": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Client"
}
}
},
"required": [
"clients"
]
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
post
/api/v1/clients
Create a client
Creates a saved client. Omit number to assign the next client number. Search first to avoid duplicates; name/email are not unique. Retries are not deduplicated. Individual clients discard business-only fields.
Required permission: clients:write
JSON request · required
{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ClientCreate"
},
"example": {
"name": "Acme B.V.",
"email": "administratie@example.com",
"type": "business",
"vatMode": "standard"
}
}
}
}
Responses and errors
{
"201": {
"description": "Created client; null if removed before read-back.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"client": {
"anyOf": [
{
"$ref": "#/components/schemas/Client"
},
{
"type": "null"
}
]
}
},
"required": [
"client"
]
}
}
}
},
"400": {
"description": "invalid_json or validation; issues groups messages by top-level field.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "duplicate_number: client number already exists or automatic numbering could not find a free number.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
get
/api/v1/clients/{id}
Read a client
Reads a client in the account default administration.
Required permission: clients:read
Parameters
[
{
"name": "id",
"in": "path",
"required": true,
"description": "ID returned by this API.",
"schema": {
"type": "string",
"minLength": 1
}
}
]
Responses and errors
{
"200": {
"description": "Client.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"client": {
"$ref": "#/components/schemas/Client"
}
},
"required": [
"client"
]
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "not_found: unknown client or outside this administration.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
get
/api/v1/invoices
List invoices
Invoices in the account default administration, newest first. Includes drafts and existing credit invoices.
Required permission: invoices:read
Parameters
[
{
"name": "clientId",
"in": "query",
"required": false,
"description": "Only invoices linked to this client.",
"schema": {
"type": "string"
}
},
{
"name": "status",
"in": "query",
"required": false,
"description": "Derived display status; overdue can include an unsent draft.",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"enum": [
"draft",
"final",
"sent",
"overdue",
"paid"
],
"description": "Derived display status. An unpaid draft with a past due date can be overdue."
}
},
{
"name": "limit",
"in": "query",
"required": false,
"description": "Page size.",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 50
}
},
{
"name": "offset",
"in": "query",
"required": false,
"description": "Number of rows to skip.",
"schema": {
"type": "integer",
"minimum": 0,
"default": 0
}
}
]
Responses and errors
{
"200": {
"description": "Page of invoices.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"invoices": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Invoice"
}
},
"total": {
"type": "integer"
},
"limit": {
"type": "integer"
},
"offset": {
"type": "integer"
}
},
"required": [
"invoices",
"total",
"limit",
"offset"
]
}
}
}
},
"400": {
"description": "invalid_status: unsupported status filter.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
post
/api/v1/invoices
Create a draft or append lines
Creates an unnumbered draft for a saved client. Sender, bank account and payment term come from account settings; VAT treatment comes from the client. The server calculates totals. Use onOpenConcept=create for a separate draft. append may change a draft scheduled for delivery until its delivery attempt starts. Send a unique Idempotency-Key header for each logical request and reuse it on retries. Matching requests return the same invoice and appended flag without adding lines again; reusing a key with different input returns 409. Keys are scoped to the administration and retained until account deletion. The returned invoice reflects its current state. Dates and notes are ignored on append. A successful draft can still need details before finalization; review it in the app.
Required permission: invoices:write
Parameters
[
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"description": "Unique key for this logical create/append request. Reuse on retries.",
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 128
}
}
]
JSON request · required
{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvoiceCreate"
},
"example": {
"clientId": "REPLACE_WITH_CLIENT_ID",
"onOpenConcept": "create",
"lines": [
{
"description": "Advies",
"quantity": 8,
"unit": "uur",
"unitPriceCents": 9500,
"vatRate": 21
}
]
}
}
}
}
Responses and errors
{
"200": {
"description": "Lines appended; appended=true. sendPlanned=true means these lines will join an existing scheduled send.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"invoice": {
"anyOf": [
{
"$ref": "#/components/schemas/InvoiceDetail"
},
{
"type": "null"
}
]
},
"appended": {
"type": "boolean"
},
"sendPlanned": {
"type": "boolean"
}
},
"required": [
"invoice",
"appended",
"sendPlanned"
]
}
}
}
},
"201": {
"description": "New draft; appended=false and sendPlanned=false. invoice can be null if removed before read-back.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"invoice": {
"anyOf": [
{
"$ref": "#/components/schemas/InvoiceDetail"
},
{
"type": "null"
}
]
},
"appended": {
"type": "boolean"
},
"sendPlanned": {
"type": "boolean"
}
},
"required": [
"invoice",
"appended",
"sendPlanned"
]
}
}
}
},
"400": {
"description": "invalid_json or validation; issues groups messages by top-level field.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"402": {
"description": "invoice_cap: account invoice allowance reached.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "client_not_found: unknown client or outside this administration.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "idempotency_conflict: this key was used with different input.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"422": {
"description": "no_company_profile: complete company settings in the app. line_limit: appending would exceed the document line limit.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
get
/api/v1/invoices/{id}
Read an invoice with lines
Returns the invoice and calculated totals. No PDF, UBL, public recipient token or download URL is returned.
Required permission: invoices:read
Parameters
[
{
"name": "id",
"in": "path",
"required": true,
"description": "ID returned by this API.",
"schema": {
"type": "string",
"minLength": 1
}
}
]
Responses and errors
{
"200": {
"description": "Invoice with lines.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"invoice": {
"$ref": "#/components/schemas/InvoiceDetail"
}
},
"required": [
"invoice"
]
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "not_found: unknown invoice or outside this administration.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
post
/api/v1/invoices/{id}/send
Schedule invoice delivery
Schedules a real email to the recipient. Only call when the user requests delivery. mode=now schedules after the 20-second undo window; delivery runs asynchronously. mode=scheduled (also an empty request body) defaults to tomorrow in the account send window. date may be at most 180 days ahead. An existing schedule is preserved with alreadyPlanned=true. After dispatch a repeat may return not_a_draft. A successful response means scheduled, not delivered. The invoice is numbered during dispatch if it is not already finalized.
Required permission: invoices:send
Parameters
[
{
"name": "id",
"in": "path",
"required": true,
"description": "ID returned by this API.",
"schema": {
"type": "string",
"minLength": 1
}
}
]
JSON request · optional
{
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvoiceSend"
},
"example": {
"mode": "scheduled"
}
}
}
}
Responses and errors
{
"200": {
"description": "Delivery scheduled or existing schedule preserved.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"scheduledSendAt": {
"type": "string",
"format": "date-time"
},
"alreadyPlanned": {
"type": "boolean"
}
},
"required": [
"scheduledSendAt",
"alreadyPlanned"
]
}
}
}
},
"400": {
"description": "invalid_json, validation or date_too_far.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "invalid_api_key: missing, malformed, unknown or revoked Bearer key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "subscription_inactive, plan_not_allowed or insufficient_scope.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "not_found.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "not_a_draft: invoice has already been sent or paid.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"422": {
"description": "email_required: recipient has no email address. vat_number_required: reverse charge requires the recipient VAT identification number.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
ClientCreate · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"type": {
"default": "business",
"type": "string",
"enum": [
"business",
"individual"
]
},
"name": {
"type": "string",
"minLength": 1
},
"number": {
"type": "string",
"maxLength": 40
},
"vatMode": {
"default": "standard",
"type": "string",
"enum": [
"standard",
"reverse_charge",
"vat_exempt"
]
},
"language": {
"default": "nl",
"type": "string",
"enum": [
"nl",
"en"
]
},
"currency": {
"default": "EUR",
"type": "string",
"enum": [
"EUR",
"USD",
"GBP",
"CHF",
"SEK",
"NOK",
"DKK",
"PLN",
"CZK",
"CAD",
"AUD"
]
},
"gAccountPct": {
"type": "string"
},
"bankAccountId": {
"description": "An existing bank account ID from this administration. Omit to use the default; this API does not list bank accounts.",
"type": "string"
},
"paymentProvider": {
"description": "'multisafepay' or 'mollie': which connected payment provider collects this client's invoice payments. Omit or empty for the administration's default; a provider that is not connected falls back to the default at payment time.",
"anyOf": [
{
"type": "string",
"enum": [
"multisafepay",
"mollie"
]
},
{
"type": "string",
"const": ""
}
]
},
"contactName": {
"type": "string"
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
},
{
"type": "string",
"const": ""
}
]
},
"address": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"description": "Country name. Omitted or empty defaults to Nederland.",
"type": "string"
},
"kvk": {
"description": "Optional KVK number: eight digits, ignoring whitespace.",
"type": "string"
},
"vatNumber": {
"description": "Optional VAT number. NL numbers must match NL + 9 digits + B + 2 digits (ignoring spaces/dots/case); foreign prefixes are accepted.",
"type": "string"
}
},
"required": [
"name"
]
}
InvoiceCreate · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"clientId": {
"type": "string",
"minLength": 1,
"description": "ID returned by the clients API. Do not invent IDs."
},
"lines": {
"minItems": 1,
"maxItems": 200,
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {
"type": "string",
"minLength": 1
},
"details": {
"type": "string",
"maxLength": 2000
},
"quantity": {
"description": "Quantity; rounded server-side to 3 decimal places.",
"type": "number",
"minimum": 0.001,
"maximum": 100000
},
"unit": {
"type": "string",
"maxLength": 30
},
"unitPriceCents": {
"type": "integer",
"minimum": -100000000,
"maximum": 100000000,
"description": "Unit price excluding VAT, in integer euro cents. 9500 means EUR 95.00."
},
"vatRate": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"enum": [
21,
9,
0
],
"description": "VAT percentage; the client VAT mode determines whether VAT is charged."
},
"discountPct": {
"type": "integer",
"minimum": 0,
"maximum": 100
},
"periodStart": {
"type": "string",
"minLength": 1
},
"periodEnd": {
"description": "ISO timestamp; exclusive end of the service period.",
"type": "string",
"minLength": 1
},
"kind": {
"default": "standard",
"type": "string",
"enum": [
"standard",
"additional_work",
"reduced_work"
]
},
"category": {
"type": "string",
"enum": [
"labour",
"materials",
"other"
]
}
},
"required": [
"description",
"quantity",
"unitPriceCents",
"vatRate"
]
}
},
"issueDate": {
"description": "YYYY-MM-DD. Defaults to today in UTC. Ignored when appending.",
"type": "string"
},
"dueDate": {
"description": "YYYY-MM-DD. Defaults to issueDate plus the account payment term. Ignored when appending.",
"type": "string"
},
"notes": {
"description": "Invoice notes. Ignored when appending to an existing draft.",
"type": "string",
"maxLength": 2000
},
"onOpenConcept": {
"default": "create",
"description": "create always makes a new draft. append adds lines to an existing open draft (even one scheduled for delivery), or creates one if none exists. Neither mode deduplicates retries.",
"type": "string",
"enum": [
"create",
"append"
]
}
},
"required": [
"clientId",
"lines"
]
}
InvoiceSend · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"mode": {
"default": "scheduled",
"type": "string",
"enum": [
"now",
"scheduled"
]
},
"date": {
"type": "string"
}
}
}
Client · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"business",
"individual"
]
},
"number": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"name": {
"type": "string"
},
"contactName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"address": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"postalCode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"city": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"country": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"kvk": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"vatNumber": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"vatMode": {
"type": "string",
"enum": [
"standard",
"reverse_charge",
"vat_exempt"
]
},
"createdAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
}
},
"required": [
"id",
"type",
"number",
"name",
"contactName",
"email",
"address",
"postalCode",
"city",
"country",
"kvk",
"vatNumber",
"vatMode",
"createdAt"
],
"additionalProperties": false
}
Invoice · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"number": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Null until the invoice is finalized in the app or during dispatch."
},
"status": {
"type": "string",
"enum": [
"draft",
"final",
"sent",
"overdue",
"paid"
],
"description": "Derived display status. An unpaid draft with a past due date can be overdue."
},
"invoiceType": {
"type": "string",
"enum": [
"invoice",
"credit"
]
},
"clientId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"recipient": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"name",
"email"
],
"additionalProperties": false
},
"issueDate": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "null"
}
]
},
"dueDate": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "null"
}
]
},
"paidAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"scheduledSendAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"currency": {
"type": "string"
},
"vatMode": {
"type": "string",
"enum": [
"standard",
"reverse_charge",
"vat_exempt"
]
},
"notes": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"subtotalCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"vatCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"totalCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"updatedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
}
},
"required": [
"id",
"number",
"status",
"invoiceType",
"clientId",
"recipient",
"issueDate",
"dueDate",
"paidAt",
"scheduledSendAt",
"currency",
"vatMode",
"notes",
"subtotalCents",
"vatCents",
"totalCents",
"createdAt",
"updatedAt"
],
"additionalProperties": false
}
InvoiceDetail · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"number": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Null until the invoice is finalized in the app or during dispatch."
},
"status": {
"type": "string",
"enum": [
"draft",
"final",
"sent",
"overdue",
"paid"
],
"description": "Derived display status. An unpaid draft with a past due date can be overdue."
},
"invoiceType": {
"type": "string",
"enum": [
"invoice",
"credit"
]
},
"clientId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"recipient": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"required": [
"name",
"email"
],
"additionalProperties": false
},
"issueDate": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "null"
}
]
},
"dueDate": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "null"
}
]
},
"paidAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"scheduledSendAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"currency": {
"type": "string"
},
"vatMode": {
"type": "string",
"enum": [
"standard",
"reverse_charge",
"vat_exempt"
]
},
"notes": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"subtotalCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"vatCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"totalCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"createdAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"updatedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"lines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"position": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"description": {
"type": "string"
},
"details": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"quantity": {
"type": "number"
},
"unit": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"unitPriceCents": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "May be negative on an existing credit invoice."
},
"vatRate": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"discountPct": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"periodStart": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
},
"periodEnd": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
]
}
},
"required": [
"id",
"position",
"description",
"details",
"quantity",
"unit",
"unitPriceCents",
"vatRate",
"discountPct",
"periodStart",
"periodEnd"
],
"additionalProperties": false
}
}
},
"required": [
"id",
"number",
"status",
"invoiceType",
"clientId",
"recipient",
"issueDate",
"dueDate",
"paidAt",
"scheduledSendAt",
"currency",
"vatMode",
"notes",
"subtotalCents",
"vatCents",
"totalCents",
"createdAt",
"updatedAt",
"lines"
],
"additionalProperties": false
}
Error · JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"error": {
"type": "string"
},
"issues": {
"description": "Validation messages grouped by top-level field, for example lines or clientId.",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"required": [
"error"
],
"additionalProperties": false
}