Contents
Delivery Promise API
Tell shoppers when an item or cart will arrive, before they buy.
The Delivery Promise API answers one question for your storefront: if the shopper orders now, when will it arrive? For a product or a whole cart, a destination country (and optionally a postcode) it returns, per shipping method, the order-by cutoff, the ship date, the delivery window, a ready-to-display sentence in the shopper's language and the stores where the items can be picked up.
The promise is computed with the same pieces Nucleo uses to fulfil the real order: order routing and real stock per location, each location's working calendar, cutoffs and daily capacity, the service-level policies and carrier transit times. Merchandise not in stock but due in from a supplier is promised from its arrival date.
It is called directly from the browser (product page, cart, checkout). Authentication is a
publishable store token passed in the token query parameter; it is safe to embed in your theme.
Authentication
storeTokenAPI key · query · tokenPublishable store token (
npk_{organization}_{random}). It identifies the store and is meant to live in storefront code; restrict who can use it with allowed origins and the per-token rate limit. Nucleo stores it encrypted and compares a hash. Get or rotate it in Settings › Orders › Shipping and delivery › Delivery promise.
- Base URL
- https://api-commerce.nucleoplatform.com/api/oms/v1Production
- Who calls it
- Storefronts
- Endpoints
- 1
- OpenAPI 3.1 specification
- delivery-promise.yaml
Delivery promise
Delivery dates and pickup options for a product or a cart, ready to show on the storefront.
Turning it on. In Nucleo go to Settings › Orders › Shipping and delivery › Delivery promise.
Switch the public API on, list the storefront origins allowed to call it, then copy the store token
(npk_…) and the endpoint. The same page has a ready-made Shopify theme snippet and a preview
("try a SKU and a country") that also shows why (which location, cutoff and transit were used).
Rotating the token. Rotate token on the same page issues a new token; the old one stops working immediately, so update your theme snippet at the same time.
Locking the promise on the order. If the cart carries the attribute _nucleo_promise, Nucleo
uses the date the shopper saw as the order's promised delivery date and measures how often it is kept
(promise accuracy on the same settings page). The value is either a bare date (2026-10-07) or
one date per method separated by ; (standard:2026-10-07;express:2026-10-06); Nucleo picks the
one matching the order's shipping method. The Shopify snippet does this for you with /cart/update.js.
/public/promiseGet the delivery promise for a cart
Returns when the given product (sku + qty) or cart (items) arrives in country, for each
shipping method (standard, express), plus up to three stores where it can be picked up today
or on the next opening day.
How it is computed
- The fulfilling location is the one order routing would choose (a dry run, nothing is reserved); without routing rules, the first location fulfilling online orders that has everything (warehouses before stores), otherwise one location per line (split).
- The ship day comes from that location's calendar (working days, holidays, closures, cutoff per method, preparation days), its daily capacity (a full day pushes the departure to the next working day) and the extra days of the matching service-level policy.
- The delivery window adds the carrier's transit time (minimum and maximum, in working days of the destination country) plus the policy's buffer days.
- Nothing in stock anywhere but stock due in within 120 days: the option is
incomingand dates start from the arrival date. - If any SKU in the request is unknown to Nucleo, no shipping or pickup option is returned and
availableisfalse.
Pickup lists stores in country with click & collect on and every item in stock, nearest first
(by postcode prefix when zip is given), at most three. Pickup is omitted entirely if the merchant
turned it off in the settings.
Messages (message at top level and per option/pickup) are rendered at response time in lang,
so the "order within" countdown is always current. Pickup times in messages use Italian time
(Europe/Rome).
Caching. The computed promise is cached server-side per store and request (country, postcode,
channel, lines) for the number of seconds set by the merchant (default 60, 0 to 3600); the countdown
and messages are still recomputed on every call. Responses carry Cache-Control: public, max-age=30.
CORS. Callable from any browser origin. If the merchant set allowed origins, a request whose
Origin header is not in the list is refused with 403 origin_not_allowed (comparison is
case-insensitive, trailing slash ignored). Requests without an Origin header (server-to-server)
are not checked against the list.
Privacy. The response never contains internal IDs, location names used for routing, carriers or the reasoning behind the dates.
Rate limits (fixed one-minute windows):
- 120 requests per minute per client IP (counted before the token is checked);
- per store token: the merchant's limit (default 600 per minute, minimum 10).
Over either limit the API answers 429 with a Retry-After header (seconds).
This endpoint is read-only and idempotent.
token query parameterQuery parameters
tokenstringrequiredPublishable store token,
npk_{organization}_{40 alphanumerics}. Copy it from Settings › Orders › Shipping and delivery › Delivery promise.pattern ^npk_[0-9]{1,10}_[A-Za-z0-9]{40}$Example:npk_1042_Q9xT2bLm8RkV4sWz7yHn3cJd6fGp1aEu5oKi0MrXcountrystringrequiredDestination country, ISO 3166-1 alpha-2 (letters only, case-insensitive).
min length 2max length 2pattern ^[A-Za-z]{2}$Example:ITskustringA single product variant SKU (max 120 characters). Use either
sku(+qty) oritems; ifitemsis present,skuandqtyare ignored. One of the two is required.max length 120Example:TEE-BLK-MqtyintegerQuantity for
sku, 1 to 99. Defaults to 1.min 1max 99default 1Example:1itemsstringA cart: comma-separated
SKU:QUANTITYpairs, 1 to 20 lines (quantity 1 to 99, defaults to 1 when omitted). SKUs containing,or:cannot be expressed in this form.Example:TEE-BLK-M:1,HOODIE-GRY-L:2zipstringDestination postcode (max 12 characters: letters, digits, spaces, hyphens). Spaces are removed and the first 5 characters are used to rank pickup stores by proximity.
max length 12pattern ^[A-Za-z0-9 -]*$Example:20121channelstringSales channel the order would come from (lowercase letters, digits,
_,-; max 30). It selects the routing rules, channel stock allocation and service-level policy. Defaults to the channel set in the merchant's settings (shopifyunless changed).max length 30pattern ^[a-z0-9_-]*$Example:shopifylangstringLanguage of the
messagefields. Anything else falls back toen.One ofitendefresdefault enExample:en
Responses
200The delivery promise.application/json
HeadersCache-ControlAlwayspublic, max-age=30.Access-Control-Allow-OriginCORS header;*or the calling origin.
computed_atstring (date-time)requiredWhen the dates were computed (may be up to the cache duration in the past).
countrystringrequiredDestination country, upper case.
Example:ITitemsarray of objectrequiredThe requested lines, in order.
Attributes of each item
skustring | nullrequiredExample:TEE-BLK-Mquantityintegerrequiredmin 1max 99knownbooleanrequiredWhether Nucleo knows this SKU. One unknown SKU means no options at all.
availablebooleanrequiredtrueif at least one shipping option isin_stockor at least one pickup store is listed.optionsarray of ShippingOptionrequiredOne entry per shipping method that could be evaluated,
standardfirst.Attributes of each item
methodstringrequiredOne ofstandardexpressstatusstringrequiredin_stockships from current stock;incomingships once stock due in arrives (available_from);unavailablecannot be promised (all date fields arenull).One ofin_stockincomingunavailableavailable_fromstring (date) | nullrequiredFor
incoming, the date the stock is expected.order_bystring (date-time) | nullrequiredCutoff to beat to ship on
ships_on. Only forin_stock.ships_onstring (date) | nullrequiredDay the parcel leaves the location (the latest one when the cart is split).
delivery_fromstring (date) | nullrequiredEarliest delivery day.
delivery_tostring (date) | nullrequiredLatest delivery day (includes the policy's buffer days). Store this in
_nucleo_promise.order_within_minutesinteger | nullrequiredMinutes left until
order_by;nullwhen the cutoff is past or not applicable.messagestringrequiredReady-to-display sentence in
lang.
pickuparray of PickupOptionrequiredStores where the whole cart can be collected, best first.
max items 3Attributes of each item
location_codestringrequiredThe store's code in Nucleo.
Example:MI01namestringrequiredExample:Acme Apparel Milanocitystring | nullrequiredExample:Milanoaddressstring | nullrequiredExample:Via Roma 1ready_atstring (date-time)requiredWhen the order would be ready for collection, from the store's opening hours and preparation time.
messagestringrequiredExample:Pick up today at Acme Apparel Milano from 16:00
messagestringrequiredThe message of the first option that is not
unavailable, or the "unavailable" sentence.Example:Order within 2 h 14 min, get it between Tuesday, 6 October and Wednesday, 7 October
401
invalid_token: the token is malformed, unknown, has been rotated, or the public API is switched off for this store. application/jsonHeadersAccess-Control-Allow-OriginCORS header;*or the calling origin.
errorstringrequiredOne ofinvalid_tokenorigin_not_allowedinvalid_requestrate_limitedfieldsarray of stringOnly for
invalid_request.
403
origin_not_allowed: the requestOriginis not among the allowed origins set by the merchant.application/jsonHeadersAccess-Control-Allow-OriginCORS header;*or the calling origin.
errorstringrequiredOne ofinvalid_tokenorigin_not_allowedinvalid_requestrate_limitedfieldsarray of stringOnly for
invalid_request.
422
invalid_request: one or more parameters are invalid.fieldslists the offending inputs (country,zip,channel,lineswhen nosku/itemswas given or more than 20 lines,lines.{n}.sku,lines.{n}.quantity). application/jsonHeadersAccess-Control-Allow-OriginCORS header;*or the calling origin.
errorstringrequiredOne ofinvalid_tokenorigin_not_allowedinvalid_requestrate_limitedfieldsarray of stringOnly for
invalid_request.
429
rate_limited: too many requests from this IP or for this store token.application/jsonHeadersRetry-AfterSeconds to wait before retrying.Access-Control-Allow-OriginCORS header;*or the calling origin.
errorstringrequiredOne ofinvalid_tokenorigin_not_allowedinvalid_requestrate_limitedfieldsarray of stringOnly for
invalid_request.
curl -X GET "https://api-commerce.nucleoplatform.com/api/oms/v1/public/promise?token=$NUCLEO_TOKEN&token=npk_1042_Q9xT2bLm8RkV4sWz7yHn3cJd6fGp1aEu5oKi0MrX&country=IT&sku=TEE-BLK-M&qty=1&items=TEE-BLK-M%3A1%2CHOODIE-GRY-L%3A2&zip=20121&channel=shopify&lang=en" \
-H 'Accept: application/json'const res = await fetch(`https://api-commerce.nucleoplatform.com/api/oms/v1/public/promise?token=${process.env.NUCLEO_TOKEN}&token=npk_1042_Q9xT2bLm8RkV4sWz7yHn3cJd6fGp1aEu5oKi0MrX&country=IT&sku=TEE-BLK-M&qty=1&items=TEE-BLK-M%3A1%2CHOODIE-GRY-L%3A2&zip=20121&channel=shopify&lang=en`, {
method: "GET",
headers: {
Accept: "application/json",
},
});
const data = await res.json();
console.log(res.status, data);<?php
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client();
$response = $client->request('GET', 'https://api-commerce.nucleoplatform.com/api/oms/v1/public/promise?token=' . getenv('NUCLEO_TOKEN') . '&token=npk_1042_Q9xT2bLm8RkV4sWz7yHn3cJd6fGp1aEu5oKi0MrX&country=IT&sku=TEE-BLK-M&qty=1&items=TEE-BLK-M%3A1%2CHOODIE-GRY-L%3A2&zip=20121&channel=shopify&lang=en', [
'headers' => [
'Accept' => 'application/json',
],
'http_errors' => false,
]);
echo $response->getStatusCode(), PHP_EOL;
echo $response->getBody();{
"computed_at": "2026-10-05T09:46:00+00:00",
"country": "IT",
"items": [
{
"sku": "TEE-BLK-M",
"quantity": 1,
"known": true
}
],
"available": true,
"options": [
{
"method": "standard",
"status": "in_stock",
"available_from": null,
"order_by": "2026-10-05T12:00:00+00:00",
"ships_on": "2026-10-05",
"delivery_from": "2026-10-06",
"delivery_to": "2026-10-07",
"order_within_minutes": 134,
"message": "Order within 2 h 14 min, get it between Tuesday, 6 October and Wednesday, 7 October"
},
{
"method": "express",
"status": "in_stock",
"available_from": null,
"order_by": "2026-10-05T13:30:00+00:00",
"ships_on": "2026-10-05",
"delivery_from": "2026-10-06",
"delivery_to": "2026-10-06",
"order_within_minutes": 224,
"message": "Order within 3 h 44 min, get it Tuesday, 6 October"
}
],
"pickup": [
{
"location_code": "MI01",
"name": "Acme Apparel Milano",
"city": "Milano",
"address": "Via Roma 1",
"ready_at": "2026-10-05T14:00:00+00:00",
"message": "Pick up today at Acme Apparel Milano from 16:00"
}
],
"message": "Order within 2 h 14 min, get it between Tuesday, 6 October and Wednesday, 7 October"
}{
"computed_at": "2026-10-05T09:46:00+00:00",
"country": "DE",
"items": [
{
"sku": "HOODIE-GRY-L",
"quantity": 2,
"known": true
}
],
"available": false,
"options": [
{
"method": "standard",
"status": "incoming",
"available_from": "2026-10-12",
"order_by": null,
"ships_on": "2026-10-12",
"delivery_from": "2026-10-14",
"delivery_to": "2026-10-16",
"order_within_minutes": null,
"message": "Available from Monday, 12 October, get it between Wednesday, 14 October and Friday, 16 October"
}
],
"pickup": [],
"message": "Available from Monday, 12 October, get it between Wednesday, 14 October and Friday, 16 October"
}{
"computed_at": "2026-10-05T09:46:00+00:00",
"country": "IT",
"items": [
{
"sku": "TEE-BLK-M",
"quantity": 1,
"known": true
},
{
"sku": "GIFT-CARD",
"quantity": 1,
"known": false
}
],
"available": false,
"options": [],
"pickup": [],
"message": "Currently unavailable"
}{
"error": "invalid_token"
}{
"error": "origin_not_allowed"
}{
"error": "invalid_request",
"fields": [
"country"
]
}{
"error": "invalid_request",
"fields": [
"lines.1.quantity"
]
}{
"error": "rate_limited"
}