Scanning from your own hardware
If you are not using a Skuflo tablet or phone, POST /v1/scan is the one endpoint your hardware needs: a scan station token (see Authentication) is locked to one event, produce, stock or dispatch, so a request can never claim to be something it is not.
The scan endpoint
curl -X POST https://api.skuflo.io/v1/scan \
-H "Authorization: Bearer st_live_..." \
-H "Content-Type: application/json" \
-d '{ "barcode": "OAK 7F3K9QZ2", "location": "A3" }'barcode is required. location is only read on a stock station (a rack bay, for example A3), and falls back to the station’s configured default location when left out.client_scan_id is for offline clients: see below.
Full parameter and response reference: POST /v1/scan.
Every outcome
The response is always { ok, outcome, barcode, item, order, ... }. ok and the HTTP status tell you at a glance whether to show a green tick or a red cross; outcome says exactly why.
| Outcome | Status | Meaning |
|---|---|---|
| ok | 200 | Accepted. The piece moved to its next state. |
| duplicate | 200 | This exact scan already happened (same piece, same event), or a replayed client_scan_id. |
| not_found | 409 | The barcode does not match a label in this factory. |
| not_produced | 409 | A stock or dispatch scan arrived before the piece was ever produced. |
| already_dispatched | 409 | The piece has already been loaded; it cannot move again. |
| cancelled | 409 | The order this piece belongs to was cancelled. |
| voided | 409 | This label was voided. A response field replacement_barcode names the piece that replaced it, if any. |
| location_required | 409 | A stock scan needs a rack bay: pass location, or set a default location on the station. |
| bad_location | 409 | The rack bay given does not exist, or is out of range for that rack. |
| test | 200 | The printed hardware test label was scanned. Nothing was touched; this just proves the scanner and the station can talk to each other. |
Offline replay
A phone or handheld that queues scans while it has no signal should generate its own client_scan_idfor every scan (a UUID is fine) and send the same id if that queued scan is ever replayed. The first attempt is recorded normally; every later attempt with the same id comes back as outcome duplicate, with replay: true, so the piece is only ever counted once no matter how many times the network makes you retry.
Barcode normalisation
Whatever a scanner or a keyboard wedge setting actually sends is cleaned up before it is matched against a label, so your hardware does not need to get this exactly right:
- Control characters (carriage return, tab, the FNC1/GS prefix some scanners add) are stripped from anywhere in the payload.
- A leading AIM symbology identifier (for example
]C0or]Q6) is removed. - Our own QR link (
https://skuflo.io/i/<code>orskuflo://i/<code>) is unwrapped to the plain barcode underneath, and URL decoded. - Internal whitespace is collapsed to a single space, and the result is uppercased.
- If a scanner drops the space between the label prefix and the code (for example
OAK7F3K9QZ2), it is reattached when the shape is unambiguous.
In short: send whatever the scanner gives you as the barcode field, raw. There is no need to clean it up on the device first.
The hardware test label
GET /v1/hardware/test-label returns a printable PDF or ZPL label with a fixed code. Scanning it at any station always returns outcome test and never touches an order, so it is safe to use while you are getting a new scanner or a new build of your app talking to Skuflo for the first time.