Skip to content

Packing and labels

Each paid store order is split into fulfilments: one per location sending some of its lines. A fulfilment goes from the pick list to packed, gets a label, and is shipped. The carrier’s tracking then moves it to delivered.

GET /v1/fulfilments is the pick list, oldest promise first, each line with its barcodes and weight. Filter with status (comma separated; default allocated,picking,packed,label_purchased), location, kind and limit (up to 100).

Terminal window
curl -sS "https://api.tuppence.ai/v1/fulfilments?status=allocated" \
-H "Authorization: Bearer $TUPPENCE_SECRET_KEY"

POST /v1/fulfilments/{id}/pack takes scans: a barcode packs one item, and a wrong one is refused with 422 wrong_item, naming what it is and what the order wants. A line with no barcode is ticked by hand ({"line": "fulln_…"}). Send package and the scales’ weight_g to set the parcel. When everything is in, the fulfilment is packed.

GET /v1/fulfilments/{id}/packing_slip is the slip: the order number and its QR code, the address, what is in the box (no prices) and how to return it.

GET /v1/fulfilments/{id}/rates answers what a label costs for the packed parcel, by service, beside expected_amount (the price at the weight your product data gave).

POST /v1/fulfilments/{id}/label buys it. It spends money, so it needs an Idempotency-Key, and a parcel’s label is bought once: asking again answers the same shipment and charges nothing.

Terminal window
curl -sS -X POST "https://api.tuppence.ai/v1/fulfilments/ful_123/label" \
-H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \
-H "Idempotency-Key: label-ful_123" \
-H "Content-Type: application/json" \
-d '{}'
ErrorFix
409 label_price_changedThe price is more than a fifth above expected_amount. Send it again with confirm_amount
409 invalid_statePack the order first

POST /v1/fulfilments/labels buys up to 50 at once; each result says bought, needs_confirmation or failed.

GET /v1/shipments/{id}/label?format=pdf prints it: pdf (4x6), png, zpl or pdf_a4, or ?printer= a label printer. A label carries the shopper’s address, so it’s never cached.

POST /v1/fulfilments/{id}/label/void voids an unused label. The parcel goes back to packed, and a label paid from your balance comes back once the carrier refunds it. Carriers whose labels can’t be voided (DPD UK) are refused, saying so.

POST /v1/fulfilments/{id}/ship marks it shipped. Posted without our label, send the receipt’s tracking_number (and carrier) so its tracking moves the order on. The shopper is told it’s on its way. Marking it again changes nothing.

In test mode, labels come from the carriers’ test accounts, cost test money only, and say TEST - NOT FOR POSTING across them.

ToolDoes
list_fulfilments, get_fulfilmentThe pick list, and a parcel with the carrier’s label prices once packed
get_shipmentA label and the carrier’s tracking events
buy_label, void_labelSpend money: over MCP they need an idempotency_key; in the assistant a person approves each one
mark_shippedMarks it shipped, with its label or a tracking number
EventWhen
fulfilment.shippedIt left
fulfilment.delayedIt is late: not sent, no tracking news, or past its latest delivery day
shipment.in_transit, shipment.out_for_delivery, shipment.deliveredThe carrier’s tracking
shipment.exception, shipment.returned_to_senderSomething went wrong in transit
shipment.updatedAny change to the parcel

Docs assistant

Open as a page
Loading the assistant…