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.
| Endpoint | Permission |
|---|---|
GET /admin/vendors/:vendorId/shipping/config | platformVendorSetting: read |
PATCH /admin/vendors/:vendorId/shipping/config | platformVendorSetting: update |
GET /admin/shipping/orders/:id/tracking | order: view |
POST /admin/shipping/orders/:id/tracking | order: update |
DELETE /admin/shipping/orders/:id/tracking/:eventId | order: 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
statusCode | errorCode examples |
|---|---|
| 400 | BAD_REQUEST, VALIDATION_ERROR |
| 401 | UNAUTHORIZED |
| 403 | FORBIDDEN |
| 404 | NOT_FOUND |
| 500 | INTERNAL_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
| Name | Notes |
|---|---|
vendorId | Target vendor id |
Response 200 — ShippingConfigResponse.
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
}| Field | Type | Constraints |
|---|---|---|
enabledProviders | string[]? | Non-empty when sent; each entry: registered provider id |
flatRateSubunit | int? | >= 0 |
freeAboveSubunit | int? | null | >= 0 or explicit null to disable free-shipping |
The body is strict() — unknown keys are rejected.
Response 200 — updated ShippingConfigResponse.
Errors
| Status | Code | When |
|---|---|---|
| 400 | VALIDATION_ERROR | Body 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.
| Endpoint | What it does |
|---|---|
GET /admin/shipping/orders/:id/tracking | Paginated timeline, newest first (page, limit) |
POST /admin/shipping/orders/:id/tracking | Append a checkpoint. delivered flips the sub-order; returned raises an RTO |
DELETE /admin/shipping/orders/:id/tracking/:eventId | Remove 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.
Related modules
admin-rbac— gates the config endpoints viaplatformVendorSetting:*and the tracking endpoints viaorder:*. Seeadmin-rbac.md.settings— sameplatformVendorSettingresource; shipping config is stored as a group inside the vendor-settings store. Seesettings.md.shipping-self-handled,shipping-clickpost— provider plugins;enabledProviders[]references their registered ids. The platform (central warehouse) ClickPost account has its own admin surface — seeshipping-clickpost.md.cart— uses the customer-charge layer at quote time. Seecart.md.order— vendors pick the active provider at the pending→fulfilled transition; seeorder.md.
Shipping Labels — Admin
HTTP surface for an admin to batch-print courier shipping labels for many orders at once — one label per vendor on them — merged into a single downloadable PDF, with async status polling and retry of failed labels.
Sign-in Methods — Admin
Read-only option feed describing each customer sign-in method (email, Google, Apple, phone), which platforms this deployment can offer it on, and where it is enabled — consumed by the settings UI's toggle-matrix on admin.sign_in.enabled_methods.