Declared range
You declare from where to where, with its lot and expiry. It works in plants with orderly consumption, under declared responsibility.
Anything you can do from the console you can do from the API, and the other way round. The console is not a privileged shortcut: it calls the same endpoints you do.
There are two steps because a factory works that way: codes are printed while production runs, and the lot’s definitive data only exists once the run ends.
The two steps are a right, not an obligation: an importer that already knows the lot and the expiry can issue and activate in a single call.
Issuing requires an idempotency header. A retry after a dropped connection does not produce a second run or spend the balance twice: it returns exactly the same issuance.
POST /v1/issuances
Generates identifiers for a product. The record is optional:
if lot and expiry are supplied, the issuance is born activated.
POST /v1/issuances/{id}/activate
Completes the record, which is what activates the codes. Four modes:
declared range · scanned bounds · scan session · whole issuance
POST /v1/issuances/{id}/reassign
Corrects the record of a range. It stays in the audit trail.
GET /v1/issuances/{id}/labels
Paginated download, or streaming for large runs. Matching codes to a lot assumes the plant consumed the labels in order, and the physical world mixes rolls up. Hence more than one method.
You declare from where to where, with its lot and expiry. It works in plants with orderly consumption, under declared responsibility.
Opening the run, the label of the first unit is read; closing it, the last one. The system derives the range actually observed and absorbs offsets and waste.
A session is opened for a lot and every code read during it is assigned to it. Assignment stops being an assumption and becomes an observation.
Before dispatch, random units from each pallet are scanned and the assigned record is compared with what is printed. A mis-assigned pallet is caught before it leaves.
In serial mode, a serial repeated within the same product, or a second attempt to bind the same code, is rejected and raises a signal. The reverse index from serial to code is what later enables a per-unit warranty or a surgical recall.
The full specification is published as OpenAPI, and the version lives in the path: what works today keeps working when the next one appears.
GET /v1/verify/{code}
Public lookup: status and passport. Anonymous, rate-limited.
Meant for integrators too: retail chains and customs.
GET /v1/labels/{code}
Looks up one of your own labels, in more detail than the public one.
POST /v1/labels/bind
Serial mode: binds a code to the manufacturer’s serial, 1 to 1.
POST /v1/labels/void
Voids ranges, with a reason. It stays in the audit trail.
Webhooks: issuance.issued · label.alert An issuer’s account authorises the creation of fiscal instruments. The asymmetry with the public is deliberate.
Looking up and reporting require no registration. Contact details in a report are optional and only serve to follow it up.
Corporate email and password with a mandatory second factor, and an optional passkey for anyone who wants phishing resistance. Nobody gets in with a password alone.
An issuer’s identity is corporate. A personal email address should not control an account that issues.
Integrations use an API key with request signing, specific scopes and rotation. Revocable per key and per device.
A fiscal system cannot stop production or trade. That stops being an aspiration and becomes a design requirement.
The range is downloaded once and the local process feeds the printer, with its own queue and consumption reporting when it reconnects.
The lookup has to keep answering even while issuance is under maintenance. They do not share a path.
If the rate limiter degrades, the lookup is served. Writes and authentication, by contrast, fail closed.
The identifier format and the print specifications are in the label reference. If you want to understand why the design makes these calls, the precedents page walks through the systems that tried it first.