Supercommerce API Docs
Admin API

Shipping Module — Admin

HTTP surface for the platform-admin override of any vendor's shipping config (enabled providers list + customer-charge flat-rate + free-shipping threshold), plus the ops-side write access to any sub-order's tracking timeline.

HTTP surface for the platform-admin override of any vendor's shipping config (enabled providers list + customer-charge flat-rate + free-shipping threshold), plus write access to any sub-order's tracking timeline. Vendor-self read/write of the same surfaces lives on the vendor side.

Source: api-modules/shipping/src/controllers/admin-shipping.controller.ts, api-modules/shipping/src/controllers/admin-shipping-events.controller.ts.

Shipping has two layers: a customer-charge layer (per-vendor flat rate, cart-side, plugin-free) and a provider layer (AWB / pickup, post-order, plugin-driven). This admin surface owns the customer-charge configuration; vendors pick the active provider per sub-order via the vendor-side fulfilment endpoints.


Conventions

Authentication

All endpoints require a Better-Auth admin session and a role granting the matching permission. Uses the platformVendorSetting resource — semantically the same action as the platform-vendor settings override surface in settings.md, so the same role can grant both.

EndpointPermission
GET /admin/vendors/:vendorId/shipping/configplatformVendorSetting: read
PATCH /admin/vendors/:vendorId/shipping/configplatformVendorSetting: update
GET /admin/shipping/orders/:id/trackingorder: view
POST /admin/shipping/orders/:id/trackingorder: update
DELETE /admin/shipping/orders/:id/tracking/:eventIdorder: update

The tracking endpoints use the order resource, not platformVendorSetting — they act on a sub-order, and ops staff who can fulfill a bag can also drive its timeline.

Response envelope

Successful responses are wrapped by ResponseInterceptor:

{
  "data": <payload>,
  "message": "Success",
  "statusCode": 200,
  "metadata": { /* optional, e.g. pagination */ }
}

Error envelope

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

Currency

flatRateSubunit and freeAboveSubunit are integer subunits (paise / cents).


Domain types

ShippingConfigResponse

type ShippingConfigResponse = {
  enabledProviders: string[];          // provider ids registered via the shipping plugin tokens
  flatRateSubunit: number;             // flat customer charge per vendor bag, in subunits
  freeAboveSubunit: number | null;     // bag subtotal at/above which shipping is free; null = always charge
};

Endpoints

GET /admin/vendors/:vendorId/shipping/config — Get config for a target vendor

Required permission: platformVendorSetting: read.

Path params

NameNotes
vendorIdTarget vendor id

Response 200ShippingConfigResponse.


PATCH /admin/vendors/:vendorId/shipping/config — Override config

Required permission: platformVendorSetting: update. Partial body — service maps to VendorSettingsService.setMany so unset keys are left untouched. Bypasses any forAdmin write guard on the underlying vendor-settings keys — platform staff can set any registered key.

Body

{
  "enabledProviders": ["self-handled", "clickpost"],
  "flatRateSubunit": 5000,                     // ₹50 in paise
  "freeAboveSubunit": 100000                   // free shipping at ≥ ₹1000 cart subtotal
}
FieldTypeConstraints
enabledProvidersstring[]?Non-empty when sent; each entry: registered provider id
flatRateSubunitint?>= 0
freeAboveSubunitint? | null>= 0 or explicit null to disable free-shipping

The body is strict() — unknown keys are rejected.

Response 200 — updated ShippingConfigResponse.

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod (unknown field, empty enabledProviders array, negative subunit)

Sub-order tracking timeline

Base path: /admin/shipping/orders/:id/tracking. :id is order_vendor.id. Unscoped — support drives any vendor's bag.

The request/response shapes are identical to the vendor routes; see vendor/shipping.md for ShippingEventResponse, the POST body, and the delivered / returned side effects. The only differences are the base path and that permissions replace vendor scoping.

EndpointWhat it does
GET /admin/shipping/orders/:id/trackingPaginated timeline, newest first (page, limit)
POST /admin/shipping/orders/:id/trackingAppend a checkpoint. delivered flips the sub-order; returned raises an RTO
DELETE /admin/shipping/orders/:id/tracking/:eventIdRemove a manually added checkpoint (409 for courier-fed rows)

This is what backs the Tracking timeline block on each vendor card in the admin order detail. For a self-handled delivery it is the only writer of the customer's tracking page after fulfillment seeds dispatched.

GET /admin/orders/:orderId/tracking is the different, order-wide read — the customer-shaped view across every sub-order, with stages. Use that to answer "where is it?", and these to change it.


  • admin-rbac — gates the config endpoints via platformVendorSetting:* and the tracking endpoints via order:*. See admin-rbac.md.
  • settings — same platformVendorSetting resource; shipping config is stored as a group inside the vendor-settings store. See settings.md.
  • shipping-self-handled, shipping-clickpost — provider plugins; enabledProviders[] references their registered ids. The platform (central warehouse) ClickPost account has its own admin surface — see shipping-clickpost.md.
  • cart — uses the customer-charge layer at quote time. See cart.md.
  • order — vendors pick the active provider at the pending→fulfilled transition; see order.md.

On this page