Contents
Stock
Absolute stock levels per item, warehouse location code and classification. Send everything or only what changed: items you do not send keep their last level. Report stock net of the orders you have accepted; Nucleo subtracts the orders you have not accepted yet before publishing availability to the sales channels.
Base URL, authentication and conventions of this API are on the Fulfillment API page.
/stockUpdate stock levels
Absolute levels (not increments) per item, location code and classification, at most 500 items
per call (the merchant can set a different limit; above it nothing is processed and the answer is
422 too_many_items: split the update in batches).
- Identify each item by
skuorbarcode. location_codeis one of thestock_location_codesreturned by Ping. It can be omitted when your connection has a single code.classificationdefaults tosellable; onlysellablestock is published as available to the sales channels. Other classifications are stored and, if the merchant chooses so, published as damaged (not sellable) stock.counted_at: when the level was counted; without it, the time Nucleo receives the call. A level older than the last one applied for the same item, location code and classification is not applied and is listed inignoredwith reasonstale, so late retries cannot roll stock back.
Unknown items are ignored (listed in ignored with reason unknown_item, and the merchant is
alerted); the others are applied and counted in accepted. A location code not linked to a Nucleo location yet is saved but not published, and listed
in warnings. Validation errors (400) reject the whole call.
Headers
Idempotency-KeystringAny unique string you generate (1–255 printable ASCII characters, no spaces), for example a UUID. For 48 hours, the same key with the same request — same method, same path written the same way (
/orders/1042and/orders/%231042differ) and same body — returns the stored answer without doing the work again (headerIdempotent-Replayed: true; the replayed body keeps the originalrequest_id, theX-Request-Idheader is the new call's). The same key with a different request answers409 idempotency_key_reused; while the first request is still running,409 idempotency_key_in_progress. A key left in progress for more than 2 minutes (an interrupted call) is free again. Keys are per connection. Server errors (5xx) and429are not stored: retry them with the same key.max length 255Example:2f0c9a1e-6b4d-4f3a-9e7c-5d1b8a2c4e6f
Request bodyapplication/json
itemsarray of ItemRef & objectrequiredmin items 1max items 500Attributes of each item
skustring | nullmax length 255barcodestring | nullmax length 255location_codestring | nullRequired when your connection has more than one stock location code.
max length 40quantityintegerrequiredAbsolute level, not an increment.
min 0classificationstringOne ofsellabledamagedquarantinereservedunsellabledefault sellablecounted_atstring (date-time) | null
Responses
200Levels applied.application/json
HeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
acceptedintegerItems applied.
ignoredarray of objectAttributes of each item
indexintegerPosition in
items, from 0.skustring | nullbarcodestring | nullreasonstringunknown_item: not in the catalog.stale:counted_atolder than the level already applied.One ofunknown_itemstale
warningsarray of objectAttributes of each item
location_codestringreasonstringOne oflocation_not_mappedmessagestring
400The request is not valid:
validation_failed(withdetailsper field),invalid_json,invalid_cursor. Nothing was changed. application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
401Missing or invalid API key (
unauthorized).application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
403The connection is paused (
connection_paused) or not active yet (connection_not_active). Nothing was read or changed: retry later. application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
409The request conflicts with the current state:
order_not_ready,order_not_accepted,order_already_accepted,order_cancelled,order_cancel_requested,order_already_shipped,invalid_state,documents_not_ready,labels_not_ready; or with anIdempotency-Key:idempotency_key_reused,idempotency_key_in_progress(withRetry-After). Read the order or return again before retrying. application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.Retry-AfterSeconds to wait before retrying.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
413The body is larger than 5 MB (
payload_too_large). Nothing was read.application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
422Valid JSON that cannot be applied:
unknown_item(an item that is not on the order or not known, withdetailsper line),too_many_items,labels_not_enabled. Nothing was changed. application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
429
rate_limited: more calls in a minute than the connection allows (600 by default, all endpoints together; the merchant can set another limit), or too many failed authentications from your IP. Wait the seconds inRetry-After. application/jsonHeadersX-Request-IdIdentifier of the call. Quote it when you contact support; it is alsoerror.request_id.Retry-AfterSeconds to wait before retrying.
errorobjectrequiredChild attributes
codestringrequiredStable, machine-readable code. Branch on it, not on
message.One ofvalidation_failedinvalid_jsoninvalid_cursorunauthorizedconnection_pausedconnection_not_activenot_foundmethod_not_allowedorder_not_foundreturn_not_foundorder_not_readyorder_not_acceptedorder_already_acceptedorder_cancelledorder_cancel_requestedorder_already_shippedinvalid_statedocuments_not_readylabels_not_readyidempotency_key_reusedidempotency_key_in_progresspayload_too_largeunknown_itemtoo_many_itemslabels_not_enabledrate_limitedinternal_errormessagestringrequiredExplanation in English for people. It can change; never parse it.
request_idstring (uuid)requiredSame as the
X-Request-Idheader.detailsobjectValidation and item errors per field:
{"lines.0.quantity": ["…"]}.
curl -X PUT https://api-commerce.nucleoplatform.com/api/fulfillment/v1/stock \
-H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
-H 'Idempotency-Key: 2f0c9a1e-6b4d-4f3a-9e7c-5d1b8a2c4e6f' \
-H 'Content-Type: application/json' \
-d '{
"items": [
{
"sku": "TEE-BLK-M",
"quantity": 42,
"counted_at": "2026-10-13T06:00:00Z"
},
{
"barcode": "2000000000022",
"location_code": "VR1",
"quantity": 3,
"classification": "damaged"
},
{
"sku": "SOCK-WHT-S",
"quantity": 0
}
]
}'const res = await fetch("https://api-commerce.nucleoplatform.com/api/fulfillment/v1/stock", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.NUCLEO_ACCESS_TOKEN}`,
"Idempotency-Key": "2f0c9a1e-6b4d-4f3a-9e7c-5d1b8a2c4e6f",
"Content-Type": "application/json",
},
body: JSON.stringify({
"items": [
{
"sku": "TEE-BLK-M",
"quantity": 42,
"counted_at": "2026-10-13T06:00:00Z"
},
{
"barcode": "2000000000022",
"location_code": "VR1",
"quantity": 3,
"classification": "damaged"
},
{
"sku": "SOCK-WHT-S",
"quantity": 0
}
]
}),
});
const data = await res.json();
console.log(res.status, data);<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$response = $client->request('PUT', 'https://api-commerce.nucleoplatform.com/api/fulfillment/v1/stock', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('NUCLEO_ACCESS_TOKEN'),
'Idempotency-Key' => '2f0c9a1e-6b4d-4f3a-9e7c-5d1b8a2c4e6f',
],
'json' => [
'items' => [
[
'sku' => 'TEE-BLK-M',
'quantity' => 42,
'counted_at' => '2026-10-13T06:00:00Z',
],
[
'barcode' => '2000000000022',
'location_code' => 'VR1',
'quantity' => 3,
'classification' => 'damaged',
],
[
'sku' => 'SOCK-WHT-S',
'quantity' => 0,
],
],
],
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();{
"accepted": 2,
"ignored": [
{
"index": 2,
"sku": "SOCK-WHT-S",
"barcode": null,
"reason": "unknown_item"
}
],
"warnings": []
}{
"error": {
"code": "validation_failed",
"message": "The request is not valid.",
"request_id": "1f7e3c2a-9b8d-4e6f-a5c4-3b2a1d0e9f8c",
"details": {
"lines.0.quantity": [
"The lines.0.quantity field must be at least 0."
],
"reason_code": [
"The reason code field is required."
]
}
}
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key.",
"request_id": "0b6c3e4f-1a2d-4c5b-8e7f-9a0b1c2d3e4f"
}
}{
"error": {
"code": "connection_paused",
"message": "This connection is paused: nothing was changed.",
"request_id": "3c2b1a0f-9e8d-4c7b-a6f5-4e3d2c1b0a9f"
}
}{
"error": {
"code": "order_not_accepted",
"message": "Accept order",
"request_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
}
}{
"error": {
"code": "validation_failed",
"message": "string",
"request_id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
"details": {}
}
}{
"error": {
"code": "unknown_item",
"message": "Some lines do not match an item of this order assigned to your warehouse. Nothing was changed.",
"request_id": "2e1d0c9b-8a7f-4e6d-9c5b-4a3f2e1d0c9b",
"details": {
"lines.1": [
"Not an item of this order assigned to your warehouse."
]
}
}
}{
"error": {
"code": "rate_limited",
"message": "Too many requests: retry after the number of seconds in Retry-After.",
"request_id": "4f3e2d1c-0b9a-4f8e-8d7c-6b5a4f3e2d1c"
}
}