Contents
Webhooks
Nucleo can call your server when something changes. In the connection's Settings, write your
Webhook URL (https only, on a public address) and save. Your key receives the events of its scopes:
| Event | Scope | When |
|---|---|---|
order.created | orders:read | A new order arrives from the sales channel or through POST /orders, or the merchant creates a replacement order. |
order.status_changed | orders:read | The order's public status changes (internal steps that keep the same public status send nothing). |
shipment.shipped | orders:read | A shipment leaves: one event per shipment, also when an order ships in several parcels. |
return.created | returns:read | A return is opened, or the warehouse receives one nobody announced. |
return.status_changed | returns:read | The return's public status changes. |
Webhooks are hints, not data: read the order or the return with the API to get its current state.
Events can arrive out of order and, after a retry, more than once: skip an id you already handled.
Keep your periodic sync with updated_since as a safety net. GET /ping tells whether webhooks are on
and which events your key receives.
Base URL, authentication and conventions of this API are on the Commerce API page.
order.createdA new order arrived
Sent when an order arrives from the sales channel or through POST /orders (also to the key that
created it), or when the merchant creates a replacement order (for example to resend lost goods).
Needs orders:read.
Request Nucleo sendsapplication/json
idstring (uuid)requiredUnique per event and the same on every retry. Skip an
idyou already handled.typestringrequiredOne oforder.createdorder.status_changedshipment.shippedreturn.createdreturn.status_changedcreated_atstring (date-time)requiredWhen the change happened in Nucleo.
dataobjectrequiredOrders and shipments:
order_id,order_number;order.createdandorder.status_changedaddstatus(an order status),order.status_changedalsoprevious_status;shipment.shippedaddsshipment_id. Returns:return_id,return_number,order_id,order_numberandstatus(a return status);return.status_changedalsoprevious_status.
Expected response
200Answer with any
2xxwithin 10 seconds; the body is ignored. Any other answer, a redirect or a timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32 minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt carries the sameid(also inX-Nucleo-Webhook-Id) and its number inX-Nucleo-Attempt. While the connection is paused or still a draft no webhook is sent, and the events of that time are not sent later: catch up withupdated_since.
{
"id": "5b7e1c2d-3a4f-4b6c-8d9e-0f1a2b3c4d5e",
"type": "order.created",
"created_at": "2026-10-13T08:29:51Z",
"data": {
"order_id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"order_number": "#1042",
"status": "received"
}
}HTTP 200 — Answer with any `2xx` within 10 seconds; the body is ignored. Any other answer, a redirect or a
timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32
minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt
carries the same `id` (also in `X-Nucleo-Webhook-Id`) and its number in `X-Nucleo-Attempt`.
While the connection is paused or still a draft no webhook is sent, and the events of that time are
not sent later: catch up with `updated_since`.
order.status_changedAn order changed status
Sent when the order's public status changes, with the new status and the previous_status. Needs
orders:read.
Request Nucleo sendsapplication/json
idstring (uuid)requiredUnique per event and the same on every retry. Skip an
idyou already handled.typestringrequiredOne oforder.createdorder.status_changedshipment.shippedreturn.createdreturn.status_changedcreated_atstring (date-time)requiredWhen the change happened in Nucleo.
dataobjectrequiredOrders and shipments:
order_id,order_number;order.createdandorder.status_changedaddstatus(an order status),order.status_changedalsoprevious_status;shipment.shippedaddsshipment_id. Returns:return_id,return_number,order_id,order_numberandstatus(a return status);return.status_changedalsoprevious_status.
Expected response
200Answer with any
2xxwithin 10 seconds; the body is ignored. Any other answer, a redirect or a timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32 minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt carries the sameid(also inX-Nucleo-Webhook-Id) and its number inX-Nucleo-Attempt. While the connection is paused or still a draft no webhook is sent, and the events of that time are not sent later: catch up withupdated_since.
{
"id": "8c9d0e1f-2a3b-4c4d-9e5f-6a7b8c9d0e1f",
"type": "order.status_changed",
"created_at": "2026-10-13T16:02:14Z",
"data": {
"order_id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"order_number": "#1042",
"status": "shipped",
"previous_status": "in_fulfillment"
}
}HTTP 200 — Answer with any `2xx` within 10 seconds; the body is ignored. Any other answer, a redirect or a
timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32
minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt
carries the same `id` (also in `X-Nucleo-Webhook-Id`) and its number in `X-Nucleo-Attempt`.
While the connection is paused or still a draft no webhook is sent, and the events of that time are
not sent later: catch up with `updated_since`.
shipment.shippedA shipment left
Sent for each shipment that leaves, also when the order ships in several parcels from different
locations. shipment_id is the id of one of the order's shipments, with carrier and tracking.
An order the customer collects in a store sends no shipment.shipped: it goes straight to delivered.
Needs orders:read.
Request Nucleo sendsapplication/json
idstring (uuid)requiredUnique per event and the same on every retry. Skip an
idyou already handled.typestringrequiredOne oforder.createdorder.status_changedshipment.shippedreturn.createdreturn.status_changedcreated_atstring (date-time)requiredWhen the change happened in Nucleo.
dataobjectrequiredOrders and shipments:
order_id,order_number;order.createdandorder.status_changedaddstatus(an order status),order.status_changedalsoprevious_status;shipment.shippedaddsshipment_id. Returns:return_id,return_number,order_id,order_numberandstatus(a return status);return.status_changedalsoprevious_status.
Expected response
200Answer with any
2xxwithin 10 seconds; the body is ignored. Any other answer, a redirect or a timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32 minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt carries the sameid(also inX-Nucleo-Webhook-Id) and its number inX-Nucleo-Attempt. While the connection is paused or still a draft no webhook is sent, and the events of that time are not sent later: catch up withupdated_since.
{
"id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
"type": "shipment.shipped",
"created_at": "2026-10-13T16:02:15Z",
"data": {
"order_id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"order_number": "#1042",
"shipment_id": "7c6b5a4f-3e2d-4c1b-9a0f-8e7d6c5b4a3f"
}
}HTTP 200 — Answer with any `2xx` within 10 seconds; the body is ignored. Any other answer, a redirect or a
timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32
minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt
carries the same `id` (also in `X-Nucleo-Webhook-Id`) and its number in `X-Nucleo-Attempt`.
While the connection is paused or still a draft no webhook is sent, and the events of that time are
not sent later: catch up with `updated_since`.
return.createdA return was opened
Sent when a return is opened on the sales channel, or when the warehouse receives a return nobody
announced. Needs returns:read.
Request Nucleo sendsapplication/json
idstring (uuid)requiredUnique per event and the same on every retry. Skip an
idyou already handled.typestringrequiredOne oforder.createdorder.status_changedshipment.shippedreturn.createdreturn.status_changedcreated_atstring (date-time)requiredWhen the change happened in Nucleo.
dataobjectrequiredOrders and shipments:
order_id,order_number;order.createdandorder.status_changedaddstatus(an order status),order.status_changedalsoprevious_status;shipment.shippedaddsshipment_id. Returns:return_id,return_number,order_id,order_numberandstatus(a return status);return.status_changedalsoprevious_status.
Expected response
200Answer with any
2xxwithin 10 seconds; the body is ignored. Any other answer, a redirect or a timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32 minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt carries the sameid(also inX-Nucleo-Webhook-Id) and its number inX-Nucleo-Attempt. While the connection is paused or still a draft no webhook is sent, and the events of that time are not sent later: catch up withupdated_since.
{
"id": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"type": "return.created",
"created_at": "2026-10-18T16:20:03Z",
"data": {
"return_id": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b",
"return_number": "R1042-1",
"order_id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"order_number": "#1042",
"status": "requested"
}
}HTTP 200 — Answer with any `2xx` within 10 seconds; the body is ignored. Any other answer, a redirect or a
timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32
minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt
carries the same `id` (also in `X-Nucleo-Webhook-Id`) and its number in `X-Nucleo-Attempt`.
While the connection is paused or still a draft no webhook is sent, and the events of that time are
not sent later: catch up with `updated_since`.
return.status_changedA return changed status
Sent when the return's public status changes, with the new status and the previous_status. Needs
returns:read.
Request Nucleo sendsapplication/json
idstring (uuid)requiredUnique per event and the same on every retry. Skip an
idyou already handled.typestringrequiredOne oforder.createdorder.status_changedshipment.shippedreturn.createdreturn.status_changedcreated_atstring (date-time)requiredWhen the change happened in Nucleo.
dataobjectrequiredOrders and shipments:
order_id,order_number;order.createdandorder.status_changedaddstatus(an order status),order.status_changedalsoprevious_status;shipment.shippedaddsshipment_id. Returns:return_id,return_number,order_id,order_numberandstatus(a return status);return.status_changedalsoprevious_status.
Expected response
200Answer with any
2xxwithin 10 seconds; the body is ignored. Any other answer, a redirect or a timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32 minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt carries the sameid(also inX-Nucleo-Webhook-Id) and its number inX-Nucleo-Attempt. While the connection is paused or still a draft no webhook is sent, and the events of that time are not sent later: catch up withupdated_since.
{
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"type": "return.status_changed",
"created_at": "2026-10-21T09:41:27Z",
"data": {
"return_id": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b",
"return_number": "R1042-1",
"order_id": "3f2a1b4c-5d6e-4f70-8a9b-0c1d2e3f4a5b",
"order_number": "#1042",
"status": "compliant",
"previous_status": "received"
}
}HTTP 200 — Answer with any `2xx` within 10 seconds; the body is ignored. Any other answer, a redirect or a
timeout is retried with exponential backoff (after about 30 seconds, then 1, 2, 4, 8, 16 and 32
minutes): 8 attempts in about an hour, then Nucleo gives up and alerts the merchant. Every attempt
carries the same `id` (also in `X-Nucleo-Webhook-Id`) and its number in `X-Nucleo-Attempt`.
While the connection is paused or still a draft no webhook is sent, and the events of that time are
not sent later: catch up with `updated_since`.