StabisoDocs

API reference

Documents

Sales invoices, purchase bills and credit notes: draft, submit, void, history; the invoice PDF, ZUGFeRD / Factur-X, sending by e-mail or recording a hand-over; the files of a document: originals, archived outputs and attachments.

Operation Summary Scope Idempotency-Key
GET /v1/archive/export Download the archive of an entity as a ZIP audit
GET /v1/documents List documents read
POST /v1/documents Create an invoice, bill or credit note draft required
POST /v1/documents/preview Preview a document and its VAT draft
GET /v1/documents/{document_id} Get a document read
PATCH /v1/documents/{document_id} Change a draft document draft
GET /v1/documents/{document_id}/allocations List what settled a document read
GET /v1/documents/{document_id}/dispatches List what was sent of an invoice and how it can be sent read
GET /v1/documents/{document_id}/file Download the original file of a document read
GET /v1/documents/{document_id}/files List the files of a document read
POST /v1/documents/{document_id}/files Attach a scanned or received original to a document draft required
GET /v1/documents/{document_id}/files/{file_id} Download a file of a document read
GET /v1/documents/{document_id}/history Get the history of a document read
POST /v1/documents/{document_id}/mark-sent Record that an invoice or credit note was handed over post required
GET /v1/documents/{document_id}/pdf Download an invoice or credit note as PDF read
POST /v1/documents/{document_id}/reopen Reopen a rejected document draft required
POST /v1/documents/{document_id}/send Send an invoice or credit note by e-mail post required
POST /v1/documents/{document_id}/submit Submit a draft document draft
POST /v1/documents/{document_id}/void Void a draft document draft required
POST /v1/documents/{document_id}/write-off Write off what is open on a customer invoice draft required
POST /v1/documents/{document_id}/write-off/recovery Book money received after a write-off draft required
POST /v1/documents/{document_id}/write-off/vat-correction Correct the VAT a write-off kept draft required
GET /v1/documents/{document_id}/write-offs List the write-offs of an invoice read
GET /v1/entities/{entity}/invoice-content What an invoice must show about the seller and the customer read
GET /v1/entities/{entity}/vat-rate-types List the VAT rate types a document line can choose read

GET /v1/archive/export

Download the archive of an entity as a ZIP

Every original, archived output and attachment of the entity's posted invoices, bills and credit notes dated in the range, as a ZIP for an auditor: the files under files/<document number>/, and a manifest as manifest.csv and manifest.json with one row per file: the document's number (and the vendor's invoice number of a bill), kind, date, party and total; the file's name, SHA-256 and source (received, captured, archived_output, attached); who stored it and when; and its integrity (ok, or mismatch or unreadable for a file that is then left out of the ZIP). A posted document without a file has a row with empty file columns.

manifest.json also has expected_files and included_files: the export is complete when it is in the ZIP and they are equal; a ZIP without manifest.json is incomplete (the download was cut short).

The ZIP is streamed, one file at a time. Needs the audit scope (the Auditor role) or admin. The export is an audit event (archive.export) with the entity, the range and the counts. 404 for an unknown entity, 422 when end is before start.

Required scope audit (admin implies every scope)
Operation id export_archive_v1_archive_export_get

Parameters

In Name Type Required Description
query entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query start string (date) yes Document date from, inclusive (ISO 8601, 2026-01-01).
query end string (date) yes Document date to, inclusive (ISO 8601, 2026-12-31).

Example request

curl "$ERP_URL/v1/archive/export?entity=CH01&start=value&end=value" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 A ZIP with the files and a manifest (manifest.csv, manifest.json). application/zip
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

GET /v1/documents

List documents

Sales invoices, bills and credit notes of an entity, newest first (by document date, then creation). Each row is a full document with its lines, party code and name, stored original and, once posted, its open amount. All filters combine with AND.

Required scope read (admin implies every scope)
Operation id list_documents_v1_documents_get

Parameters

In Name Type Required Description
query entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query kind array of "purchase_bill" | "purchase_credit_note" | "sales_credit_note" | "sales_invoice" or null Repeat the parameter to select several kinds: sales_invoice, sales_credit_note, purchase_bill, purchase_credit_note. Default: all.
query status array of "draft" | "open" | "paid" | "pending_approval" | "posted" | "rejected" | "void" or null Repeat the parameter to select several statuses: draft, pending_approval, posted, rejected, void, open (posted with an open amount) and paid (posted, nothing open). Default: all.
query party string or null Customer or vendor code (e.g. C-DE) or id.
query currency string or null ISO 4217 code of the document currency, e.g. EUR.
query start string (date) or null Document date from, inclusive (ISO 8601, 2026-09-01).
query end string (date) or null Document date to, inclusive (ISO 8601, 2026-09-30).
query q string or null Text in the number, vendor invoice number, order or buyer reference, notes, or the party's name or code (case-insensitive, any part).
query limit integer Most documents returned, 1 to 1000. (min 1; max 1000; default 100)

Example request

curl "$ERP_URL/v1/documents?entity=CH01" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of DocumentOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "withholding_code": "string",
    "withholding_rate": "string",
    "withholding_base": "0.00",
    "withholding_amount": "0.00",
    "creditable_amount": "string",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party_code": "string",
    "party_name": "string",
    "party_status": "string",
    "number": "string",
    "external_number": "string",
    "status": "string",
    "document_date": "2026-09-21",
    "supply_date": "2026-09-21",
    "due_date": "2026-09-21",
    "currency": "string",
    "net_total": "string",
    "tax_total": "string",
    "total": "string",
    "functional_total": "string",
    "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "notes": "string",
    "legal_notes": [
      "string"
    ],
    "payment_iban": "string",
    "payment_reference": "string",
    "buyer_reference": "string",
    "order_reference": "string",
    "open_amount": "string",
    "payment_blocked": false,
    "tax_fx": {},
    "tax_fx_rate": "string",
    "tax_fx_net_total": "string",
    "tax_fx_tax_total": "string",
    "cash_discount_percent": "string",
    "cash_discount_date": "2026-09-21",
    "cash_discount_amount": "string",
    "discount_percent": "string",
    "discount_amount": "0.00",
    "provenance": {},
    "created_by": {},
    "created_at": "2026-09-21T09:30:00Z",
    "version": 1,
    "missing_content": [
      {
        "party": "buyer",
        "field": "name",
        "basis": "string",
        "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      }
    ],
    "source_file": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "kind": "string",
      "filename": "string",
      "content_type": "string",
      "size": 1,
      "sha256": "string",
      "created_at": "2026-09-21T09:30:00Z"
    },
    "ic": {
      "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "role": "mirror",
      "status": "string",
      "partner_entity": "string",
      "other_document_id": null
    },
    "lines": [
      {
        "line_no": 1,
        "description": "string",
        "quantity": "string",
        "creditable_quantity": null,
        "creditable_tax_amount": null,
        "creditable_discount_amount": null,
        "unit_price": "string",
        "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "product_id": null,
        "obligation_id": null,
        "sales_line_id": null,
        "credits_line": null,
        "delivery_line_id": null,
        "goods_returned": false,
        "warehouse_id": null,
        "as_credited": false,
        "supply_type": "string",
        "rate_type": "string",
        "tax_category": null,
        "use_tax": false,
        "vat_scope": "in_scope",
        "vat_scope_reason": null,
        "discount_percent": null,
        "discount_amount": "0.00",
        "document_discount_amount": "0.00",
        "net_amount": "string",
        "tax_rate": "string",
        "tax_amount": "string",
        "tax": null,
        "vat_recovery_percent": "100",
        "tax_fx_net_amount": null,
        "tax_fx_tax_amount": null,
        "dimensions": {}
      }
    ],
    "delivery_notes": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "number": "string"
      }
    ]
  }
]

POST /v1/documents

Create an invoice, bill or credit note

Create a sales invoice, purchase bill or credit note for a customer or vendor.

Tax is determined per line by data-vNext (place of supply, liable party, rate); the decision and its legal reference are stored on each line. The response holds the document and, with submit=true, the submit result: its policy is allow (posted, numbered) or require_approval (status pending_approval, approval_id set); a deny answers 403. Refuses with 404 for an unknown entity, party or account, 422 for invalid lines or a credit note above the open amount of the document it credits, and 409 when submitting for a draft customer or vendor (create with submit=false instead) or when crediting a document that is not posted. A credit note line with credits_line and a unit_price crediting a line that had a discount must state its discount (0 for none): 422 credit_discount_required otherwise. A credit note of a bill blocked for payment posts without settling the bill; the credit stays open until the variance is approved.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id create_document_v1_documents_post

Parameters

In Name Type Required Description
query submit boolean true (default): also submit the document through the approval policy (it is posted, or waits for approval). false: keep it as a draft. (default true)

Request body

application/json (required): DocumentInput

Field Type Required Description
entity string yes Code (or id) of the entity the document belongs to, e.g. CH01.
kind "purchase_bill" | "purchase_credit_note" | "sales_credit_note" | "sales_invoice" yes sales_invoice, sales_credit_note, purchase_bill or purchase_credit_note; the sales kinds take a customer as party, the purchase kinds a vendor.
party string yes Customer or vendor code (or id).
document_date string (date) or null Document date (ISO 8601, e.g. 2026-09-15): the invoice date. It must fall in an open period for the document to be posted. It is the tax point unless supply_date moves it; the VAT rates are those of the date of supply (a credit note takes the rates of the document it credits). Sales invoices and credit notes: default today where the company is. Bills and vendor credit notes: required, the date the vendor printed on it (422 document_date_required).
supply_date string (date) or null The date of supply (ISO 8601): when the goods were delivered or the service was performed (Leistungsdatum, date de livraison, data di effettuazione), printed on the invoice; omitted or null: the document date. Where the law of the company's country makes VAT due with the supply (DE, ES, GB; FR and IT for goods), the VAT is reported in the period of the supply, and the VAT rate and the official VAT exchange rate are those of the supply. An invoice issued before the supply (an advance invoice) is reported with its own date. A credit note is reported with its own date whatever its date of supply. Switzerland: VAT is due with the invoice (Art. 40 MWSTG).
due_date string (date) or null Due date (ISO 8601). Default: the document date plus the party's payment_terms_days, moved by due_date_convention if given.
currency string or null ISO 4217 code of the document currency, e.g. EUR; default: the party's currency (a credit note takes the currency of the document it credits). (pattern ^[A-Z]{3}$)
external_number string or null Vendor's invoice number.
credits string (uuid) or null Document this credit note corrects.
notes string or null Free text kept on the document.
lines array of DocumentLineInput The document's lines. At least one, except on a credit note with credits set, which then copies the quantities remaining after posted and pending credits. Price corrections or credits without a line link may require explicit lines.
source_document_id string (uuid) or null Id of the stored original file (e-invoice or captured bill) the document was entered from; shown as source_file and downloadable with GET /v1/documents/{id}/file.
provenance object Free-form object stored with the document, e.g. where the data came from. The server adds the reference-data versions and warnings. On a vendor document, vendor_vat_ids (a list) gives the VAT ids the document shows: the seller's (BT-31) and its tax representative's (BT-63); one of the company's VAT area tells that VAT the vendor printed may be the company's own VAT, not foreign VAT.
payment_iban string or null Bills: the account to pay if not the vendor's IBAN, e.g. a QR-IBAN.
payment_reference string or null Bills: the QR reference or ISO 11649 creditor reference to quote.
due_date_convention "following" | "modified_following" | "modified_preceding" | "preceding" or null Roll a due date computed from the payment terms onto a business day of the entity's country payment calendar (CH: SIC, euro area: TARGET), e.g. 'following'. Ignored when due_date is given.
buyer_reference string or null Invoices: the buyer's reference (XRechnung BT-10); defaults to the customer's Leitweg-ID.
cash_discount_percent decimal string or null Cash discount (Skonto) percent if paid within cash_discount_days, e.g. 2. Default: the party's; 0 for none. (min 0)
cash_discount_days integer or null Days from the document date within which the cash discount may be taken, 0 to 365. Give this or cash_discount_date, not both. (min 0; max 365)
cash_discount_date string (date) or null Instead of days.
order_reference string or null Buyer's PO number (BT-13).
discount_percent decimal string or null A discount on the whole document, in percent of the lines after their own discounts (above 0, at most 100). It is split over the lines by what each is worth, so the VAT of each rate goes down by its share. Give this or discount_amount, not both. (max 100; greater than 0)
discount_amount decimal string or null A discount on the whole document as an amount in its currency, at most what the lines are worth after their own discounts; split over the lines like discount_percent. On a credit note too, only the document discount it gives applies: the share of the credited document's discount comes with each line that credits a line as it was, in that line's own discount (credits_line). (greater than 0)

Example request

curl -X POST "$ERP_URL/v1/documents" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "document_date": "2026-09-15",
  "entity": "CH01",
  "kind": "sales_invoice",
  "lines": [
    {
      "description": "Consulting September 2026",
      "quantity": "10",
      "unit_price": "180.00"
    }
  ],
  "party": "C-CH"
}'

Responses

Status Meaning Body
201 Created DocumentResult
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "document": {
    "withholding_code": "string",
    "withholding_rate": "string",
    "withholding_base": "0.00",
    "withholding_amount": "0.00",
    "creditable_amount": "string",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party_code": "string",
    "party_name": "string",
    "party_status": "string",
    "number": "string",
    "external_number": "string",
    "status": "string",
    "document_date": "2026-09-21",
    "supply_date": "2026-09-21",
    "due_date": "2026-09-21",
    "currency": "string",
    "net_total": "string",
    "tax_total": "string",
    "total": "string",
    "functional_total": "string",
    "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "notes": "string",
    "legal_notes": [
      "string"
    ],
    "payment_iban": "string",
    "payment_reference": "string",
    "buyer_reference": "string",
    "order_reference": "string",
    "open_amount": "string",
    "payment_blocked": false,
    "tax_fx": {},
    "tax_fx_rate": "string",
    "tax_fx_net_total": "string",
    "tax_fx_tax_total": "string",
    "cash_discount_percent": "string",
    "cash_discount_date": "2026-09-21",
    "cash_discount_amount": "string",
    "discount_percent": "string",
    "discount_amount": "0.00",
    "provenance": {},
    "created_by": {},
    "created_at": "2026-09-21T09:30:00Z",
    "version": 1,
    "missing_content": [
      {
        "party": null,
        "field": null,
        "basis": null,
        "record_id": null
      }
    ],
    "source_file": {
      "id": null,
      "kind": null,
      "filename": null,
      "content_type": null,
      "size": null,
      "sha256": null,
      "created_at": null
    },
    "ic": {
      "link_id": null,
      "role": null,
      "status": null,
      "partner_entity": null,
      "other_document_id": null
    },
    "lines": [
      {
        "line_no": null,
        "description": null,
        "quantity": null,
        "creditable_quantity": null,
        "creditable_tax_amount": null,
        "creditable_discount_amount": null,
        "unit_price": null,
        "account_id": null,
        "product_id": null,
        "obligation_id": null,
        "sales_line_id": null,
        "credits_line": null,
        "delivery_line_id": null,
        "goods_returned": null,
        "warehouse_id": null,
        "as_credited": null,
        "supply_type": null,
        "rate_type": null,
        "tax_category": null,
        "use_tax": null,
        "vat_scope": null,
        "vat_scope_reason": null,
        "discount_percent": null,
        "discount_amount": null,
        "document_discount_amount": null,
        "net_amount": null,
        "tax_rate": null,
        "tax_amount": null,
        "tax": null,
        "vat_recovery_percent": null,
        "tax_fx_net_amount": null,
        "tax_fx_tax_amount": null,
        "dimensions": null
      }
    ],
    "delivery_notes": [
      {
        "id": null,
        "number": null
      }
    ]
  },
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": null,
      "reason": null,
      "rule_id": null,
      "table_id": null
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

POST /v1/documents/preview

Preview a document and its VAT

The document the body would create, with the tax of every line determined and its totals, without storing anything (entry forms show live VAT with it). The body is the same as for creating a document and is validated the same way (404, 409, 422); the returned id is a placeholder, status is draft and number is null. For a sales invoice or credit note missing_content warns of what the entity's or the customer's record lacks to be a lawful invoice; it does not refuse (printing and sending do).

Required scope draft (admin implies every scope)
Idempotency-Key not used
Operation id preview_document_v1_documents_preview_post

Request body

application/json (required): DocumentInput

Field Type Required Description
entity string yes Code (or id) of the entity the document belongs to, e.g. CH01.
kind "purchase_bill" | "purchase_credit_note" | "sales_credit_note" | "sales_invoice" yes sales_invoice, sales_credit_note, purchase_bill or purchase_credit_note; the sales kinds take a customer as party, the purchase kinds a vendor.
party string yes Customer or vendor code (or id).
document_date string (date) or null Document date (ISO 8601, e.g. 2026-09-15): the invoice date. It must fall in an open period for the document to be posted. It is the tax point unless supply_date moves it; the VAT rates are those of the date of supply (a credit note takes the rates of the document it credits). Sales invoices and credit notes: default today where the company is. Bills and vendor credit notes: required, the date the vendor printed on it (422 document_date_required).
supply_date string (date) or null The date of supply (ISO 8601): when the goods were delivered or the service was performed (Leistungsdatum, date de livraison, data di effettuazione), printed on the invoice; omitted or null: the document date. Where the law of the company's country makes VAT due with the supply (DE, ES, GB; FR and IT for goods), the VAT is reported in the period of the supply, and the VAT rate and the official VAT exchange rate are those of the supply. An invoice issued before the supply (an advance invoice) is reported with its own date. A credit note is reported with its own date whatever its date of supply. Switzerland: VAT is due with the invoice (Art. 40 MWSTG).
due_date string (date) or null Due date (ISO 8601). Default: the document date plus the party's payment_terms_days, moved by due_date_convention if given.
currency string or null ISO 4217 code of the document currency, e.g. EUR; default: the party's currency (a credit note takes the currency of the document it credits). (pattern ^[A-Z]{3}$)
external_number string or null Vendor's invoice number.
credits string (uuid) or null Document this credit note corrects.
notes string or null Free text kept on the document.
lines array of DocumentLineInput The document's lines. At least one, except on a credit note with credits set, which then copies the quantities remaining after posted and pending credits. Price corrections or credits without a line link may require explicit lines.
source_document_id string (uuid) or null Id of the stored original file (e-invoice or captured bill) the document was entered from; shown as source_file and downloadable with GET /v1/documents/{id}/file.
provenance object Free-form object stored with the document, e.g. where the data came from. The server adds the reference-data versions and warnings. On a vendor document, vendor_vat_ids (a list) gives the VAT ids the document shows: the seller's (BT-31) and its tax representative's (BT-63); one of the company's VAT area tells that VAT the vendor printed may be the company's own VAT, not foreign VAT.
payment_iban string or null Bills: the account to pay if not the vendor's IBAN, e.g. a QR-IBAN.
payment_reference string or null Bills: the QR reference or ISO 11649 creditor reference to quote.
due_date_convention "following" | "modified_following" | "modified_preceding" | "preceding" or null Roll a due date computed from the payment terms onto a business day of the entity's country payment calendar (CH: SIC, euro area: TARGET), e.g. 'following'. Ignored when due_date is given.
buyer_reference string or null Invoices: the buyer's reference (XRechnung BT-10); defaults to the customer's Leitweg-ID.
cash_discount_percent decimal string or null Cash discount (Skonto) percent if paid within cash_discount_days, e.g. 2. Default: the party's; 0 for none. (min 0)
cash_discount_days integer or null Days from the document date within which the cash discount may be taken, 0 to 365. Give this or cash_discount_date, not both. (min 0; max 365)
cash_discount_date string (date) or null Instead of days.
order_reference string or null Buyer's PO number (BT-13).
discount_percent decimal string or null A discount on the whole document, in percent of the lines after their own discounts (above 0, at most 100). It is split over the lines by what each is worth, so the VAT of each rate goes down by its share. Give this or discount_amount, not both. (max 100; greater than 0)
discount_amount decimal string or null A discount on the whole document as an amount in its currency, at most what the lines are worth after their own discounts; split over the lines like discount_percent. On a credit note too, only the document discount it gives applies: the share of the credited document's discount comes with each line that credits a line as it was, in that line's own discount (credits_line). (greater than 0)

Example request

curl -X POST "$ERP_URL/v1/documents/preview" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "document_date": "2026-09-15",
  "entity": "CH01",
  "kind": "sales_invoice",
  "lines": [
    {
      "description": "Consulting September 2026",
      "quantity": "10",
      "unit_price": "180.00"
    }
  ],
  "party": "C-CH"
}'

Responses

Status Meaning Body
200 OK DocumentOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "withholding_code": "string",
  "withholding_rate": "string",
  "withholding_base": "0.00",
  "withholding_amount": "0.00",
  "creditable_amount": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "kind": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "party_code": "string",
  "party_name": "string",
  "party_status": "string",
  "number": "string",
  "external_number": "string",
  "status": "string",
  "document_date": "2026-09-21",
  "supply_date": "2026-09-21",
  "due_date": "2026-09-21",
  "currency": "string",
  "net_total": "string",
  "tax_total": "string",
  "total": "string",
  "functional_total": "string",
  "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "notes": "string",
  "legal_notes": [
    "string"
  ],
  "payment_iban": "string",
  "payment_reference": "string",
  "buyer_reference": "string",
  "order_reference": "string",
  "open_amount": "string",
  "payment_blocked": false,
  "tax_fx": {},
  "tax_fx_rate": "string",
  "tax_fx_net_total": "string",
  "tax_fx_tax_total": "string",
  "cash_discount_percent": "string",
  "cash_discount_date": "2026-09-21",
  "cash_discount_amount": "string",
  "discount_percent": "string",
  "discount_amount": "0.00",
  "provenance": {},
  "created_by": {},
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "missing_content": [
    {
      "party": "buyer",
      "field": "name",
      "basis": "string",
      "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "source_file": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "ic": {
    "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "role": "mirror",
    "status": "string",
    "partner_entity": "string",
    "other_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "lines": [
    {
      "line_no": 1,
      "description": "string",
      "quantity": "string",
      "creditable_quantity": "string",
      "creditable_tax_amount": "string",
      "creditable_discount_amount": "string",
      "unit_price": "string",
      "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "obligation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sales_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "credits_line": 1,
      "delivery_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "goods_returned": false,
      "warehouse_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "as_credited": false,
      "supply_type": "string",
      "rate_type": "string",
      "tax_category": "string",
      "use_tax": false,
      "vat_scope": "in_scope",
      "vat_scope_reason": "damages",
      "discount_percent": "string",
      "discount_amount": "0.00",
      "document_discount_amount": "0.00",
      "net_amount": "string",
      "tax_rate": "string",
      "tax_amount": "string",
      "tax": {},
      "vat_recovery_percent": "100",
      "tax_fx_net_amount": "string",
      "tax_fx_tax_amount": "string",
      "dimensions": {}
    }
  ],
  "delivery_notes": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string"
    }
  ]
}

GET /v1/documents/{document_id}

Get a document

One document with its lines, tax decisions and, once posted, its open amount, by id or by number (e.g. INV-2026-000001; a number used in several entities answers 409, use the id). The ETag response header names the version; send it back as If-Match when you change, submit or void the document. 404 when it does not exist.

Required scope read (admin implies every scope)
Response header ETag names the current version
Operation id get_document_v1_documents__document_id__get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK DocumentOut, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "withholding_code": "string",
  "withholding_rate": "string",
  "withholding_base": "0.00",
  "withholding_amount": "0.00",
  "creditable_amount": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "kind": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "party_code": "string",
  "party_name": "string",
  "party_status": "string",
  "number": "string",
  "external_number": "string",
  "status": "string",
  "document_date": "2026-09-21",
  "supply_date": "2026-09-21",
  "due_date": "2026-09-21",
  "currency": "string",
  "net_total": "string",
  "tax_total": "string",
  "total": "string",
  "functional_total": "string",
  "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "notes": "string",
  "legal_notes": [
    "string"
  ],
  "payment_iban": "string",
  "payment_reference": "string",
  "buyer_reference": "string",
  "order_reference": "string",
  "open_amount": "string",
  "payment_blocked": false,
  "tax_fx": {},
  "tax_fx_rate": "string",
  "tax_fx_net_total": "string",
  "tax_fx_tax_total": "string",
  "cash_discount_percent": "string",
  "cash_discount_date": "2026-09-21",
  "cash_discount_amount": "string",
  "discount_percent": "string",
  "discount_amount": "0.00",
  "provenance": {},
  "created_by": {},
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "missing_content": [
    {
      "party": "buyer",
      "field": "name",
      "basis": "string",
      "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "source_file": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "ic": {
    "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "role": "mirror",
    "status": "string",
    "partner_entity": "string",
    "other_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "lines": [
    {
      "line_no": 1,
      "description": "string",
      "quantity": "string",
      "creditable_quantity": "string",
      "creditable_tax_amount": "string",
      "creditable_discount_amount": "string",
      "unit_price": "string",
      "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "obligation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sales_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "credits_line": 1,
      "delivery_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "goods_returned": false,
      "warehouse_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "as_credited": false,
      "supply_type": "string",
      "rate_type": "string",
      "tax_category": "string",
      "use_tax": false,
      "vat_scope": "in_scope",
      "vat_scope_reason": "damages",
      "discount_percent": "string",
      "discount_amount": "0.00",
      "document_discount_amount": "0.00",
      "net_amount": "string",
      "tax_rate": "string",
      "tax_amount": "string",
      "tax": {},
      "vat_recovery_percent": "100",
      "tax_fx_net_amount": "string",
      "tax_fx_tax_amount": "string",
      "dimensions": {}
    }
  ],
  "delivery_notes": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string"
    }
  ]
}

PATCH /v1/documents/{document_id}

Change a draft document

Change a draft: header fields, party and lines (which replace all lines).

Omitted fields keep their value, null clears an optional one. The tax of every line is determined again. Only drafts change (409 otherwise); a rejected document must be reopened first (POST .../reopen). Repeating the same change gives the same draft; send If-Match so a change made in the meantime is not overwritten (412 when the document is at another version). 422 when the result is invalid, e.g. a negative total.

Required scope draft (admin implies every scope)
Idempotency-Key not used
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id update_document_v1_documents__document_id__patch

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
header If-Match string or null The ETag of the version you read; a changed document answers 412. (max length 200)

Request body

application/json (required): DocumentUpdate

Field Type Required Description
party string or null Customer or vendor code (or id).
document_date string (date) or null New document date (ISO 8601); the due date follows unless given. null is refused.
supply_date string (date) or null The date of supply (ISO 8601): when the goods were delivered or the service was performed (Leistungsdatum, date de livraison, data di effettuazione), printed on the invoice; omitted or null: the document date. Where the law of the company's country makes VAT due with the supply (DE, ES, GB; FR and IT for goods), the VAT is reported in the period of the supply, and the VAT rate and the official VAT exchange rate are those of the supply. An invoice issued before the supply (an advance invoice) is reported with its own date. A credit note is reported with its own date whatever its date of supply. Switzerland: VAT is due with the invoice (Art. 40 MWSTG). null clears it (the document date).
due_date string (date) or null New due date (ISO 8601); null recomputes it from the payment terms.
due_date_convention "following" | "modified_following" | "modified_preceding" | "preceding" or null Moves a due date computed from the payment terms onto a business day of the entity's country calendar (CH: SIC, euro area: TARGET): following, modified_following, preceding or modified_preceding. Ignored when due_date is given.
currency string or null ISO 4217 currency code, e.g. EUR. (pattern ^[A-Z]{3}$)
external_number string or null Vendor's invoice number.
notes string or null Free text kept on the document; null clears it.
lines array of DocumentLineInput or null The new lines; they replace all existing lines (at least one). null or omitted keeps the lines. (min items 1)
payment_iban string or null Bills: the account to pay if it is not the vendor's own IBAN, e.g. a QR-IBAN printed on the bill. It must be one of the vendor's confirmed accounts before a payment to it can be released.
payment_reference string or null Bills: the QR reference (27 digits) or ISO 11649 creditor reference (RF...) printed on the bill, quoted when paying. A QR reference needs a QR-IBAN.
buyer_reference string or null XRechnung BT-10.
order_reference string or null The buyer's purchase order number (EN 16931 BT-13).
cash_discount_percent decimal string or null Cash discount (Skonto) percent; 0 for none. (min 0)
cash_discount_days integer or null Days from the document date within which the cash discount may be taken, 0 to 365. Give this or cash_discount_date, not both. (min 0; max 365)
cash_discount_date string (date) or null Last day the cash discount may be taken (ISO 8601, not before the document date), instead of cash_discount_days.
discount_percent decimal string or null A discount on the whole document in percent; it replaces any document discount. null removes the document discount. (max 100; greater than 0)
discount_amount decimal string or null A discount on the whole document as an amount; it replaces any document discount. null removes the document discount. (greater than 0)

Example request

curl -X PATCH "$ERP_URL/v1/documents/INV-2026-000001" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{
  "due_date": "2026-10-31",
  "lines": [
    {
      "description": "Consulting September 2026",
      "quantity": "12",
      "unit_price": "180.00"
    }
  ],
  "notes": "Payable within 45 days."
}'

Responses

Status Meaning Body
200 OK DocumentOut, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "withholding_code": "string",
  "withholding_rate": "string",
  "withholding_base": "0.00",
  "withholding_amount": "0.00",
  "creditable_amount": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "kind": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "party_code": "string",
  "party_name": "string",
  "party_status": "string",
  "number": "string",
  "external_number": "string",
  "status": "string",
  "document_date": "2026-09-21",
  "supply_date": "2026-09-21",
  "due_date": "2026-09-21",
  "currency": "string",
  "net_total": "string",
  "tax_total": "string",
  "total": "string",
  "functional_total": "string",
  "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "notes": "string",
  "legal_notes": [
    "string"
  ],
  "payment_iban": "string",
  "payment_reference": "string",
  "buyer_reference": "string",
  "order_reference": "string",
  "open_amount": "string",
  "payment_blocked": false,
  "tax_fx": {},
  "tax_fx_rate": "string",
  "tax_fx_net_total": "string",
  "tax_fx_tax_total": "string",
  "cash_discount_percent": "string",
  "cash_discount_date": "2026-09-21",
  "cash_discount_amount": "string",
  "discount_percent": "string",
  "discount_amount": "0.00",
  "provenance": {},
  "created_by": {},
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "missing_content": [
    {
      "party": "buyer",
      "field": "name",
      "basis": "string",
      "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "source_file": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "ic": {
    "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "role": "mirror",
    "status": "string",
    "partner_entity": "string",
    "other_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "lines": [
    {
      "line_no": 1,
      "description": "string",
      "quantity": "string",
      "creditable_quantity": "string",
      "creditable_tax_amount": "string",
      "creditable_discount_amount": "string",
      "unit_price": "string",
      "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "obligation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sales_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "credits_line": 1,
      "delivery_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "goods_returned": false,
      "warehouse_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "as_credited": false,
      "supply_type": "string",
      "rate_type": "string",
      "tax_category": "string",
      "use_tax": false,
      "vat_scope": "in_scope",
      "vat_scope_reason": "damages",
      "discount_percent": "string",
      "discount_amount": "0.00",
      "document_discount_amount": "0.00",
      "net_amount": "string",
      "tax_rate": "string",
      "tax_amount": "string",
      "tax": {},
      "vat_recovery_percent": "100",
      "tax_fx_net_amount": "string",
      "tax_fx_tax_amount": "string",
      "dimensions": {}
    }
  ],
  "delivery_notes": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string"
    }
  ]
}

GET /v1/documents/{document_id}/allocations

List what settled a document

The payments and credit notes that settled the document (or, for a credit note, what it settled), oldest first. Allocations still waiting for approval are listed with their status; rejected ones too.

Required scope read (admin implies every scope)
Operation id document_allocations_v1_documents__document_id__allocations_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/allocations" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of AllocationOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "credit_note",
    "status": "string",
    "amount": "string",
    "source_amount": "string",
    "source_currency": "string",
    "functional_amount": "string",
    "fx_difference": "string",
    "created_at": "2026-09-21T09:30:00Z",
    "payment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "payment_number": "string",
    "payment_date": "2026-09-21",
    "payment_status": "string",
    "write_off_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "write_off_number": "string",
    "payment_journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "document_number": "string",
    "document_kind": "string",
    "document_date": "2026-09-21",
    "applied_on": "2026-09-21",
    "application_journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  }
]

GET /v1/documents/{document_id}/dispatches

List what was sent of an invoice and how it can be sent

The sent log of an invoice or credit note (when, to whom, which attachments, the Message-ID), oldest first, with what a send would do: whether this server sends e-mail at all (sending_configured), the recipient used without to, allowed_recipients (the customer's own addresses a send may go to), the default format (pdf) and whether the XRechnung XML would be attached. 422 for a document that is not a sales invoice or credit note. The sent log is evidence: it is readable whatever the state of the customer's or the entity's records, and for a draft it is empty (printing and sending, not reading, answer 409).

Required scope read (admin implies every scope)
Operation id document_dispatches_v1_documents__document_id__dispatches_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/dispatches" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK Dispatches
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "sending_configured": true,
  "test_copy": false,
  "suggested_recipient": "string",
  "default_format": "pdf",
  "allowed_recipients": [
    "string"
  ],
  "zugferd_available": true,
  "xrechnung_attached": true,
  "items": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sent_at": "2026-09-21T09:30:00Z",
      "channel": "email",
      "handed_over_on": "2026-09-21",
      "recipients": [
        "string"
      ],
      "subject": "string",
      "message_id": "string",
      "format": "pdf",
      "attachments": [
        null
      ],
      "sent_by": {}
    }
  ]
}

GET /v1/documents/{document_id}/file

Download the original file of a document

The original a document was entered from: the e-invoice XML or PDF, or the PDF or image read by bill capture. 404 when the document has none.

Shown inline only when its bytes are of an allowed type (PDF, PNG, JPEG, WebP, XML without HTML or SVG markup); anything else is an application/octet-stream attachment. Never cached, never embeddable by another site.

Required scope read (admin implies every scope)
Operation id document_file_v1_documents__document_id__file_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
query download boolean true: send as an attachment (download); false (default): inline when the type is safe to show. (default false)

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/file" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 The stored original, byte for byte (SHA-256 in X-Content-SHA256). application/pdf, application/xml, text/xml, image/png, image/jpeg, image/webp
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

GET /v1/documents/{document_id}/files

List the files of a document

Every file stored for an invoice, bill or credit note, oldest first: the original it was entered from (received or captured), its archived outputs (archived_output: the PDF, ZUGFeRD hybrid or XRechnung exactly as they were first output, see GET /v1/documents/{id}/pdf) and the originals attached afterwards (attached). Each file has its SHA-256, who stored it and when. The list is empty for a document without a file; 404 for an unknown document.

Required scope read (admin implies every scope)
Operation id list_files_v1_documents__document_id__files_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/files" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of FileOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "source": "archived_output",
    "variant": "string",
    "stored_by": {},
    "stored_at": "2026-09-21T09:30:00Z"
  }
]

POST /v1/documents/{document_id}/files

Attach a scanned or received original to a document

Add a scanned or received original to a document of any kind and status: a bill that was entered by hand, an open receivable or payable the opening import brought in, a credit note. Send multipart/form-data with the file in the form field file.

Attaching is append-only: nothing is ever replaced or removed, a second file is another attachment, and each one has its own audit event (document.attach, in the document's history) with the file's SHA-256. The file is stored under its content, so the same bytes are stored once. Refused with 422 for an empty file, one over 20 MB or one that is not a PDF or an image by its bytes, 409 when the document already has this file (as its original or an attachment), 404 for an unknown document. A retry with the same Idempotency-Key returns the first answer and attaches nothing more.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id attach_file_v1_documents__document_id__files_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

multipart/form-data (required): Body_attach_file_v1_documents__document_id__files_post

Field Type Required Description
file string yes The original: a PDF, PNG, JPEG or WebP file, at most 20 MB. Its type is read from its bytes, whatever its name or declared type.

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/files" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@statement.xml"

Responses

Status Meaning Body
201 Created FileOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "string",
  "content_type": "string",
  "size": 1,
  "sha256": "string",
  "source": "archived_output",
  "variant": "string",
  "stored_by": {},
  "stored_at": "2026-09-21T09:30:00Z"
}

GET /v1/documents/{document_id}/files/{file_id}

Download a file of a document

One file of the document: its original, an archived output or an attachment, byte for byte. Shown inline only when its bytes are of an allowed type (as for GET /v1/documents/{id}/file); never cached, never embeddable by another site. 404 when the document has no such file, 409 when the stored bytes no longer match their SHA-256. An archived output is served whatever the state of the customer's records now.

Required scope read (admin implies every scope)
Operation id download_file_v1_documents__document_id__files__file_id__get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
path file_id string (uuid) yes Id of a stored file (GET /v1/documents/{document_id}/files).
query download boolean true: send as an attachment (download); false (default): inline when the type is safe to show. (default false)

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/files/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 The stored file, byte for byte (SHA-256 in X-Content-SHA256). application/pdf, application/xml, text/xml, image/png, image/jpeg, image/webp, application/octet-stream
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

GET /v1/documents/{document_id}/history

Get the history of a document

Audit events of the document, its journal entries (submissions, approvals, rejections, also of earlier attempts) and its stored files (original, archived outputs, attachments), oldest first.

Required scope read (admin implies every scope)
Operation id document_history_v1_documents__document_id__history_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/history" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of AuditEventOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": 1,
    "at": "2026-09-21T09:30:00Z",
    "actor": {},
    "action": "string",
    "object_type": "string",
    "object_id": "string",
    "request_id": "string",
    "idempotency_key": "string",
    "data": {}
  }
]

POST /v1/documents/{document_id}/mark-sent

Record that an invoice or credit note was handed over

Record that a person handed the invoice or credit note to the customer outside this system: they e-mailed the downloaded PDF from their own mailbox, posted it, or put it on the customer's portal. Nothing is sent. The sent log (GET .../dispatches) and the document's history get a row with the channel, the recipient, the day it was handed over and the SHA-256 of the archived file that was handed over: file_id names it (an archived output of GET .../files); omitted, it is the invoice PDF, which is archived now if it was never output (then the content gate applies as for the PDF). Marking is repeatable: each call is another hand-over.

Only a person records: the approval policy action send_document is denied to agents by default (403 policy_denied), and an agent key answers 403 whatever the policy says. 404 for an unknown document or file_id, 409 when the document is not posted (or, without file_id, the content gate refuses the PDF), 422 for a document that is not a sales invoice or credit note, a day before the document's date or in the future. A retry with the same Idempotency-Key returns the first answer and records nothing more.

Required scope post (admin implies every scope)
Idempotency-Key required
Operation id mark_sent_v1_documents__document_id__mark_sent_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): MarkSentInput

Field Type Required Description
channel "email" | "other" | "portal" | "post" yes How it was handed over: email (a person sent the downloaded file from their own mailbox), post, portal (the customer's portal) or other.
recipient string yes Who got it: an e-mail address, a name or a portal, up to 200 characters. (min length 1; max length 200)
handed_over_on string (date) yes The day it was handed over (ISO 8601): not before the document date and not in the future.
file_id string (uuid) or null The archived output that was handed over (source archived_output in GET /v1/documents/{id}/files). Omitted: the invoice PDF, which is archived now if it was never output.

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/mark-sent" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "channel": "email",
  "handed_over_on": "2026-09-22",
  "recipient": "buchhaltung@matter-treuhand.example"
}'

Responses

Status Meaning Body
201 Created DispatchOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "sent_at": "2026-09-21T09:30:00Z",
  "channel": "email",
  "handed_over_on": "2026-09-21",
  "recipients": [
    "string"
  ],
  "subject": "string",
  "message_id": "string",
  "format": "pdf",
  "attachments": [
    {
      "filename": "string",
      "content_type": "string",
      "size": 1,
      "sha256": "string"
    }
  ],
  "sent_by": {}
}

GET /v1/documents/{document_id}/pdf

Download an invoice or credit note as PDF

The invoice or credit note as an A4 PDF: the entity's name, address, VAT number and bank account, the customer's address and references (customer number, buyer reference, purchase order), the lines with VAT, the VAT per rate, the totals, payment terms with a cash discount, and the notes. The labels and the way numbers and dates are written follow the customer's language. A Swiss entity's invoice that is not settled gets the Swiss QR-bill payment part (on the last page, or on a page of its own when it does not fit). In a test copy every page says it is a test copy and not valid, there is no QR-bill, and format=zugferd is refused (409, ADR-0039).

Archived as issued. The first time an output is asked for, its exact bytes are stored with their SHA-256 and linked to the document (GET /v1/documents/{id}/files, source archived_output). Every later request for the same output (the same format and the same language, qr_bill and profile, an omitted language being the customer's language) returns those bytes and renders nothing, so an auditor gets what the customer got, also after the customer's address was corrected or the invoice was paid. Another language, qr_bill or profile is another output, archived the same way. A stored output is returned even when the records lack content the law requires now (the gate decides the first output only). The first output needs the post scope and an organization that is not suspended: anyone else (a viewer, an auditor) gets 409 not_issued until a person who may post has downloaded it; what is archived is read with read. 422 for a document that is not a sales invoice or credit note (and for format=zugferd of a non-German entity or an invoice that breaks an EN 16931 rule); 409 when the document is not posted, and 409 invoice_content_incomplete when the entity's or the customer's record lacks content the law requires on an invoice (name, place or address, VAT number: Art. 26 MWSTG, § 14 UStG): missing lists each field with its legal basis and the record to complete, and missing_content on the document says it beforehand.

Required scope read (admin implies every scope)
Operation id document_pdf_v1_documents__document_id__pdf_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
query format "pdf" | "zugferd" pdf (default): the invoice PDF; zugferd: the hybrid PDF with the EN 16931 invoice embedded as factur-x.xml (ZUGFeRD / Factur-X; German entities). Not yet verified for PDF/A-3: no PDF/A validator runs in CI (backlog B-55). (default "pdf")
query profile "en16931" | "xrechnung" With format=zugferd: the profile of the embedded XML, en16931 (EN 16931, default) or xrechnung (XRechnung 3.0; refused when it breaks an XRechnung rule, e.g. a missing buyer reference). (default "en16931")
query language "de" | "en" | "fr" | "it" | "sv" or null Language of the labels and dates: de, fr, it, en or sv. Omitted: the customer's language, else the language of its country.
query qr_bill boolean Swiss entities, format=pdf: add the QR-bill payment part to an invoice that still has an open amount (false leaves it out). (default true)
query download boolean true: send as an attachment (download); false (default): inline. (default false)

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/pdf" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 The PDF, as archived at its first output (SHA-256 in X-Content-SHA256). application/pdf
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

POST /v1/documents/{document_id}/reopen

Reopen a rejected document

Return a rejected document to draft, to correct it and submit it again (audited with the reason). The rejected journal entry stays in the document's history. Only a rejected document reopens (409 otherwise, also when its vendor invoice number was recorded again on another bill).

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id reopen_document_v1_documents__document_id__reopen_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): DocumentAction

Field Type Required Description
reason string yes Why; kept in the audit trail. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/reopen" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Entered twice by mistake"
}'

Responses

Status Meaning Body
200 OK DocumentOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "withholding_code": "string",
  "withholding_rate": "string",
  "withholding_base": "0.00",
  "withholding_amount": "0.00",
  "creditable_amount": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "kind": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "party_code": "string",
  "party_name": "string",
  "party_status": "string",
  "number": "string",
  "external_number": "string",
  "status": "string",
  "document_date": "2026-09-21",
  "supply_date": "2026-09-21",
  "due_date": "2026-09-21",
  "currency": "string",
  "net_total": "string",
  "tax_total": "string",
  "total": "string",
  "functional_total": "string",
  "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "notes": "string",
  "legal_notes": [
    "string"
  ],
  "payment_iban": "string",
  "payment_reference": "string",
  "buyer_reference": "string",
  "order_reference": "string",
  "open_amount": "string",
  "payment_blocked": false,
  "tax_fx": {},
  "tax_fx_rate": "string",
  "tax_fx_net_total": "string",
  "tax_fx_tax_total": "string",
  "cash_discount_percent": "string",
  "cash_discount_date": "2026-09-21",
  "cash_discount_amount": "string",
  "discount_percent": "string",
  "discount_amount": "0.00",
  "provenance": {},
  "created_by": {},
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "missing_content": [
    {
      "party": "buyer",
      "field": "name",
      "basis": "string",
      "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "source_file": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "ic": {
    "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "role": "mirror",
    "status": "string",
    "partner_entity": "string",
    "other_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "lines": [
    {
      "line_no": 1,
      "description": "string",
      "quantity": "string",
      "creditable_quantity": "string",
      "creditable_tax_amount": "string",
      "creditable_discount_amount": "string",
      "unit_price": "string",
      "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "obligation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sales_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "credits_line": 1,
      "delivery_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "goods_returned": false,
      "warehouse_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "as_credited": false,
      "supply_type": "string",
      "rate_type": "string",
      "tax_category": "string",
      "use_tax": false,
      "vat_scope": "in_scope",
      "vat_scope_reason": "damages",
      "discount_percent": "string",
      "discount_amount": "0.00",
      "document_discount_amount": "0.00",
      "net_amount": "string",
      "tax_rate": "string",
      "tax_amount": "string",
      "tax": {},
      "vat_recovery_percent": "100",
      "tax_fx_net_amount": "string",
      "tax_fx_tax_amount": "string",
      "dimensions": {}
    }
  ],
  "delivery_notes": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string"
    }
  ]
}

POST /v1/documents/{document_id}/send

Send an invoice or credit note by e-mail

E-mail the invoice or credit note to the customer, with the PDF attached, as archived (see GET /v1/documents/{id}/pdf; format is pdf by default; zugferd is the hybrid, not yet verified for PDF/A-3) and, for a German public-sector customer with a Leitweg-ID, the XRechnung XML next to it. The mail goes to to, which may only name the customer's own addresses (its e-invoice address, e-mail address and contacts' e-mail addresses), or without to to the customer's e-invoice or billing address. The answer records what was sent: time, recipients, subject, Message-ID and the attachments with their SHA-256; the same is in the document's sent log and in its history.

Only a person sends: the approval policy action send_document is denied to agents by default (403 policy_denied), and an agent key answers 403 whatever the policy says. 409 when this server has no mail server configured (sending is not configured: download the PDF instead; sending_configured in GET .../dispatches says so beforehand), in a test copy (it never e-mails customers, who may be real ones), or when the document is not posted; 422 when there is no recipient, an address is invalid or is not one of the customer's (add it to the customer first), or the XML breaks a rule; 409 invoice_content_incomplete when the entity's or the customer's record lacks content the law requires (as for the PDF); 429 (rate_limited) beyond the organization's hourly limit of messages (default 60); 502 (mail_failed) when the mail server does not accept the message, in which case nothing is recorded and the request can be repeated. A retry with the same Idempotency-Key returns the first answer and sends nothing.

Required scope post (admin implies every scope)
Idempotency-Key required
Operation id send_document_v1_documents__document_id__send_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): SendInput

Field Type Required Description
to array of string or null Recipient addresses, one to five. Each must be an address of the customer: its e-invoice address (scheme EM), its e-mail address or a contact's e-mail address (allowed_recipients of GET /v1/documents/{id}/dispatches); any other address is refused with 422 until it is added to the customer. Omitted: the customer's e-invoice address if it is an e-mail address, else the e-mail address of a contact whose role says billing or accounting, else the customer's e-mail address. (min items 1; max items 5)
message string or null A text of at most 1,000 characters placed before the standard text of the e-mail. (max length 1000)
format "pdf" | "zugferd" or null pdf (default): the invoice PDF; zugferd: the hybrid PDF with the EN 16931 XML inside (German entities only; not yet verified for PDF/A-3, see docs/engineering/backlog.md B-55).

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/send" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "message": "Please quote the order number when you pay.",
  "to": [
    "buchhaltung@matter-treuhand.example"
  ]
}'

Responses

Status Meaning Body
201 Created DispatchOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError
429 A per-organization limit was reached, e.g. messages sent per hour (rate_limited, with retry_after_seconds). ErrorEnvelope

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "sent_at": "2026-09-21T09:30:00Z",
  "channel": "email",
  "handed_over_on": "2026-09-21",
  "recipients": [
    "string"
  ],
  "subject": "string",
  "message_id": "string",
  "format": "pdf",
  "attachments": [
    {
      "filename": "string",
      "content_type": "string",
      "size": 1,
      "sha256": "string"
    }
  ],
  "sent_by": {}
}

POST /v1/documents/{document_id}/submit

Submit a draft document

Post a draft through the approval policy, or queue it for approval. Only drafts submit (409 otherwise, also when the customer or vendor is still a draft). The submit result's policy is allow (document posted and numbered) or require_approval (status pending_approval, a second person decides); deny answers 403. A bill that quotes a purchase order none of its vendor's in its company waits for a second person whatever the policy allows; the result's reason says why. A credit note is checked again against the document it credits: 409 when it now exceeds that document's open amount, 422 when its lines without an obligation would credit more than the invoice's other lines left (another credit note took it since the draft). With If-Match, only the version you read is submitted (412 if it changed since).

Required scope draft (admin implies every scope)
Idempotency-Key not used
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id submit_document_v1_documents__document_id__submit_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
header If-Match string or null The ETag of the version you read; a changed document answers 412. (max length 200)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/submit" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H 'If-Match: "1"'

Responses

Status Meaning Body
200 OK DocumentResult, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "document": {
    "withholding_code": "string",
    "withholding_rate": "string",
    "withholding_base": "0.00",
    "withholding_amount": "0.00",
    "creditable_amount": "string",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party_code": "string",
    "party_name": "string",
    "party_status": "string",
    "number": "string",
    "external_number": "string",
    "status": "string",
    "document_date": "2026-09-21",
    "supply_date": "2026-09-21",
    "due_date": "2026-09-21",
    "currency": "string",
    "net_total": "string",
    "tax_total": "string",
    "total": "string",
    "functional_total": "string",
    "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "notes": "string",
    "legal_notes": [
      "string"
    ],
    "payment_iban": "string",
    "payment_reference": "string",
    "buyer_reference": "string",
    "order_reference": "string",
    "open_amount": "string",
    "payment_blocked": false,
    "tax_fx": {},
    "tax_fx_rate": "string",
    "tax_fx_net_total": "string",
    "tax_fx_tax_total": "string",
    "cash_discount_percent": "string",
    "cash_discount_date": "2026-09-21",
    "cash_discount_amount": "string",
    "discount_percent": "string",
    "discount_amount": "0.00",
    "provenance": {},
    "created_by": {},
    "created_at": "2026-09-21T09:30:00Z",
    "version": 1,
    "missing_content": [
      {
        "party": null,
        "field": null,
        "basis": null,
        "record_id": null
      }
    ],
    "source_file": {
      "id": null,
      "kind": null,
      "filename": null,
      "content_type": null,
      "size": null,
      "sha256": null,
      "created_at": null
    },
    "ic": {
      "link_id": null,
      "role": null,
      "status": null,
      "partner_entity": null,
      "other_document_id": null
    },
    "lines": [
      {
        "line_no": null,
        "description": null,
        "quantity": null,
        "creditable_quantity": null,
        "creditable_tax_amount": null,
        "creditable_discount_amount": null,
        "unit_price": null,
        "account_id": null,
        "product_id": null,
        "obligation_id": null,
        "sales_line_id": null,
        "credits_line": null,
        "delivery_line_id": null,
        "goods_returned": null,
        "warehouse_id": null,
        "as_credited": null,
        "supply_type": null,
        "rate_type": null,
        "tax_category": null,
        "use_tax": null,
        "vat_scope": null,
        "vat_scope_reason": null,
        "discount_percent": null,
        "discount_amount": null,
        "document_discount_amount": null,
        "net_amount": null,
        "tax_rate": null,
        "tax_amount": null,
        "tax": null,
        "vat_recovery_percent": null,
        "tax_fx_net_amount": null,
        "tax_fx_tax_amount": null,
        "dimensions": null
      }
    ],
    "delivery_notes": [
      {
        "id": null,
        "number": null
      }
    ]
  },
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": null,
      "reason": null,
      "rule_id": null,
      "table_id": null
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

POST /v1/documents/{document_id}/void

Void a draft document

Void a draft: it keeps no number, posts nothing and can no longer change (409 for any other status; 412 when If-Match names a version that is no longer current). A vendor invoice number or file of a void bill can be entered again.

Required scope draft (admin implies every scope)
Idempotency-Key required
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id void_document_v1_documents__document_id__void_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.
header If-Match string or null The ETag of the version you read; a changed document answers 412. (max length 200)

Request body

application/json (required): DocumentAction

Field Type Required Description
reason string yes Why; kept in the audit trail. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/void" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Entered twice by mistake"
}'

Responses

Status Meaning Body
200 OK DocumentOut, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "withholding_code": "string",
  "withholding_rate": "string",
  "withholding_base": "0.00",
  "withholding_amount": "0.00",
  "creditable_amount": "string",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "kind": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "party_code": "string",
  "party_name": "string",
  "party_status": "string",
  "number": "string",
  "external_number": "string",
  "status": "string",
  "document_date": "2026-09-21",
  "supply_date": "2026-09-21",
  "due_date": "2026-09-21",
  "currency": "string",
  "net_total": "string",
  "tax_total": "string",
  "total": "string",
  "functional_total": "string",
  "credits_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "source_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "notes": "string",
  "legal_notes": [
    "string"
  ],
  "payment_iban": "string",
  "payment_reference": "string",
  "buyer_reference": "string",
  "order_reference": "string",
  "open_amount": "string",
  "payment_blocked": false,
  "tax_fx": {},
  "tax_fx_rate": "string",
  "tax_fx_net_total": "string",
  "tax_fx_tax_total": "string",
  "cash_discount_percent": "string",
  "cash_discount_date": "2026-09-21",
  "cash_discount_amount": "string",
  "discount_percent": "string",
  "discount_amount": "0.00",
  "provenance": {},
  "created_by": {},
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "missing_content": [
    {
      "party": "buyer",
      "field": "name",
      "basis": "string",
      "record_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "source_file": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "string",
    "filename": "string",
    "content_type": "string",
    "size": 1,
    "sha256": "string",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "ic": {
    "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "role": "mirror",
    "status": "string",
    "partner_entity": "string",
    "other_document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "lines": [
    {
      "line_no": 1,
      "description": "string",
      "quantity": "string",
      "creditable_quantity": "string",
      "creditable_tax_amount": "string",
      "creditable_discount_amount": "string",
      "unit_price": "string",
      "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "obligation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "sales_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "credits_line": 1,
      "delivery_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "goods_returned": false,
      "warehouse_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "as_credited": false,
      "supply_type": "string",
      "rate_type": "string",
      "tax_category": "string",
      "use_tax": false,
      "vat_scope": "in_scope",
      "vat_scope_reason": "damages",
      "discount_percent": "string",
      "discount_amount": "0.00",
      "document_discount_amount": "0.00",
      "net_amount": "string",
      "tax_rate": "string",
      "tax_amount": "string",
      "tax": {},
      "vat_recovery_percent": "100",
      "tax_fx_net_amount": "string",
      "tax_fx_tax_amount": "string",
      "dimensions": {}
    }
  ],
  "delivery_notes": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string"
    }
  ]
}

POST /v1/documents/{document_id}/write-off

Write off what is open on a customer invoice

Write off all or part of what is open on a posted sales invoice the customer will not pay.

An internal entry, not a credit note: nothing goes to the customer. It credits the receivable and debits the bad-debt account (role bad_debt_expense): with vat_treatment=correct the output VAT on the amount is corrected too (the loss is final) and the VAT return shows the reduction like a credit note's; with keep the whole amount goes to the bad-debt account. A foreign-currency invoice is written off at the rate it is carried at. It always waits for a second person (submit.status pending_approval, decided on Approvals); meanwhile it reserves its amount on the invoice. Refused: 404 for an unknown invoice; 422 when it is not a posted customer invoice (write_off_not_invoice), nothing is open (write_off_nothing_open), the amount exceeds what is open (more_than_open), the date is after today (write_off_in_future) or before the invoice or its latest settlement (write_off_before_settlement), the VAT is to be kept on the cash basis (write_off_keep_cash_basis: no VAT is owed on money never received), or the chart has no bad-debt account (role_missing); 409 when the period is closed or the customer is blocked.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id write_off_v1_documents__document_id__write_off_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): WriteOffInput

Field Type Required Description
write_off_date string (date) yes The day of the write-off (ISO 8601): on or after the invoice and its latest settlement, not after today, in an open period.
amount decimal string or null What to write off, VAT included, in the invoice's currency; at most what is open. Default: all of what is open. (greater than 0)
vat_treatment "correct" | "keep" yes correct: the loss is final (bankruptcy closed, nothing more to collect), so the output VAT on the amount is corrected now and the VAT return of the period shows the reduction; keep: the loss is not final yet, the VAT stays owed and the whole amount goes to the bad-debt account (its VAT can be corrected later, once the loss is final). A company that reports VAT when paid (cash basis) always corrects: no VAT is owed on money never received, so keep is refused there (write_off_keep_cash_basis).
reason string yes Why the receivable cannot be collected; kept with the write-off and shown to the person who approves it. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/write-off" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "540.50",
  "reason": "Customer bankrupt; the receiver confirmed no dividend.",
  "vat_treatment": "correct",
  "write_off_date": "2026-10-12"
}'

Responses

Status Meaning Body
201 Created WriteOffResult
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "write_off": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "number": "string",
    "entity": "string",
    "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "document_number": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party": "string",
    "write_off_date": "2026-09-21",
    "currency": "string",
    "amount": "string",
    "vat_treatment": "correct",
    "tax_amount": "string",
    "functional_amount": "string",
    "reason": "string",
    "status": "pending_approval",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "created_at": "2026-09-21T09:30:00Z",
    "recovered": "0.00",
    "vat_corrected_later": false,
    "follow_ups": [
      {
        "id": null,
        "write_off_id": null,
        "kind": null,
        "follow_up_date": null,
        "currency": null,
        "amount": null,
        "tax_amount": null,
        "bank_account": null,
        "note": null,
        "status": null,
        "journal_entry_id": null,
        "created_at": null
      }
    ]
  },
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

POST /v1/documents/{document_id}/write-off/recovery

Book money received after a write-off

The customer paid all or part of a written-off invoice after all. The invoice stays written off; the entry debits the bank account and credits the bad-debt account (a recovery). Where the write-off corrected the output VAT (now or later), the VAT is owed again in proportion to what was received (CH MWSTG Art. 41, DE UStG § 17 Abs. 2): the VAT return of the period shows it like a sale. Submitted under the approval policy (submit.status posted or pending_approval). Refused: 404 for an unknown invoice or write-off of it; 422 when the write-off is not posted (write_off_not_posted), the amount is more than what is written off and not received yet (recovery_more_than_written_off), the date is after today (follow_up_in_future) or before the write-off (follow_up_before_write_off), or the account is no bank account (not_a_bank_account); 409 while something else booked on the write-off waits for approval (write_off_follow_up_waiting) or when the period is closed.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id write_off_recovery_v1_documents__document_id__write_off_recovery_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): RecoveryInput

Field Type Required Description
write_off_id string (uuid) yes The posted write-off of the invoice the money is for.
recovery_date string (date) yes The day the money arrived (ISO 8601): on or after the write-off, not after today, in an open period.
amount decimal string yes What was received, VAT included, in the invoice's currency; at most what is written off and not received yet. (greater than 0)
bank_account string or null Code of the bank account the money arrived on; default: the main bank account for the invoice's currency.
note string or null Free text, e.g. where the money came from. (max length 500)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/write-off/recovery" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "200.00",
  "bank_account": "1020",
  "note": "First dividend from the bankruptcy office.",
  "recovery_date": "2026-11-20",
  "write_off_id": "0f6b6a3e-5d7c-4b8e-9a51-2f4c1d0e7a90"
}'

Responses

Status Meaning Body
201 Created FollowUpResult
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "follow_up": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "write_off_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "recovery",
    "follow_up_date": "2026-09-21",
    "currency": "string",
    "amount": "string",
    "tax_amount": "string",
    "bank_account": "string",
    "note": "string",
    "status": "pending_approval",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

POST /v1/documents/{document_id}/write-off/vat-correction

Correct the VAT a write-off kept

The loss of a write-off that kept the VAT (vat_treatment=keep) is final now: the output VAT on what is written off and was not received after all is corrected, dated the day the loss became final, as a write-off that corrects it at once would have (CH MWSTG Art. 41, DE UStG § 17 Abs. 2). Its VAT lines go back to the VAT accounts with their tax tags; the bad-debt account is relieved by as much. Submitted under the approval policy. Refused: 404 for an unknown invoice or write-off of it; 422 when the write-off is not posted (write_off_not_posted), its VAT is corrected already (write_off_vat_corrected), everything was received after all (write_off_all_recovered) or the date is after today or before the write-off (follow_up_in_future, follow_up_before_write_off); 409 while something else booked on the write-off waits for approval (write_off_follow_up_waiting).

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id write_off_vat_correction_v1_documents__document_id__write_off_vat_correction_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): VatCorrectionInput

Field Type Required Description
write_off_id string (uuid) yes The posted write-off whose VAT was kept, now that the loss is final.
correction_date string (date) yes The day the loss became final (ISO 8601): on or after the write-off, not after today, in an open period.
note string or null Why the loss is final now. (max length 500)

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/write-off/vat-correction" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "correction_date": "2026-12-15",
  "note": "Bankruptcy closed; certificate of loss received.",
  "write_off_id": "0f6b6a3e-5d7c-4b8e-9a51-2f4c1d0e7a90"
}'

Responses

Status Meaning Body
201 Created FollowUpResult
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "follow_up": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "write_off_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "kind": "recovery",
    "follow_up_date": "2026-09-21",
    "currency": "string",
    "amount": "string",
    "tax_amount": "string",
    "bank_account": "string",
    "note": "string",
    "status": "pending_approval",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "created_at": "2026-09-21T09:30:00Z"
  },
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

GET /v1/documents/{document_id}/write-offs

List the write-offs of an invoice

The write-offs of the invoice, oldest first, with their reason, VAT treatment and status (waiting ones and rejected ones too).

Required scope read (admin implies every scope)
Operation id document_write_offs_v1_documents__document_id__write_offs_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/write-offs" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of WriteOffOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "number": "string",
    "entity": "string",
    "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "document_number": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party": "string",
    "write_off_date": "2026-09-21",
    "currency": "string",
    "amount": "string",
    "vat_treatment": "correct",
    "tax_amount": "string",
    "functional_amount": "string",
    "reason": "string",
    "status": "pending_approval",
    "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "created_at": "2026-09-21T09:30:00Z",
    "recovered": "0.00",
    "vat_corrected_later": false,
    "follow_ups": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "write_off_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "kind": "recovery",
        "follow_up_date": "2026-09-21",
        "currency": "string",
        "amount": "string",
        "tax_amount": "string",
        "bank_account": null,
        "note": null,
        "status": "pending_approval",
        "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "created_at": "2026-09-21T09:30:00Z"
      }
    ]
  }
]

GET /v1/entities/{entity}/invoice-content

What an invoice must show about the seller and the customer

The fields of the company profile (seller) and of a customer's record (buyer) that an invoice of this entity must show by the law of its country, each with its legal basis and whether every invoice needs it or only some. The same rules decide missing_content on a document and refuse to print or send one that lacks them.

Required scope read (admin implies every scope)
Operation id get_invoice_content_v1_entities__entity__invoice_content_get

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).

Example request

curl "$ERP_URL/v1/entities/CH01/invoice-content" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK InvoiceContentOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "country": "string",
  "seller": [
    {
      "field": "name",
      "basis": "string",
      "always": true
    }
  ],
  "buyer": [
    {
      "field": "name",
      "basis": "string",
      "always": true
    }
  ]
}

GET /v1/entities/{entity}/vat-rate-types

List the VAT rate types a document line can choose

The rate types the entity's VAT area has in force on the day (Germany has no super_reduced, France no zero), standard first, each with its rates and what they apply to (categories), from data-vNext. A line sends the type as rate_type; where a type has several rates or kinds of exemption (category_needed: France reduced 5.5 % for books and 10 % for restaurants, the Swiss exemptions), it also sends one of the rate's categories as tax_category. A line of another type, or one that needs a category and names none, is refused (tax_rate_type_missing, tax_category_needed).

Required scope read (admin implies every scope)
Operation id vat_rate_types_v1_entities__entity__vat_rate_types_get

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query date string (date) or null The day (ISO 8601) the rates are in force, usually the document date. Defaults to today where the entity is.

Example request

curl "$ERP_URL/v1/entities/CH01/vat-rate-types" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK VatRateTypes
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "entity": "string",
  "jurisdiction": "string",
  "date": "2026-09-21",
  "rate_types": [
    {
      "rate_type": "exempt",
      "rates": [
        null
      ],
      "category_needed": true
    }
  ]
}

Schemas

AllocationOut

What settled a document, or what a credit note settled.

Field Type Required Description
id string (uuid) yes Id of the allocation.
kind "credit_note" | "credited_document" | "payment" | "write_off" yes payment: a payment or receipt; credit_note: a credit note applied to this document; credited_document: the invoice or bill this credit note settles; write_off: a write-off of the invoice as uncollectable (dated applied_on).
status string yes pending (the payment waits for approval), posted, rejected or reversed (the payment was reversed: it settled the document from its date to the reversal's and settles nothing now).
amount string yes Amount applied to the document, in the document currency.
source_amount string or null The same settlement on the other side, in its own currency (source_currency): what the payment received or paid for it, or what the credit note (or the credited document) took. Null when that side is in this document's currency.
source_currency string or null The currency of the payment, credit note or credited document, when it is not this document's.
functional_amount string yes This document's carrying amount relieved, in the functional currency (on a credit note applied later, the credit note's own, which may differ from the document's it settled).
fx_difference string yes Share of the realised FX gain (positive) or loss (negative), in the functional currency.
created_at string (date-time) yes When the allocation was created (UTC).
payment_id string (uuid) or null Payment allocations: id of the payment or receipt.
payment_number string or null Payment allocations: its number, e.g. PAY-2026-000001.
payment_date string (date) or null Payment allocations: its date.
payment_status string or null Payment allocations: its status.
write_off_id string (uuid) or null A write-off: its id.
write_off_number string or null A write-off: its number.
payment_journal_entry_id string (uuid) or null Payment allocations: its journal entry, once posted.
document_id string (uuid) or null The credit note, or the credited document.
document_number string or null Number of the credit note or credited document.
document_kind string or null Kind of that document.
document_date string (date) or null Date of that document.
applied_on string (date) or null An application made later (ADR-0045): the day it took effect, not the payment's or credit note's own date.
application_journal_entry_id string (uuid) or null An application made later: its own journal entry, once posted (the payment's entry booked the amount on account, not this settlement).

AttachmentOut

Field Type Required Description
filename string yes File name of the attachment, e.g. INV-2026-000001.pdf.
content_type string yes Media type, e.g. application/pdf.
size integer yes Size in bytes.
sha256 string yes SHA-256 of the attached bytes, hex.

Body_attach_file_v1_documents__document_id__files_post

Field Type Required Description
file string yes The original: a PDF, PNG, JPEG or WebP file, at most 20 MB. Its type is read from its bytes, whatever its name or declared type.

DispatchOut

Field Type Required Description
id string (uuid) yes Id of the dispatch.
document_id string (uuid) yes Id of the invoice or credit note that was sent.
sent_at string (date-time) yes When the mail server accepted the message, or when a person recorded the hand-over (UTC).
channel "email" | "other" | "portal" | "post" | "system_email" yes system_email (this server sent it) or what a person recorded: email, post, portal, other.
handed_over_on string (date) or null yes The day a person says it was handed over; null for a message of this server.
recipients array of string yes The addresses it was sent to, or the recipient a person recorded.
subject string or null yes Subject line of the e-mail; null for a recorded hand-over.
message_id string or null yes The Message-ID header, to find the mail in a mailbox; null for a recorded hand-over.
format "pdf" | "xrechnung" | "zugferd" yes pdf, zugferd or xrechnung: the form of the file handed over.
attachments array of AttachmentOut yes What was handed over, with each file's SHA-256: for a message of this server the PDF and, for a German public-sector customer with a Leitweg-ID, the XRechnung XML; for a recorded hand-over the archived file.
sent_by object yes The actor (type, id) that sent it.

Dispatches

How an invoice can be delivered, and what was already sent.

Field Type Required Description
sending_configured boolean yes false when this deployment has no mail server, or this is a test copy: POST .../send answers 409, and the document is delivered by downloading the PDF.
test_copy boolean true in a test copy (POST /v1/test-copies): it never e-mails customers, who may be real ones copied from the organization it was made from. (default false)
suggested_recipient string or null yes The address a send without to would use; null when the customer has none.
default_format "pdf" | "zugferd" yes The format a send without format uses: pdf (ZUGFeRD stays available on request until the hybrid is validated as PDF/A-3).
allowed_recipients array of string yes The addresses a send may go to: the customer's e-invoice address, e-mail address and contacts' e-mail addresses. Add an address to the customer to use it.
zugferd_available boolean yes true when the invoice can be output as ZUGFeRD / Factur-X (German entity).
xrechnung_attached boolean yes true when a send also attaches the XRechnung XML (German entity, customer with a Leitweg-ID).
items array of DispatchOut yes What was sent, oldest first.

DocumentAction

Field Type Required Description
reason string yes Why; kept in the audit trail. (min length 1; max length 500)

DocumentInput

Field Type Required Description
entity string yes Code (or id) of the entity the document belongs to, e.g. CH01.
kind "purchase_bill" | "purchase_credit_note" | "sales_credit_note" | "sales_invoice" yes sales_invoice, sales_credit_note, purchase_bill or purchase_credit_note; the sales kinds take a customer as party, the purchase kinds a vendor.
party string yes Customer or vendor code (or id).
document_date string (date) or null Document date (ISO 8601, e.g. 2026-09-15): the invoice date. It must fall in an open period for the document to be posted. It is the tax point unless supply_date moves it; the VAT rates are those of the date of supply (a credit note takes the rates of the document it credits). Sales invoices and credit notes: default today where the company is. Bills and vendor credit notes: required, the date the vendor printed on it (422 document_date_required).
supply_date string (date) or null The date of supply (ISO 8601): when the goods were delivered or the service was performed (Leistungsdatum, date de livraison, data di effettuazione), printed on the invoice; omitted or null: the document date. Where the law of the company's country makes VAT due with the supply (DE, ES, GB; FR and IT for goods), the VAT is reported in the period of the supply, and the VAT rate and the official VAT exchange rate are those of the supply. An invoice issued before the supply (an advance invoice) is reported with its own date. A credit note is reported with its own date whatever its date of supply. Switzerland: VAT is due with the invoice (Art. 40 MWSTG).
due_date string (date) or null Due date (ISO 8601). Default: the document date plus the party's payment_terms_days, moved by due_date_convention if given.
currency string or null ISO 4217 code of the document currency, e.g. EUR; default: the party's currency (a credit note takes the currency of the document it credits). (pattern ^[A-Z]{3}$)
external_number string or null Vendor's invoice number.
credits string (uuid) or null Document this credit note corrects.
notes string or null Free text kept on the document.
lines array of DocumentLineInput The document's lines. At least one, except on a credit note with credits set, which then copies the quantities remaining after posted and pending credits. Price corrections or credits without a line link may require explicit lines.
source_document_id string (uuid) or null Id of the stored original file (e-invoice or captured bill) the document was entered from; shown as source_file and downloadable with GET /v1/documents/{id}/file.
provenance object Free-form object stored with the document, e.g. where the data came from. The server adds the reference-data versions and warnings. On a vendor document, vendor_vat_ids (a list) gives the VAT ids the document shows: the seller's (BT-31) and its tax representative's (BT-63); one of the company's VAT area tells that VAT the vendor printed may be the company's own VAT, not foreign VAT.
payment_iban string or null Bills: the account to pay if not the vendor's IBAN, e.g. a QR-IBAN.
payment_reference string or null Bills: the QR reference or ISO 11649 creditor reference to quote.
due_date_convention "following" | "modified_following" | "modified_preceding" | "preceding" or null Roll a due date computed from the payment terms onto a business day of the entity's country payment calendar (CH: SIC, euro area: TARGET), e.g. 'following'. Ignored when due_date is given.
buyer_reference string or null Invoices: the buyer's reference (XRechnung BT-10); defaults to the customer's Leitweg-ID.
cash_discount_percent decimal string or null Cash discount (Skonto) percent if paid within cash_discount_days, e.g. 2. Default: the party's; 0 for none. (min 0)
cash_discount_days integer or null Days from the document date within which the cash discount may be taken, 0 to 365. Give this or cash_discount_date, not both. (min 0; max 365)
cash_discount_date string (date) or null Instead of days.
order_reference string or null Buyer's PO number (BT-13).
discount_percent decimal string or null A discount on the whole document, in percent of the lines after their own discounts (above 0, at most 100). It is split over the lines by what each is worth, so the VAT of each rate goes down by its share. Give this or discount_amount, not both. (max 100; greater than 0)
discount_amount decimal string or null A discount on the whole document as an amount in its currency, at most what the lines are worth after their own discounts; split over the lines like discount_percent. On a credit note too, only the document discount it gives applies: the share of the credited document's discount comes with each line that credits a line as it was, in that line's own discount (credits_line). (greater than 0)

DocumentResult

Field Type Required Description
document DocumentOut yes The document as stored.
submit SubmitResult or null yes How the submission went (policy: allow or require_approval, entry id, approval_id); null when the document was created with submit=false.

DocumentUpdate

Changes to a draft. Omitted fields keep their value; null clears an optional one.

lines replaces every line. The tax of every line is determined again, also when only the party or the date changes. Without due_date, a new date or party recomputes the due date from the payment terms; without currency, a new party brings its currency.

Field Type Required Description
party string or null Customer or vendor code (or id).
document_date string (date) or null New document date (ISO 8601); the due date follows unless given. null is refused.
supply_date string (date) or null The date of supply (ISO 8601): when the goods were delivered or the service was performed (Leistungsdatum, date de livraison, data di effettuazione), printed on the invoice; omitted or null: the document date. Where the law of the company's country makes VAT due with the supply (DE, ES, GB; FR and IT for goods), the VAT is reported in the period of the supply, and the VAT rate and the official VAT exchange rate are those of the supply. An invoice issued before the supply (an advance invoice) is reported with its own date. A credit note is reported with its own date whatever its date of supply. Switzerland: VAT is due with the invoice (Art. 40 MWSTG). null clears it (the document date).
due_date string (date) or null New due date (ISO 8601); null recomputes it from the payment terms.
due_date_convention "following" | "modified_following" | "modified_preceding" | "preceding" or null Moves a due date computed from the payment terms onto a business day of the entity's country calendar (CH: SIC, euro area: TARGET): following, modified_following, preceding or modified_preceding. Ignored when due_date is given.
currency string or null ISO 4217 currency code, e.g. EUR. (pattern ^[A-Z]{3}$)
external_number string or null Vendor's invoice number.
notes string or null Free text kept on the document; null clears it.
lines array of DocumentLineInput or null The new lines; they replace all existing lines (at least one). null or omitted keeps the lines. (min items 1)
payment_iban string or null Bills: the account to pay if it is not the vendor's own IBAN, e.g. a QR-IBAN printed on the bill. It must be one of the vendor's confirmed accounts before a payment to it can be released.
payment_reference string or null Bills: the QR reference (27 digits) or ISO 11649 creditor reference (RF...) printed on the bill, quoted when paying. A QR reference needs a QR-IBAN.
buyer_reference string or null XRechnung BT-10.
order_reference string or null The buyer's purchase order number (EN 16931 BT-13).
cash_discount_percent decimal string or null Cash discount (Skonto) percent; 0 for none. (min 0)
cash_discount_days integer or null Days from the document date within which the cash discount may be taken, 0 to 365. Give this or cash_discount_date, not both. (min 0; max 365)
cash_discount_date string (date) or null Last day the cash discount may be taken (ISO 8601, not before the document date), instead of cash_discount_days.
discount_percent decimal string or null A discount on the whole document in percent; it replaces any document discount. null removes the document discount. (max 100; greater than 0)
discount_amount decimal string or null A discount on the whole document as an amount; it replaces any document discount. null removes the document discount. (greater than 0)

FileOut

A file stored for a document; the bytes are GET /v1/documents/{id}/files/{file_id}.

Field Type Required Description
id string (uuid) yes Id of the stored file.
filename string yes File name, e.g. INV-2026-000001.pdf.
content_type string yes Media type, determined from the bytes.
size integer yes Size in bytes.
sha256 string yes SHA-256 of the file, hex; the download carries it too.
source "archived_output" | "attached" | "captured" | "received" yes Where the file comes from: received (the e-invoice a vendor sent, booked from its data), captured (the PDF or image bill capture read), archived_output (an invoice or credit note exactly as issued: what the customer got) or attached (an original added afterwards).
variant string or null yes Of an archived output: which output it is (pdf-auto-qr, zugferd-en16931-auto, xrechnung); null for the other files.
stored_by object yes The actor (type, id, name) that stored it.
stored_at string (date-time) yes When it was stored (UTC).

FollowUpOut

Money received after a write-off, or the VAT of a kept write-off corrected later.

Field Type Required Description
id string (uuid) yes Id of the follow-up.
write_off_id string (uuid) yes The write-off it follows.
kind "recovery" | "vat_correction" yes recovery (money received after the write-off) or vat_correction (the VAT of a write-off that kept it, corrected once the loss is final).
follow_up_date string (date) yes The day of its entry.
currency string yes ISO 4217 currency of the invoice and the amounts.
amount string yes recovery: what was received; vat_correction: the amount, VAT included, whose VAT is corrected (what is written off less what was received before).
tax_amount string yes recovery: the output VAT owed again on what was received; vat_correction: the output VAT corrected.
bank_account string or null yes recovery: code of the bank account.
note string or null yes Free text.
status "pending_approval" | "posted" | "rejected" yes pending_approval (decided on Approvals), posted or rejected.
journal_entry_id string (uuid) yes Its journal entry.
created_at string (date-time) yes When it was asked for (UTC).

FollowUpResult

Field Type Required Description
follow_up FollowUpOut yes The recovery or the VAT correction.
submit SubmitResult yes How its entry was submitted under the approval policy: posted, or pending_approval with the approval_id a second person decides.

InvoiceContentOut

What the law requires an invoice of this entity to show about its seller and customers.

Field Type Required Description
country string yes The entity's country, whose rules apply.
seller array of InvoiceField yes Fields of the company profile.
buyer array of InvoiceField yes Fields of each customer's record.

InvoiceField

One field of a seller's or customer's record that an invoice of this entity must show.

Field Type Required Description
field "name" | "postal_code" | "street" | "tax_id" | "town" | "vat_designation" | "vat_number" yes The field, as in missing_content: name, street, postal_code, town, vat_number, tax_id (the seller's USt-IdNr or Steuernummer) or vat_designation (a Swiss UID with MWST, TVA or IVA).
basis string yes The legal basis that makes it mandatory.
always boolean yes True: every invoice needs it. False: only some (e.g. an intra-community supply needs the customer's VAT number).

MarkSentInput

An invoice handed over outside the system.

Field Type Required Description
channel "email" | "other" | "portal" | "post" yes How it was handed over: email (a person sent the downloaded file from their own mailbox), post, portal (the customer's portal) or other.
recipient string yes Who got it: an e-mail address, a name or a portal, up to 200 characters. (min length 1; max length 200)
handed_over_on string (date) yes The day it was handed over (ISO 8601): not before the document date and not in the future.
file_id string (uuid) or null The archived output that was handed over (source archived_output in GET /v1/documents/{id}/files). Omitted: the invoice PDF, which is archived now if it was never output.

RecoveryInput

Field Type Required Description
write_off_id string (uuid) yes The posted write-off of the invoice the money is for.
recovery_date string (date) yes The day the money arrived (ISO 8601): on or after the write-off, not after today, in an open period.
amount decimal string yes What was received, VAT included, in the invoice's currency; at most what is written off and not received yet. (greater than 0)
bank_account string or null Code of the bank account the money arrived on; default: the main bank account for the invoice's currency.
note string or null Free text, e.g. where the money came from. (max length 500)

SendInput

Who gets the invoice and in which form. Every field is optional.

Field Type Required Description
to array of string or null Recipient addresses, one to five. Each must be an address of the customer: its e-invoice address (scheme EM), its e-mail address or a contact's e-mail address (allowed_recipients of GET /v1/documents/{id}/dispatches); any other address is refused with 422 until it is added to the customer. Omitted: the customer's e-invoice address if it is an e-mail address, else the e-mail address of a contact whose role says billing or accounting, else the customer's e-mail address. (min items 1; max items 5)
message string or null A text of at most 1,000 characters placed before the standard text of the e-mail. (max length 1000)
format "pdf" | "zugferd" or null pdf (default): the invoice PDF; zugferd: the hybrid PDF with the EN 16931 XML inside (German entities only; not yet verified for PDF/A-3, see docs/engineering/backlog.md B-55).

VatCorrectionInput

Field Type Required Description
write_off_id string (uuid) yes The posted write-off whose VAT was kept, now that the loss is final.
correction_date string (date) yes The day the loss became final (ISO 8601): on or after the write-off, not after today, in an open period.
note string or null Why the loss is final now. (max length 500)

VatRateChoice

Field Type Required Description
series string yes The rate's series in data-vNext, e.g. fr.vat.reduced.
rate string yes Percent, e.g. 5.5; 0 for an exempt supply. (pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$)
categories array of string yes What the rate applies to, in English words, e.g. books. A line names one of them as its tax_category to choose this rate.
description string or null yes The legal basis or a remark; null for none.

VatRateTypeChoice

Field Type Required Description
rate_type "exempt" | "parking" | "reduced" | "special" | "standard" | "super_reduced" | "zero" yes The rate type a line sends as rate_type.
rates array of VatRateChoice yes The rates of the type in force, at least one.
category_needed boolean yes True when the type has several rates (France: reduced 5.5 % and 10 %) or several kinds of exemption (Switzerland): a line of this type must name its tax_category, else the document is refused with tax_category_needed.

VatRateTypes

Field Type Required Description
entity string yes Entity code.
jurisdiction string yes Whose rates these are: the entity's VAT area (Liechtenstein: CH), or its province where it has one (CA-ON).
date string (date) yes The day the rates are in force.
rate_types array of VatRateTypeChoice yes Only the rate types the jurisdiction has on that day, standard first; empty where data-vNext has no rate for it.

WriteOffInput

Field Type Required Description
write_off_date string (date) yes The day of the write-off (ISO 8601): on or after the invoice and its latest settlement, not after today, in an open period.
amount decimal string or null What to write off, VAT included, in the invoice's currency; at most what is open. Default: all of what is open. (greater than 0)
vat_treatment "correct" | "keep" yes correct: the loss is final (bankruptcy closed, nothing more to collect), so the output VAT on the amount is corrected now and the VAT return of the period shows the reduction; keep: the loss is not final yet, the VAT stays owed and the whole amount goes to the bad-debt account (its VAT can be corrected later, once the loss is final). A company that reports VAT when paid (cash basis) always corrects: no VAT is owed on money never received, so keep is refused there (write_off_keep_cash_basis).
reason string yes Why the receivable cannot be collected; kept with the write-off and shown to the person who approves it. (min length 1; max length 500)

WriteOffOut

A write-off of all or part of what was open on a sales invoice.

Field Type Required Description
id string (uuid) yes Id of the write-off.
number string or null yes Its number once posted, e.g. WO-2026-000001; none while it waits.
entity string yes Code of the company.
document_id string (uuid) yes Id of the invoice written off.
document_number string or null yes Number of the invoice written off.
party_id string (uuid) yes Id of the customer.
party string yes Name of the customer.
write_off_date string (date) yes The day of the write-off.
currency string yes ISO 4217 currency of the invoice and the amounts.
amount string yes What was written off, VAT included.
vat_treatment "correct" | "keep" yes correct (the VAT on it was corrected) or keep (the VAT stays owed).
tax_amount string yes The output VAT corrected, in the invoice's currency; 0 when kept.
functional_amount string yes What it took off the receivable in the functional currency, at the rate the invoice is carried at.
reason string yes Why it was written off.
status "pending_approval" | "posted" | "rejected" yes pending_approval (a second person decides it on Approvals; until then it reserves its amount on the invoice), posted or rejected.
journal_entry_id string (uuid) yes Its journal entry.
created_at string (date-time) yes When it was asked for (UTC).
recovered string What was received after the write-off (recoveries posted or waiting), in the invoice's currency. (default "0.00")
vat_corrected_later boolean Whether the VAT it kept was corrected later, once the loss was final (a vat_correction follow-up posted or waiting). (default false)
follow_ups array of FollowUpOut Money received after it and the VAT corrected later, oldest first (rejected ones too).

WriteOffResult

Field Type Required Description
write_off WriteOffOut yes The write-off, waiting for a second person.
submit SubmitResult yes How its entry was submitted: always pending_approval, with the approval_id a second person decides.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3