Skip to content

Blog

A barcode is an API call

A scan is not data entry. It is an event with intent, and the code on the label can say exactly which action it means. The scanner is a keyboard, so the keyboard is a scanner.

October 22, 2026 · Long Tail team

Watch someone work a bench with a typical piece of floor software. They pick up an item and scan it. The scan types a serial number into a search box. They wait, then click the result. They click Claim. They do the work. They click Done, then confirm, then scan the next item into the same search box.

The scan was the only fast part, and it was used to fill in a text field.

We think that gets the scanner backwards. A person who points a scanner at a label is not entering data. They are saying something: this item, here, now, and they usually mean one specific thing by it. The software’s job is to hear what they meant and do it, in one gesture, safely.

So in Long Tail, a barcode is an API call.

The code says what it means

A scan code has three parts: version : category : target.

10:1:SN-12345 reads as scheme 10, rule 1, target SN-12345.

The scheme (two digits) says what the target identifies and how the code parses. Scheme 10 might say “the target is a serialNumber”. The scheme binds a printed value to a metadata facet on escalation rows, so the label and the row share a value, and the scan is the join between them.

The rule (one digit) says what scanning this code does. Rule 1 on scheme 10 might be “collect the finished item”. Print the rule’s friendly name beside the code on the label, and the label tells people what it does.

The target is the value itself.

One machine can carry four labels, one per corner, with the same serial and four different rules: send it for service, mark the job done, mark the job failed, take it offline. A person does not choose an action from a menu. They choose a label.

Operators never pick the numbers. They name schemes and rules in the admin screen and the indices are assigned. A deployment that already has manufacturer barcodes on its products can use a gtin scheme instead, which reads UPC and EAN codes as printed, with no version or category at all.

A rule is a small program over the queue

Every unit of work in Long Tail is a row in a role’s queue, with a status, a claim state and metadata facets. That is what makes a scan tractable: the world the scan acts on is small and uniform. A rule is an event, condition, action rule over it:

  • Event: a code arrives.
  • Condition: an ordered list of queries against the queue: which roles, which status, whether the row is available, which facets.
  • Action: the verb of the first step whose query matches.
[
{ "query": { "roles": ["press-fleet"], "status": "pending", "availability": "available",
"facets": { "state": "running" } },
"verb": "resolve",
"params": { "resolverPayload": { "outcome": "complete" } } },
{ "verb": "show-detail" }
]

The verbs are the same ones every other surface uses: open, claim, release, resolve with a canned payload, escalate to another queue, cancel, or add the item to a container.

The ordering is the interesting part. Put the expected state first and a broad show-detail last. When the machine is in the state you expected, the scan acts. When it is not, say it was sent for service an hour ago and nobody told you, the scan falls through and opens the row where the machine actually is. The scan is also a state query. A person learns something even from a scan that did nothing.

One gesture, exactly one transition

A scan that writes needs the same guarantees as a button that writes, and a few more, because two people can scan the same label within a second.

Claims, resolves and cancels run as single-statement operations located by the target facet. The caller’s role scope is part of the same SQL filter as the step’s role guard. Two people scanning the same code at once produce exactly one transition. The second scan reports a conflict or falls through to the locator step. Nothing lands twice.

When a scan needs a person to choose, the present verb shows what is true about the row in the top half of the screen and the allowed choices in the bottom half. The choice comes back to the server as a pointer, and the pointer grants nothing. The server re-reads the config, re-locates the row, re-checks the identity requirement and writes that exact row by id. If the row moved on between render and tap, the answer is a conflict, exactly as with a lost double scan.

Who did it

A shared tablet on a bench belongs to nobody. Long Tail signs it in as a station account that can read the queues it fronts and cannot write anything on its own. Every write takes a badge.

A badge scan mints a short-lived grant, and the acts that follow run as the badged person, under that person’s own live permissions. The grant confers attribution, never privilege. A badge cannot make anyone able to do something their role does not allow. A role sets its stations’ policy: one act per badge at a careful workstation, or ten minutes of acts at a busy packing bench.

Put the item, the badge and the container together, and you get the motion we built the whole feature around. Scan the item: the station holds it and shows, in very large type, where it goes. Scan your badge. Scan the container: the item joins it, and both rows change in one statement. Scan the wrong container and the station says so, names the right one, and writes nothing.

The scanner is a keyboard, so the keyboard is a scanner

Here is the part that surprised people the most.

Almost every barcode scanner, over USB or Bluetooth, pretends to be a keyboard. It types its decode and presses Enter. Most software fights this, with a focused input field and a mode switch. We went the other way.

When scan capture is on, the dashboard listens on every page, whatever has focus. It lets keystrokes accumulate. When Enter arrives, it checks whether the recent keys end in a shape one of your schemes can parse. If they do, it swallows the Enter, removes the code’s characters from whatever field held focus, and runs the code. Cursor focus never diverts a scan.

Codes made only of digits fire only at scanner speed, about 50 milliseconds per key or faster, so a purchase order number typed into a form stays in the form. Scanners with no Enter suffix still work: a full code at scanner speed followed by 300 ms of silence fires on its own.

And because the scanner is a keyboard, the keyboard is a scanner. Type 10:1:SN-12345 anywhere and press Enter, and it runs. That is the contract, not an accident. A supervisor at a desk can act on a machine across the building by typing its label. The header bar goes one step further: pick a rule as a Run mode, type only the target, and press Enter.

Under all of it is one endpoint:

Terminal window
curl -X POST https://lt.acme.dev/api/scan-codes/execute \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{ "code": "10:1:SN-12345" }'

It runs as the caller, under normal RBAC, and every outcome is a structured answer: executed, matched a list, needs confirmation, needs a badge, refused with a reason, or no match with the rule’s fallback text. A camera decode can call it, as can an RFID reader, an MCP agent through execute_scan_code, or a cron job. Anything that can produce a string can drive the floor.

What the label becomes

Once a scan is an API call, the label on an object becomes its interface. It names the object, carries the actions you are allowed to take on it, and connects to the row where its state lives. People stop translating between the thing in their hand and the screen in front of them, because the thing in their hand is the input.

That is the whole idea, and it fits on a sticker.

The scan codes guide has the full rule reference. The one scan, one action and item, badge, container patterns show the motion in its smallest form.