For the complete documentation index, see llms.txt. This page is also available as Markdown.

Documents

How documents move through their state machine — transitions, states and references.

Documents (Belege) — offers, orders, delivery notes, invoices, credit notes — are the ERP's central business objects. They are also the object most integrations get wrong, because a document is not a record you edit freely. It is a state machine.

This page explains the model. For endpoint details use the API Reference; for field paths use runtime discovery.

Everything happens through a transition

There is no DELETE /erp/documents/{id}, and no endpoint that sets a state directly. Creating, editing, transferring, cancelling and deleting a document are all transitions:

POST /erp/documents            create — with a transitionId 
PUT  /erp/documents/{id}/states   change state — with a transitionId 
POST /erp/documents/{id}/types    transfer into a follow-up document

A transition is more than "from state A to state B". It is identified by the document category, an optional source category (for takeovers), the transition, the source state (absent = creation) and the target state.

Finding the transition you need

Three questions, three endpoints:

Question
Call

Which documents may I create?

GET /erp/documents/types?qualifiers=SALE&languageCode=de

What can I do with this document right now?

GET /erp/documents/{id}/states

Which follow-up documents can I create from it?

GET /erp/documents/{id}/types

Each entry carries the transitionId you then send, plus typeId, typeLabel, targetState and transitionKey. Of those, transitionKey (the transition's name) is the only human-stable identifier — match on that if you need to recognise a specific transition, and take the transitionId from the same response.

The qualifier narrows the document world; there are only eight, so they are worth knowing: SALE, PURCHASE, COMMISSION, POINT_OF_SALE, SALES_CONTRACT, PURCHASE_CONTRACT, FABRICATION, RMA.

Categories and transitions, by contrast, number in the dozens and hundreds. Their names follow a grammar — categories are prefixed by counterparty (CUSTOMER_ORDER, SUPPLIER_ORDER, POS_*, FABRICATION_*), transitions are either lifecycle verbs (CREATE, BEGIN_EDITING, DELETE, PUBLISH, COPY) or takeovers in X_TO_Y form (OFFER_TO_ORDER, ORDER_TO_DELIVERY, DELIVERY_TO_INVOICE) — but do not work from a list. The valid combinations depend on your installation's configuration; enumerate them.

/{id}/states and /{id}/types are disjoint lists. A takeover into another document type never appears under /states. If a transition you expect is "missing", you are probably asking the wrong endpoint.

Creating a document

Only transitionId is required:

Whether an account is required depends on the category. Ids travel as strings throughout.

Two things to get right in the order you do them:

  • Header fields such as the document date, default storage or report group are set with PATCH /erp/documents/{id}before you add lines.

  • POS documents need posRegisterId and cashDrawerId flat in document at creation time, not nested.

Leave the document number out. It is generated automatically (see below).

What you may change, and when

Every state carries a classification, and that classification — not the state name — decides what is allowed:

Classification
Meaning

EDITABLE

Full edit allowed

INTERNAL_EDITABLE

Only the backend may change it (a workflow is running)

PARTIALLY_TRANSFERRED / TRANSFERRED

Partly or fully taken over into a follow-up

DELETED

Being deleted

A full-body update requires EDITABLE. On a non-editable document, PATCH still works — but only for a small whitelist of fields; anything else is rejected. A document in a workflow state, or deleted, is refused outright.

Writes participate in optimistic locking. The x-get-leasable-lock, x-use-leasable-locks, x-refresh-leasable-locks and x-release-leasable-locks request headers, and x-active-leasable-locks in the response, are part of the contract — respect them when several clients or users touch the same document.

Lines

  • Every line write returns the whole document, not the line.

  • On the document, the collection is called lines.

  • PUT …/line/{lineId} ignores a changed position — it forces the stored one. Use …/move/{position} (1-based) to reorder.

Document texts

Two positions: HEADER_TEXT and FOOTER_TEXT. A text either carries free content or references a text template, and transferableIntoSubsequentDocuments controls whether it survives a takeover.

Texts can be sent at creation, per line, or on the document header via PUT /erp/documents.

Two traps on the header update:

1

Do not include lines

The body must not contain lines — the request is rejected.

2

Send the complete texts array

The texts array is treated as complete. A text you omit is deleted. Read the existing texts first and send them back in full.

When reading, note that deleted texts are included in the response — filter them out.

How documents reference each other

The link lives on the lines, not on the document. A line carries sourceLine pointing at the line it came from; the document-level chain is derived from that.

To show a document's history, use GET /erp/documents/{id}/types/history — a tree of predecessors and successors with number, date, type, state and totals.

Partial delivery

Three line fields express it:

Field
Meaning

quantity

The line's quantity

quantityCommitted

How much has been passed to follow-up documents — can exceed quantity

complete

Whether the line is finally settled

The predecessor's state is then recomputed from those, not set by you: fully taken over → ACCEPTED, partly → PARTIALLY_ACCEPTED, otherwise back to SAVED. While a successor is being edited, the predecessor may show "successor is being edited" instead.

To offer a partial takeover, ask for the open quantities — for example GET /erp/documents/{id}/lines-to-transfer-to-customer-delivery — then send the chosen sourceLineId + quantity pairs in document.lines of the takeover call. That is the only way a reduced (or negative) quantity travels along.

A worked example: order → delivery note

The ORDER_TO_DELIVERY transition accepts a CUSTOMER_ORDER in state SAVED, PARTIALLY_ACCEPTED or PICKING_FINISHED, and produces a delivery note in SAVED with its lines linked back to the order and a fresh document number. Yes — the delivery note is created with reference to the order; that reference is what later drives the order's own state.

Document numbers

They are generated automatically. Each document type has a sequence configuration — typically fully automatic, with a length, a pad character and a prefix expression (for example the short year).

Consequences:

  • Don't send number on create; it is not part of the create body. externalNumber is the field for your reference.

  • A blank number is rejected on save (except for historical imports).

  • Deleting a document returns its number to the pool, so numbers are not strictly monotonic. Don't derive ordering or counts from them.

Sequence configuration and next/last values can be inspected under /cmn/sequencer.

Deleting

Deletion is the DELETE transition, and it is allowed from exactly one state: EDIT. A saved document must first go through BEGIN_EDITING.

It is refused when:

  • active successor documents exist — take them back or cancel them first (references to already-inactive successors are cleaned up silently);

  • open items with movements exist — payments have already been recorded against it.

For documents that must remain on record, use cancellation (CANCELLED) or dissolution (DISSOLVED) instead of deletion — those keep the document and its number.

Querying documents

Sales documents are queried through the document.querySalesDocuments template. It is already scoped — restricted to the sales-side qualifiers and excluding internal POS categories — so you cannot widen it; use the purchase or POS template instead.

Do not guess field paths. Enumerate them:

depth is what walks into relations. To explore an entity's own attributes and relations, use GET /cmn/computed-queries/fields?entityIdentifier=….

The semantics you usually want: a delivery note that is posted but not yet invoiced is one whose state is not ACCEPTED (so SAVED, or PARTIALLY_ACCEPTED when partly invoiced), with lines where complete is false and quantityCommitted is below quantity.

There is no "shipped" flag on a document. The closest things are line-level shipping and delivery dates, and the document's published flag — which means "output has been produced", not "goods have left".

Checklist

  • transitionId fetched at runtime, never cached

  • Right endpoint for the question — /states for state changes, /types for follow-ups

  • Header fields patched before lines are added

  • PUT /erp/documents sent without lines, and with the complete texts array

  • Line paths use the doubled /document segment

  • Number left to the sequencer

  • 301 after deletion handled as success

  • Leasable-lock headers respected

Last updated

Was this helpful?