API reference

Webhooks

Receive order and PUDO events as they happen. Your Starmile organization configures one or more webhook endpoints, each subscribed to the events you care about; we POST a signed JSON envelope to your URL and retry on failure.

How deliveries reach you

We POST a JSON envelope to your endpoint. A delivery is a success on any 2xx response; anything else (or a timeout) is retried 3 times, 5 minutes apart, after which the delivery is marked failed. Respond 2xx quickly and process asynchronously.

The request we send

Each delivery is a single event. Verify the signature, acknowledge with a 2xx, and de-duplicate on X-Webhook-Id (the same id is re-sent on every retry).

POST https://your-app.example/webhooks
Content-Type: application/json
X-Webhook-Id: 4821
X-Webhook-Event: order.delivered
X-Webhook-Signature: sha256=9f86d0818...c2c9

{
  "id": 4821,
  "event": "order.delivered",
  "occurred_at": "2026-06-22T14:05:11+00:00",
  "data": {
    "order_id": 12345,
    "tracking_number": "STM-12345",
    "external_parent_id": "EXT-1",
    "status": "delivered",
    "occurred_at": "2026-06-22T14:05:10+00:00"
  }
}

Headers

X-Webhook-Idstringrequired
The delivery id — stable across retries of the same delivery. Use it to de-duplicate.
X-Webhook-Eventstringrequired
The event name (e.g. order.delivered), so you can route without parsing the body.
X-Webhook-Signaturestringoptional
Present when the endpoint has a signing secret: sha256=<HMAC-SHA256 of the raw body>.

Body

idintegerrequired
The delivery id (matches X-Webhook-Id).
eventstringrequired
The event name.
occurred_atstring (ISO-8601)required
When the delivery was created.
dataobjectrequired
The event payload — fields depend on the event (see below).

Verifying the signature

When your endpoint has a signing secret, every delivery carries X-Webhook-Signature: the lowercase hex HMAC-SHA256 of the raw request body using your secret, prefixed with sha256=. Compute the same and compare in constant time — reject the delivery if it does not match.

// Verify the signature before trusting a delivery (Node.js)
import crypto from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  // constant-time compare
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected),
  );
}

Events

Subscribe each endpoint to any of the events below. The data object carries the listed fields.

Order events (OMS)

EventSets statusdata fieldsDescription
order.createdorder_createdorder_idtracking_numberexternal_parent_idAn order entered the system.
order.status_updated(varies)order_idstatusstagestepThe order advanced to a new status.
order.consolidatedconsolidatedorder_idretainedChild parcels were consolidated under a master order.
order.delivereddeliveredorder_idtracking_numberThe order was delivered to the recipient.
order.delivery_faileddelivery_failedorder_idreasonA delivery attempt failed.
order.cancelledcancelledorder_idThe order was cancelled.
order.customs_holdcustoms_holdorder_idThe order was held at customs.

PUDO events

EventSets statusdata fieldsDescription
pudo.receivedreceived_at_pudoparcel_idtracking_numberpudo_point_idA parcel was received at a PUDO point.
pudo.acceptedaccepted_at_pudoparcel_idpudo_point_idA parcel was accepted (checked in) at a PUDO point.
pudo.delivereddeliveredparcel_idpudo_point_idA customer collected the parcel from the PUDO point.
pudo.undeliveredundeliveredparcel_idpudo_point_idThe parcel went uncollected past the PUDO hold window.

Retries & failures

  • A delivery succeeds on any 2xx.
  • On a non-2xx or a timeout, it is retried 3 times, 5 minutes apart.
  • After the final attempt it is marked failed and logged; your Starmile operator can review every delivery (success or failure) in the console and re-send a test event.