Fulfil orders
Take an order, pick it, ship it and send the tracking, also when an order is split across warehouses.
Fulfil an order
1. Read the queue. GET /orders (default status=to_fulfill) lists the orders ready for your warehouse and not yet accepted, oldest first, with everything you need: customer and shipping address, carrier and service, priority, notes, and only your lines with quantities, weights and unit prices for customs. Reading never takes an order over, so poll it every 1 to 5 minutes. A page can hold fewer orders than limit — even none — while next_cursor is not null: keep following it until it is.
curl "https://api-commerce.nucleoplatform.com/api/fulfillment/v1/orders?status=to_fulfill&limit=100" \
-H "Authorization: Bearer $NUCLEO_FULFILLMENT_KEY"let cursor = null;
do {
const page = await nucleo(`/orders?status=to_fulfill&limit=100${cursor ? `&cursor=${cursor}` : ""}`);
for (const order of page.data) await importIntoWms(order);
cursor = page.next_cursor;
} while (cursor);<?php
$cursor = null;
do {
$query = ['status' => 'to_fulfill', 'limit' => 100] + ($cursor ? ['cursor' => $cursor] : []);
$page = json_decode($nucleo->get('orders', ['query' => $query])->getBody(), true);
foreach ($page['data'] as $order) {
importIntoWms($order);
}
$cursor = $page['next_cursor'];
} while ($cursor !== null);2. Accept it once it is in your WMS, with your own reference. It leaves the queue and its items stop being reserved out of the stock you report. If you cannot take it (address incomplete, item unknown), reject it with a reason code instead: the merchant fixes it and it comes back.
curl -X POST https://api-commerce.nucleoplatform.com/api/fulfillment/v1/orders/1042/accept \
-H "Authorization: Bearer $NUCLEO_FULFILLMENT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: accept-1042" \
-d '{"wms_reference": "VR-2026-004211"}'await nucleo("/orders/1042/accept", {
method: "POST",
body: { wms_reference: "VR-2026-004211" },
idempotencyKey: "accept-1042",
});<?php
$nucleo->post('orders/1042/accept', [
'headers' => ['Idempotency-Key' => 'accept-1042'],
'json' => ['wms_reference' => 'VR-2026-004211'],
]);3. Report the picking with what you actually picked, by sku or barcode, and the parcels. It is all or nothing: one item that is not a line of the order assigned to you rejects the call with 422 unknown_item and nothing is recorded. A quantity lower than ordered marks the missing pieces as unfulfillable; the merchant is alerted and, if the merchant enabled it, the customer is refunded for them. You can send the picking again until you ship: the last report counts. A later report with more pieces missing refunds only the difference; a refund already made is never taken back, so a correction with fewer pieces missing is flagged to the merchant — report the picking when it is complete.
curl -X POST https://api-commerce.nucleoplatform.com/api/fulfillment/v1/orders/1042/picked \
-H "Authorization: Bearer $NUCLEO_FULFILLMENT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: picked-1042" \
-d '{
"lines": [
{"sku": "TEE-BLK-M", "quantity": 1},
{"barcode": "2000000000022", "quantity": 2, "lot_number": "L2026-41"}
],
"parcels": [{"reference": "PK-1", "weight_g": 1540}]
}'await nucleo("/orders/1042/picked", {
method: "POST",
idempotencyKey: "picked-1042",
body: {
lines: [
{ sku: "TEE-BLK-M", quantity: 1 },
{ barcode: "2000000000022", quantity: 2, lot_number: "L2026-41" },
],
parcels: [{ reference: "PK-1", weight_g: 1540 }],
},
});<?php
$nucleo->post('orders/1042/picked', [
'headers' => ['Idempotency-Key' => 'picked-1042'],
'json' => [
'lines' => [
['sku' => 'TEE-BLK-M', 'quantity' => 1],
['barcode' => '2000000000022', 'quantity' => 2, 'lot_number' => 'L2026-41'],
],
'parcels' => [['reference' => 'PK-1', 'weight_g' => 1540]],
],
]);4. Report the shipment with the carrier and one tracking number per parcel. Nucleo marks the order shipped and creates the fulfilment on the sales channel. The same tracking number sent again is a retry: 200 with the shipment already recorded, never a second fulfilment.
curl -X POST https://api-commerce.nucleoplatform.com/api/fulfillment/v1/orders/1042/shipments \
-H "Authorization: Bearer $NUCLEO_FULFILLMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"carrier_code": "EXAMPLE", "service_code": "EXPRESS", "parcels": [{"tracking_number": "064152003391", "weight_g": 1540}]}'const shipment = await nucleo("/orders/1042/shipments", {
method: "POST",
body: { carrier_code: "EXAMPLE", service_code: "EXPRESS", parcels: [{ tracking_number: "064152003391", weight_g: 1540 }] },
});
console.log(shipment.order_status); // "shipped"<?php
$res = $nucleo->post('orders/1042/shipments', ['json' => [
'carrier_code' => 'EXAMPLE',
'service_code' => 'EXPRESS',
'parcels' => [['tracking_number' => '064152003391', 'weight_g' => 1540]],
]]);
// 201 = new shipment, 200 = the same tracking number was already recordedCannot ship an order you accepted? POST /orders/{number}/cancel with a reason code: the order is cancelled and the merchant refunds the customer. On an order split with another warehouse — even if the other warehouse already shipped its part — cancel gives up only your part: what is left of your share becomes unfulfillable (refunded once, if the merchant enabled it), your part turns closed and picked and shipments on it answer 409 invalid_state, while the other warehouse goes on with its own.
Accepting again an order you already picked answers 409 invalid_state; one you already shipped, 409 order_already_shipped.
Labels made by Nucleo. When shipping.labels_by is nucleo, the merchant has Nucleo create the carrier labels: the first one is ready right after you accept the order. Download them with GET /orders/{number}/labels, ask for more parcels with POST /orders/{number}/labels, and report the shipment without carrier_code and parcels — the shipment gets one parcel per ready label, with the labels' tracking numbers and the carrier and service of the order (shipping.carrier_code, shipping.service_code), and sending it again answers 200 with the same shipment. At most 10 labels per order: with Nucleo labels, parcels takes at most 10 items. After the shipment, GET /orders/{number}/labels still shows the labels it left with. Labels can be created only once you accepted your part; after a partial shipment (lines), POST /orders/{number}/labels creates new labels for the rest and the next shipment without parcels takes them. With no ready label the shipment answers 409 labels_not_ready. If you send parcels in the picking report, each one gets its own label and keeps its tracking number; your references, weights and sizes are added to it. GET /orders/{number}/documents returns the invoice, customs documents and inserts to put in the parcel.
Cancellations. An order cancelled before you accept it simply leaves the queue. Cancelled after you accepted it, it turns cancel_requested (and you get the order.cancelled webhook): stop picking if you still can and call cancel to confirm you stopped, or report the shipment if the parcel already left — never both. The order is then closed: cancelled, or — if part of it already left — that part stays shipped and only the pieces not shipped are cancelled and refunded. Split orders work differently: see below. accept, reject and picked answer 409 order_cancel_requested.
See List orders, Report the picking and Report a shipment for every field.
Orders split across warehouses (v1)
An order can be split between your warehouse and another one — by line, or even within a line (for example 2 pieces from you and 1 from the other warehouse).
What works
- You see only your lines, and every quantity you read and report — ordered, open, picked, unfulfillable, shipped, cancelled — is your share of the line. Your picking and your shipments never change the other warehouse's share, and a shipment contains only your share.
- Until you accept the order, your part stays reserved out of the stock you report, even if the other warehouse already took its own.
cancelgives up only your part — also after the other warehouse shipped its own: your part becomesclosed, what is left of your share becomes unfulfillable (refunded once, if the merchant enabled automatic refunds), andpickedandshipmentson it answer409 invalid_state.
What the merchant completes by hand
- When the merchant cancels a split order, Nucleo does not close it or refund it automatically in v1. The order stays
cancel_requestedfor every warehouse that accepted it and still has something to ship. - Confirm with
cancelthat you stopped (your part then readscancelled), or report the shipment if the parcel already left (it stays shipped). - The merchant sees the state of every part and completes the cancellation and the refund in Nucleo. A warehouse that never accepted the order sees it as
cancelledand has nothing to confirm (409 order_not_accepted).