{"openapi":"3.1.1","info":{"title":"factuurmaken API","version":"1.0.0","description":"Create invoice drafts for review. Active API-enabled subscription required (Pro, Business, or qualifying complimentary access). All keys act in the account default administration, independent of the app selected administration. Money is integer euro cents. This is a REST API; no MCP endpoint or OAuth connection is provided."},"servers":[{"url":"https://factuurmaken.nl"}],"externalDocs":{"description":"Developer guide and invoice quickstart","url":"https://factuurmaken.nl/developers"},"security":[{"bearerAuth":[]}],"paths":{"/api/v1/clients":{"get":{"operationId":"listClients","summary":"Find clients","description":"Clients in the account default administration, newest first. Search name/email with q. No pagination. Ask the user when multiple clients match.","x-required-scopes":["clients:read"],"x-openai-isConsequential":false,"parameters":[{"name":"q","in":"query","required":false,"description":"Case-insensitive name or email search.","schema":{"type":"string"}}],"responses":{"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":{"operationId":"createClient","summary":"Create a client","description":"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.","x-required-scopes":["clients:write"],"x-openai-isConsequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientCreate"},"example":{"name":"Acme B.V.","email":"administratie@example.com","type":"business","vatMode":"standard"}}}},"responses":{"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"}}}}}}},"/api/v1/clients/{id}":{"get":{"operationId":"getClient","summary":"Read a client","description":"Reads a client in the account default administration.","x-required-scopes":["clients:read"],"x-openai-isConsequential":false,"parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by this API.","schema":{"type":"string","minLength":1}}],"responses":{"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"}}}}}}},"/api/v1/invoices":{"get":{"operationId":"listInvoices","summary":"List invoices","description":"Invoices in the account default administration, newest first. Includes drafts and existing credit invoices.","x-required-scopes":["invoices:read"],"x-openai-isConsequential":false,"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":{"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":{"operationId":"createInvoiceDraft","summary":"Create a draft or append lines","description":"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 already scheduled for delivery. Creation/appending is NOT idempotent; an Idempotency-Key header is not supported. Dates and notes are ignored on append. A successful draft can still need details before finalization; review it in the app.","x-required-scopes":["invoices:write"],"x-openai-isConsequential":true,"requestBody":{"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":{"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"}}}},"422":{"description":"no_company_profile: complete company settings in the app.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/invoices/{id}":{"get":{"operationId":"getInvoice","summary":"Read an invoice with lines","description":"Returns the invoice and calculated totals. No PDF, UBL, public recipient token or download URL is returned.","x-required-scopes":["invoices:read"],"x-openai-isConsequential":false,"parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by this API.","schema":{"type":"string","minLength":1}}],"responses":{"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"}}}}}}},"/api/v1/invoices/{id}/send":{"post":{"operationId":"scheduleInvoiceSend","summary":"Schedule invoice delivery","description":"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.","x-required-scopes":["invoices:send"],"x-openai-isConsequential":true,"parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by this API.","schema":{"type":"string","minLength":1}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceSend"},"example":{"mode":"scheduled"}}}},"responses":{"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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"fm_live_…","description":"Create a key at https://factuurmaken.nl/app/settings/api. Required permissions are listed per operation in x-required-scopes. Keep the key in your integration secret store, not in prompts or URLs."}},"schemas":{"ClientCreate":{"$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"]},"bankAccountId":{"description":"An existing bank account ID from this administration. Omit to use the default; this API does not list bank accounts.","type":"string"},"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":{"$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":0,"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}},"required":["description","quantity","unitPriceCents","vatRate"]}},"issueDate":{"description":"YYYY-MM-DD. Defaults to today in UTC. Ignored when appending.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"dueDate":{"description":"YYYY-MM-DD. Defaults to issueDate plus the account payment term. Ignored when appending.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"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":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"mode":{"default":"scheduled","type":"string","enum":["now","scheduled"]},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}},"Client":{"$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":{"$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":{"$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":{"$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}}}}