Method POST/partner /dispatch /shipments /{shipment_id} /units
The logistics scan: allocate up to 1000 units to a B2B order, one result per unit. Requires the dispatch:write scope.
On this page
This is the logistics scan. You send the units the picker has just put into the box, up to 1000 per call, and each one gets its own result. A call with 1000 units of which 3 are wrong records the 997 others and names the 3. The whole flow is in the guide Tie each unit to its order.
This call can be replayed: a unit already in the order answers
already_in_shipment, never an error, and never a second row.
#
API key in the Authorization header, Bearer format, with the
dispatch:write scope. A key without it gets a 403 whose message names the
missing scope. The plan of the key's brand must include API access, and the
shipment's brand must be on the Compliance + Identity offer.
Authorization: Bearer votre_clef#Rate limit
The same as the other partner routes: one counter per key and one for the sum of your brand's keys, 120 calls per 60-second window by default. Every call that writes takes 1 unit of the key's daily quota, whatever the number of units it carries.
#Request body
| Name | Type | Required | Description |
|---|---|---|---|
units | array of string | yes | 1 to 1000 units, each as the scanner read it: the 12-character serial printed on the label, the unit link (https://sealtrust.io/p/{serial}), its GS1 Digital Link (.../01/{gtin}/21/{serial}) or its signed QR link. |
reallocate | boolean | no | true moves into this order the units that are in another order of your brand. Absent or false, such a unit answers already_allocated. |
reason | string | with reallocate | Why the units move, 200 characters at most. It is written on the old row and in the audit log. |
A unit belongs to one active order at a time. The database guarantees it, even when two pickers scan the same unit in the same second.
#Example request
curl -i -X POST "https://api.sealtrust.io/v1/partner/dispatch/shipments/318/units" \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"units": ["H897RFWJ4972", "https://sealtrust.io/p/Y5T2VGGF2NP9", "K2M8Q0R4T6V1", "000000000000"]}'#Example response
HTTP 200, even when some units are refused.
{
"shipment_id": 318,
"order_ref": "SO-2026-1042",
"accepted": 2,
"rejected": 2,
"units_allocated": 2,
"results": [
{"input": "H897RFWJ4972", "status": "allocated", "ok": true, "product_id": 4096, "serial": "H897RFWJ4972", "other_order_ref": null},
{"input": "https://sealtrust.io/p/Y5T2VGGF2NP9", "status": "allocated", "ok": true, "product_id": 4097, "serial": "Y5T2VGGF2NP9", "other_order_ref": null},
{"input": "K2M8Q0R4T6V1", "status": "already_allocated", "ok": false, "product_id": 4098, "serial": "K2M8Q0R4T6V1", "other_order_ref": "SO-2026-0998"},
{"input": "000000000000", "status": "unknown_unit", "ok": false, "product_id": null, "serial": null, "other_order_ref": null}
]
}#The result of each unit
status | ok | What it means |
|---|---|---|
allocated | true | The unit is now in this order. |
already_in_shipment | true | It already was. Nothing changed: a second scan or a replayed call has no effect. |
reallocated | true | It was in another order, named by other_order_ref, and you asked for the move. |
unreadable | false | The value is not a unit code: neither a serial nor a unit link. A lot or model link names no unit. |
unknown_unit | false | No unit of your brand carries this code. A unit of another brand gets exactly the same answer, so that a code is never confirmed to exist elsewhere. |
not_minted | false | The unit exists but is not registered on chain yet. Retry once the mint is confirmed. |
already_allocated | false | It is in another order of your brand, named by other_order_ref. Remove it from that order, or call again with reallocate. |
#Errors
| Code | Condition | What to do |
|---|---|---|
| 401 | Key missing, malformed or unknown. | Send Authorization: Bearer <your key> with the whole key. |
| 403 | The key lacks the dispatch:write scope. Message Missing required scopes: dispatch:write. | Create a key that carries this scope. |
| 403 | The brand is on the Compliance offer. detail.code is OFFER_EXCLUDES_IDENTITY and detail.feature is dispatch. Nothing is recorded. | Move to the Compliance + Identity offer. Retrying changes nothing. |
| 429 | Rate limit or daily quota reached. | Wait the number of seconds in Retry-After, or midnight UTC for the quota. |
| 404 | No shipment of your brand has this id. A shipment of another brand gets exactly the same answer. | Check the id returned at creation. |
| 409 | The shipment is closed or cancelled. detail.code is shipment_not_open. | A closed shipment no longer changes. Create a new order. |
| 400 | reallocate without reason. detail.code is reason_required. | Add a reason. |
| 422 | More than 1000 units, or an invalid body. | Split the batch into calls of 1000 units at most. |
Was this page helpful?
Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.