Number ranges
Three things in the orders app carry a number a human reads: the order, the delivery note, and the return. Each is drawn from a counter the merchant shapes.
Base path: https://api.revenexx.com/v1/orders/number-ranges.
The three seeded ranges
curl -X POST https://api.revenexx.com/v1/orders/number-ranges/defaults \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..." \
-H "Content-Type: application/json" \
-d '{}'
| Code | Numbers | Seeded as |
|---|---|---|
order | Orders | ORD- + six digits, step 1 |
delivery | Delivery notes, drawn by POST /v1/orders/{id}/ship | DEL- + six digits, step 1 |
return | Returns, drawn by POST /v1/orders/{id}/return | RET- + six digits, step 1 |
The app runs this on install, so a fresh tenant needs nothing. Call it by hand after a range was deleted, or to see what a tenant has.
Idempotent: a code that already exists comes back under existing with its format, counter and active flag left as they are, so a merchant who changed the prefix keeps their change. The one thing it writes on an existing range is a standard name the range is missing (title or labels); a name already there is never changed. It answers 200, never 201 — it is a reconcile, not a create.
The shape of a number
{prefix}{counter padded to `padding`}{suffix}
| Field | Meaning |
|---|---|
code | Which counter this is. Unique per tenant, and the value the settings point at. |
title | The range's name, what a list and a breadcrumb show. The fallback for every locale labels does not carry. The three standard ranges are named "Order numbers", "Delivery note numbers" and "Return numbers". A range of the merchant's own has no name until one is given, and a screen shows its code instead. |
labels | The name per locale, keyed by locale code (de, en, …). Falls back to title for a locale that is missing. The standard ranges carry de and en; a standard range created before names existed gets them on the next seed or draw, and a name already there is never overwritten. |
prefix | Literal text in front. ORD- turns counter 123 into ORD-000123. Empty by default. |
suffix | Literal text after — a market or year marker. Empty by default, which is what most merchants use. |
padding | How wide the counter is written, zero-padded. 6 makes 123 into 000123; 0 writes the bare number. Widening it later does not renumber what was already drawn. |
step | How far the counter moves per draw. 1 is consecutive; a larger step is what a merchant chooses who does not want their order volume readable off an invoice. |
counter | The last number drawn — state, not configuration. |
active | Whether numbers may be drawn from this range. true by default. A draw that would use an inactive range is refused with 422 number_range_inactive; it does not fall back to another range. Numbers already issued stay as they are, and seeding the standard ranges never switches an inactive one back on. |
position_step | The gap between the position numbers of a new order: 10 numbers the lines 10, 20, 30, leaving room to slot one in later. Read from the range the market's order_number_range_code names (order by default), and from that range only. |
channel_id | A label. It does not select the range. |
metadata | Free-form. The app stores it and reads nothing out of it. |
GET /v1/orders/number-ranges filters by exact match on id, code, prefix, suffix, padding, counter, step, position_step, title, active, channel_id, created_at and updated_at. The API reference does not list labels or metadata, so do not filter on them. An unknown filter answers 400 unknown_filter.
counter is state
The next draw is counter + step, and it writes the new value back.
counter forward skips numbers. Setting it below its current value is refused with 422 (counter_rewind), so a number is never issued twice. Setting it is a repair, not a configuration.Because a draw writes the counter, updated_at on a range changes on every single order.
channel_id does not select the range
A draw finds the range by code alone, and the unique index on (tenant, code) means one code is one range per tenant. So an order on another channel draws from the same range this one names. channel_id is a label on the row, nothing more.
Adding a range
curl -X POST https://api.revenexx.com/v1/orders/number-ranges \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..." \
-H "Content-Type: application/json" \
-d '{"code":"order_at","prefix":"AT-","padding":6,"step":1}'
A code that is taken answers 409 rather than creating a second counter under the same name. Creating a range renumbers nothing that already exists.
title, labels and active are optional here, and PUT /v1/orders/number-ranges/{id} takes them too. active defaults to true.
Pointing a setting at it
A new range is only used once a setting names it:
| Setting | Drawn by |
|---|---|
order_number_range_code | POST /v1/orders/place |
delivery_number_range_code | POST /v1/orders/{id}/ship |
return_number_range_code | POST /v1/orders/{id}/return |
422. Create the range first, then point the setting at it.Settings resolve per market, so a per-market number range is a per-market setting pointing at a second range — not a channel_id on the range. See Settings.
Routes
| Method and path | What it does |
|---|---|
POST /v1/orders/number-ranges/defaults | Creates any of the three seeded ranges that is missing. A missing standard range is also recreated by the next draw on its own, so call this to see what a tenant has. |
GET /v1/orders/number-ranges/{id} | Reads one range by its id, the uuid and not the code. Reading draws no number and does not move counter. To find the id of a code, use GET /v1/orders/number-ranges?code=order. An unknown id answers 404. |
PUT /v1/orders/number-ranges/{id} | Changes the columns the range accepts: code, prefix, suffix, padding, counter, step, position_step, title, labels, active, channel_id and metadata. The change applies from the next draw only. Moving counter back answers 422 counter_rewind, a code another range holds answers 409, and a body that carries created_at or updated_at answers 400 server_owned_field. |
DELETE /v1/orders/number-ranges/{id} | Removes a range that has never drawn a number. A range whose counter is above 0 answers 409 range_in_use. Numbers already placed keep their values. |
POST /v1/orders/number-ranges adds a range, as shown under Adding a range. code is unique per tenant.