Skip to content

Number ranges

Delivery notes and loans carry a number that is printed on the document. Numbers have to be assigned while offline, so there are two modes: the device formats numbers itself, or it uses numbers it reserved from the server earlier.

A number format is a text with placeholders:

Placeholder Replaced by Device Server
{YYYY} four-digit year yes yes
{YY} two-digit year, 26 yes yes
{MM} two-digit month, 03 yes yes
{DEV} device code yes no, stays as written
{SEQ} counter without padding yes yes
{SEQ:n} counter padded with zeros to n digits (n is 1 or 2 digits); longer counters are not cut yes yes

Other text is copied as it is. Dates are calendar dates in the time zone of the formatter: the device's time zone on the device, the business time zone on the server.

Differences between the reference implementations, which implementers of either side should match:

Case Reference app (device) Reference server
Format without {SEQ} appends the counter: LS gives LS3 no counter: LS gives LS for every number
Several {SEQ} only the first is replaced all are replaced
{DEV} replaced by the device code left as written

Examples, from test-vectors/numbering.json:

Format Date Counter Device code Device result Server result
LS-{YYYY}-{DEV}-{SEQ:4} 2026-03-09 42 B LS-2026-B-0042
{YY}{MM}/{SEQ} 2026-03-09 7 B 2603/7
LS-{YYYY}-{SEQ:5} 2026-10-12 41 LS-2026-00041
LS-{DEV}-{SEQ:3} 2026-10-12 41 LS-{DEV}-041

In device mode (document_template.numbering.mode is device or absent), each device formats numbers from numbering.format (default LS-{YYYY}-{DEV}-{SEQ:4}), its own device code and its own counter.

  • The device code keeps numbers of different devices apart. The reference app defaults it to the first two characters of the node id (3F for node 3F2A9C1B) and lets the user change it. Two devices with the same code can produce the same number; the protocol accepts duplicate numbers.
  • The counter is kept on the device and is not synchronised. It starts at 1 and increases with every number taken. When the format contains {YYYY} or {YY}, it restarts at 1 with the first number of a new calendar year. The user can set the next value in the app.
  • numbering.next in the template is reserved; the reference app neither reads nor writes it.

Device numbers are unique per device but not consecutive across the inventory.

In server mode (numbering.mode is server), numbers come from the server's number range. To number offline, the client reserves numbers in blocks while it is online:

sequenceDiagram
  autonumber
  participant C as Client
  participant S as Server
  Note over C: end of sync round,<br/>template says server numbering,<br/>3 reserved numbers left
  C->>S: POST /lve/v1/number-ranges/delivery_note/reserve {count: 25}
  Note over S: in one transaction: counter for<br/>"delivery_note:2026" += 25
  S-->>C: {key, numbers: [LS-2026-00041 ... LS-2026-00065]}
  Note over C: append to the reserved list
  Note over C: offline: each new delivery note<br/>takes the first reserved number
  Note over C: list empty: fall back to the device format
POST /lve/v1/number-ranges/delivery_note/reserve HTTP/1.1
Authorization: Bearer 7|kM2p...
Content-Type: application/json
{ "count": 25 }
Part Rules
key (path) The number range. [a-z0-9_]+. The only key in version 1 is delivery_note.
count Integer from 1 to 100.
{ "key": "delivery_note", "numbers": ["LS-2026-00041", "LS-2026-00042", "LS-2026-00043"] }

numbers holds exactly count formatted numbers in ascending order.

Status Code When
200 Numbers reserved
401 unauthenticated Token missing or revoked
404 not_found Unknown key
422 validation_failed count missing, not an integer, below 1 or above 100
  • The server hands out every number once, across all devices and users. Concurrent reservations never overlap.
  • Numbers within one response are consecutive. Numbers of the server's counter have no gaps when they are handed out.
  • Reserved numbers belong to the device that reserved them. A device that never uses a number, loses its reserved list (disconnect, reinstall) or loses a response leaves a gap in the printed sequence. The protocol does not return unused numbers.
  • The counter restarts at 1 in every calendar year of the server's business time zone, whatever the format contains. The reference server keeps one counter per key and year (delivery_note:2026) and decides the year in LVE_TIMEZONE (default Europe/Berlin), so a reservation at 00:30 on 1 January in Berlin starts the new year although it is still 31 December in UTC.
  • A server formats numbers with its own format (LVE_DELIVERY_NOTE_FORMAT on the reference server, default LS-{YYYY}-{SEQ:5}). The template's numbering.format is not sent to the server and only applies to device numbering and the fallback.

So that server numbers can be "gapless per year" in practice, devices should reserve small blocks and keep using them up; the reference app reserves 25 at a time.

The reference app:

  • reserves 25 numbers at the end of a sync round when the delivery note template is in server mode and fewer than 5 reserved numbers are left; a failed reservation is ignored and tried again next round,
  • takes reserved numbers oldest first,
  • falls back to device numbering with numbering.format when no reserved number is left,
  • keeps reserved numbers across years (a number reserved in December may be used in January),
  • drops all reserved numbers when it disconnects from the server.

A server without number ranges leaves number_ranges out of features and answers the endpoint with 404. Clients should then use device numbering.

Loans are always numbered on the device, with their own counter and the fixed format UE-{YYYY}-{DEV}-{SEQ:4} (UE for Übergabe, handover), for example UE-2026-3F-0001. The counter restarts every calendar year. There is no server number range for loans in version 1.