Supercommerce API Docs
Store API

Shipping Module — Storefront

HTTP surface for customer-side shipment tracking — the timeline of provider-emitted events for a sub-order the customer placed. Read-only.

HTTP surface for customer-side shipment tracking — the timeline of provider-emitted events for a sub-order the customer placed. Read-only.

Source: api-modules/shipping/src/controllers/store-shipping-tracking.controller.ts.

Provider configuration, vendor-side shipment management, and admin operations live in sibling docs. The shipping module follows a two-layer model: the customer pays a per-vendor flat rate at cart time (plugin-free), and the vendor assigns a concrete provider at the pending→fulfilled transition (plugin-driven). Customers observe the latter via this tracking endpoint.


Conventions

Authentication

EndpointAuth
GET /store/shipping/orders/:id/trackingrequired (customer session)

The endpoint resolves scope through order.customer_id — sub-orders for other customers return 404 Not Found, never 403 (no row leak).

Response envelope

{
  "data": <payload>,
  "metadata": { "total", "limit", "offset", "hasMore" },
  "message": "Success",
  "statusCode": 200
}

Error envelope

statusCodeerrorCode examples
400VALIDATION_ERROR
401UNAUTHORIZED
404NOT_FOUND
500INTERNAL_SERVER_ERROR, DATABASE_ERROR

Domain types

ShippingNormalizedStatus

The mapper normalizes every provider's event code into a small, stable set:

type ShippingNormalizedStatus =
  | "pending"
  | "in_transit"
  | "out_for_delivery"
  | "delivered"
  | "failed"
  | "returned";

The raw statusCode from the provider is preserved alongside the normalized value so the UI can render provider-specific copy. delivered is the trigger that lets the order module auto-stamp order_vendor.delivered_at (and, for COD, the parent payment_status -> paid).

ShippingEventResponse

type ShippingEventResponse = {
  id: string;
  providerId: string;                       // e.g. "clickpost", "self-handled"
  externalEventId: string | null;           // provider's id for the event, when present
  statusCode: string;                       // raw provider code
  normalizedStatus: ShippingNormalizedStatus;
  payload: Record<string, unknown>;         // raw provider event payload (for debugging/forensics)
  receivedAt: string;                       // ISOwhen the system received the event
};

The payload field is the raw provider payload as received — useful for support to introspect courier-reported timestamps, locations, and reasons. The storefront UI typically renders the timeline off normalizedStatus + receivedAt and uses payload only for an expandable "raw event" view.


Endpoints

GET /store/shipping/orders/:id/tracking — Tracking timeline for one of my sub-orders

Newest event first. Paginated.

Path params

NameNotes
idorder_vendor.id — the sub-order id (not the parent order id)

Query

NameTypeDefaultNotes
pageint1>= 1
limitint501..200

Response 200 — paginated ShippingEventResponse[].

{
  "data": [
    {
      "id": "01J9...",
      "providerId": "clickpost",
      "externalEventId": "evt_abc123",
      "statusCode": "OFD",
      "normalizedStatus": "out_for_delivery",
      "payload": {
        "city": "Bengaluru",
        "remarks": "Out for delivery",
        "occurredAt": "2026-05-13T08:15:00Z"
      },
      "receivedAt": "2026-05-13T08:16:42.122Z"
    }
  ],
  "metadata": { "total": 4, "limit": 50, "offset": 0, "hasMore": false }
}

Errors

StatusCodeWhen
400VALIDATION_ERRORpage / limit out of range
404NOT_FOUNDSub-order does not exist or belongs to another customer

  • order — the sub-order id (order_vendor.id) comes from OrderResponse.vendorBreakdowns[].id. The fulfillmentStatus lifecycle that this timeline annotates lives there. See order.md.
  • shipping-clickpost / shipping-self-handled — the concrete provider plugins emit the events this endpoint reads.

On this page