Warehouse pick & returns
Called with shop (retail) account keys. A key only sees its own account's data. Every example uses the same sample brand, order and item, so you can follow one item from call to call.
http://62.169.23.239:8001/api/v1Auth Bearer token5 endpointsEndpoints
- POST/retail/integrations/fulfillment/orders/{external_order_id}/scanPick by order number
- POST/retail/integrations/fulfillment/tasks/{task_id}/scanPick by task
- POST/retail/integrations/fulfillment/tasks/{task_id}/unlinkUnlink a damaged item
- POST/retail/integrations/fulfillment/tasks/{task_id}/receiveReceive a return
- POST/retail/integrations/fulfillment/tasks/{task_id}/inspectionInspect a return
Pick by order number#
Requires scope fulfillment:write
Pick scan by the shop's own order number: links the scanned unit's passport to the matching pending line of that order. item_id takes the raw scanned QR (any printed URL form) or a bare unit token. Same outcomes as the per-task scan; never transfers ownership.
Parameters
- external_order_idstringpathRequired
Your web shop's own order id. Skannit keys the order on it, so sending it twice does not create it twice.
Request body
- item_idstring | null
Scanned QR unit token — provenance_confidence 'high'
- product_numberstring | null
Hand-keyed fallback — provenance_confidence 'low'
Returns
HTTP 200- matchedbooleanRequired
True when the scanned item was accepted. False is a normal answer (wrong item, already sold) — scan another.
- task_idstringRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
- statusstringRequired
Current state of the object. See the allowed values.
One ofpendingpickedshippeddeliveredcancelledrefusedlostreturn_requestedreturn_receivedreturnedreturn_rejected - provenance_confidencestring | null
high when the item's history comes from the factory; low when it was registered later.
One ofhighlow - unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- reasonstring | nullOne of
wrong_variantalready_linkedalready_solddamageddifferent_item - mismatchobject | null
What was ordered vs. what was scanned. Spec §21: on a mismatch nothing fires and the worker rescans, so the response has to show both sides rather than a bare error.
+Show 4 child attributesHide child attributes
- ordered_product_idstring | null
- ordered_variantstring | null
- scanned_product_idstring | null
- scanned_variantstring | null
- detailstring | null
curl -X POST http://62.169.23.239:8001/api/v1/retail/integrations/fulfillment/orders/1001/scan \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"item_id": "http://62.169.23.239:8001/api/v1/scan/Qm7xK2pL9vR4tY8wZ1nB3c"
}'{
"matched": true,
"task_id": "266ac6a0-a008-5349-ae80-086961f95f9a",
"status": "picked",
"provenance_confidence": "high",
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"reason": null,
"mismatch": null,
"detail": null
}Pick by task#
Requires scope fulfillment:write
Pick scan: check the unit and link its passport to the order.
A failed check returns 200 with matched: false and a reason, a normal outcome the worker resolves by picking another item. Never transfers ownership.
Parameters
- task_idstringpathRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
Request body
- item_idstring | null
Scanned QR unit token — provenance_confidence 'high'
- product_numberstring | null
Hand-keyed fallback — provenance_confidence 'low'
Returns
HTTP 200- matchedbooleanRequired
True when the scanned item was accepted. False is a normal answer (wrong item, already sold) — scan another.
- task_idstringRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
- statusstringRequired
Current state of the object. See the allowed values.
One ofpendingpickedshippeddeliveredcancelledrefusedlostreturn_requestedreturn_receivedreturnedreturn_rejected - provenance_confidencestring | null
high when the item's history comes from the factory; low when it was registered later.
One ofhighlow - unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- reasonstring | nullOne of
wrong_variantalready_linkedalready_solddamageddifferent_item - mismatchobject | null
What was ordered vs. what was scanned. Spec §21: on a mismatch nothing fires and the worker rescans, so the response has to show both sides rather than a bare error.
+Show 4 child attributesHide child attributes
- ordered_product_idstring | null
- ordered_variantstring | null
- scanned_product_idstring | null
- scanned_variantstring | null
- detailstring | null
curl -X POST http://62.169.23.239:8001/api/v1/retail/integrations/fulfillment/tasks/266ac6a0-a008-5349-ae80-086961f95f9a/scan \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"item_id": "Qm7xK2pL9vR4tY8wZ1nB3c"
}'{
"matched": true,
"task_id": "266ac6a0-a008-5349-ae80-086961f95f9a",
"status": "picked",
"provenance_confidence": "high",
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"reason": null,
"mismatch": null,
"detail": null
}Unlink a damaged item#
Requires scope fulfillment:write
Damaged at packing: write the unit off and return the order to pick.
Parameters
- task_idstringpathRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
Request body
- reasonstring
Defaults to
damaged - notestring | null
Returns
HTTP 200- task_idstringRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
- sourcestringRequired
- order_referencestring | null
Order number your customer sees (for example #1001).
- external_order_idstringRequired
Your web shop's own order id. Skannit keys the order on it, so sending it twice does not create it twice.
- product_idstring | null
Skannit's id for the product.
- product_namestring | null
- assigned_variantstring | null
Colour / size the order line asks for.
- skustring | null
Stock-keeping unit of the variant.
- quantityinteger
Number of units.
Defaults to
1 - buyer_emailstring | null
GL-02: buyer identity is never sent out (always null); the order reference identifies the order. Kept in the schema only so the public v1 contract doesn't break. Stored on the task only to email the buyer.
- buyer_phonestring | null
Stored only. Matching is by email. Never returned in responses (always null).
- buyer_namestring | null
Never returned in responses (always null).
- deadlinetimestamp | null
When the order is promised. Drives the queue's ordering; NULL when the provider sent no SLA.
- statusstring
Current state of the object. See the allowed values.
One ofpendingpickedshippeddeliveredcancelledrefusedlostreturn_requestedreturn_receivedreturnedreturn_rejectedDefaults to
pending - linked_unit_tokenstring | null
The unit whose passport is linked to this order (set by the pick scan).
- carrierstring | null
Carrier name, for example PostNL or DHL.
- tracking_numberstring | null
The carrier's tracking number.
- shipped_attimestamp | null
When your web shop reported the parcel shipped.
- delivered_attimestamp | null
When the parcel was reported delivered — the moment ownership moved.
- is_matchableboolean
False when the external SKU matched no Skannit product. Such a task is visible to a worker but cannot be picked until it is mapped.
Defaults to
true - created_attimestampRequired
When the object was created (ISO 8601, UTC).
curl -X POST http://62.169.23.239:8001/api/v1/retail/integrations/fulfillment/tasks/266ac6a0-a008-5349-ae80-086961f95f9a/unlink \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "damaged",
"note": "Seam torn at packing"
}'{
"task_id": "266ac6a0-a008-5349-ae80-086961f95f9a",
"source": "web_shop",
"order_reference": "#1001",
"external_order_id": "1001",
"product_id": "f6abe715-90aa-5908-a0a6-12951a3a21cc",
"product_name": "Trail Tee",
"assigned_variant": "White / M",
"sku": "TT-100-WHT-M",
"quantity": 1,
"buyer_email": null,
"buyer_phone": null,
"buyer_name": null,
"deadline": null,
"status": "pending",
"linked_unit_token": null,
"carrier": "PostNL",
"tracking_number": "3SNWD1234567890",
"shipped_at": null,
"delivered_at": null,
"is_matchable": true,
"created_at": "2026-10-09T09:30:00Z"
}Receive a return#
Requires scope fulfillment:write
Scan in a refused parcel (shipped) or a customer return (return_requested).
Parameters
- task_idstringpathRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
Request body
- item_idstring | null
Scanned QR unit token — provenance_confidence 'high'
- product_numberstring | null
Hand-keyed fallback — provenance_confidence 'low'
Returns
HTTP 200- matchedbooleanRequired
True when the scanned item was accepted. False is a normal answer (wrong item, already sold) — scan another.
- task_idstringRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
- statusstringRequired
Current state of the object. See the allowed values.
One ofpendingpickedshippeddeliveredcancelledrefusedlostreturn_requestedreturn_receivedreturnedreturn_rejected - provenance_confidencestring | null
high when the item's history comes from the factory; low when it was registered later.
One ofhighlow - unit_tokenstring | null
The item's own token. It is what the item's QR code carries, and the id every item event uses.
- reasonstring | nullOne of
wrong_variantalready_linkedalready_solddamageddifferent_item - mismatchobject | null
What was ordered vs. what was scanned. Spec §21: on a mismatch nothing fires and the worker rescans, so the response has to show both sides rather than a bare error.
+Show 4 child attributesHide child attributes
- ordered_product_idstring | null
- ordered_variantstring | null
- scanned_product_idstring | null
- scanned_variantstring | null
- detailstring | null
curl -X POST http://62.169.23.239:8001/api/v1/retail/integrations/fulfillment/tasks/266ac6a0-a008-5349-ae80-086961f95f9a/receive \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"item_id": "Qm7xK2pL9vR4tY8wZ1nB3c"
}'{
"matched": true,
"task_id": "266ac6a0-a008-5349-ae80-086961f95f9a",
"status": "return_received",
"provenance_confidence": "high",
"unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"reason": null,
"mismatch": null,
"detail": "Box BOX-F4E1A9-0003 manifest says 48 units"
}Inspect a return#
Requires scope fulfillment:write
Accept (passport back to the shop) or reject (stays with the customer).
Parameters
- task_idstringpathRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
Request body
- decisionstringRequired
accept = the shop takes the passport back; reject = it stays with the customer.
One ofacceptreject - next_stepstring | null
Required to accept: what happens to the item once the shop owns it again.
One ofrestockrepairrecycle - reasonstring | null
Required to reject: why (worn, damaged by the customer, ...).
Returns
HTTP 200- task_idstringRequired
One unit of a web order to pick. An order with quantity 3 creates 3 tasks.
- sourcestringRequired
- order_referencestring | null
Order number your customer sees (for example #1001).
- external_order_idstringRequired
Your web shop's own order id. Skannit keys the order on it, so sending it twice does not create it twice.
- product_idstring | null
Skannit's id for the product.
- product_namestring | null
- assigned_variantstring | null
Colour / size the order line asks for.
- skustring | null
Stock-keeping unit of the variant.
- quantityinteger
Number of units.
Defaults to
1 - buyer_emailstring | null
GL-02: buyer identity is never sent out (always null); the order reference identifies the order. Kept in the schema only so the public v1 contract doesn't break. Stored on the task only to email the buyer.
- buyer_phonestring | null
Stored only. Matching is by email. Never returned in responses (always null).
- buyer_namestring | null
Never returned in responses (always null).
- deadlinetimestamp | null
When the order is promised. Drives the queue's ordering; NULL when the provider sent no SLA.
- statusstring
Current state of the object. See the allowed values.
One ofpendingpickedshippeddeliveredcancelledrefusedlostreturn_requestedreturn_receivedreturnedreturn_rejectedDefaults to
pending - linked_unit_tokenstring | null
The unit whose passport is linked to this order (set by the pick scan).
- carrierstring | null
Carrier name, for example PostNL or DHL.
- tracking_numberstring | null
The carrier's tracking number.
- shipped_attimestamp | null
When your web shop reported the parcel shipped.
- delivered_attimestamp | null
When the parcel was reported delivered — the moment ownership moved.
- is_matchableboolean
False when the external SKU matched no Skannit product. Such a task is visible to a worker but cannot be picked until it is mapped.
Defaults to
true - created_attimestampRequired
When the object was created (ISO 8601, UTC).
curl -X POST http://62.169.23.239:8001/api/v1/retail/integrations/fulfillment/tasks/266ac6a0-a008-5349-ae80-086961f95f9a/inspection \
-H "Authorization: Bearer $SKANNIT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"decision": "accept",
"next_step": "restock"
}'{
"task_id": "266ac6a0-a008-5349-ae80-086961f95f9a",
"source": "web_shop",
"order_reference": "#1001",
"external_order_id": "1001",
"product_id": "f6abe715-90aa-5908-a0a6-12951a3a21cc",
"product_name": "Trail Tee",
"assigned_variant": "White / M",
"sku": "TT-100-WHT-M",
"quantity": 1,
"buyer_email": null,
"buyer_phone": null,
"buyer_name": null,
"deadline": null,
"status": "returned",
"linked_unit_token": "Qm7xK2pL9vR4tY8wZ1nB3c",
"carrier": "PostNL",
"tracking_number": "3SNWD1234567890",
"shipped_at": null,
"delivered_at": null,
"is_matchable": true,
"created_at": "2026-10-09T09:30:00Z"
}