Supercommerce API Docs
Admin API

Shipping ClickPost Module — Admin surface

Admin-facing HTTP surface for the platform (central warehouse) ClickPost account — credentials, pickup address, courier map, parcel defaults, webhook secret, and the live active-courier lookup. This is the account used when an admin fulfills a sub-order with credentialSource=platform.

Admin-facing HTTP surface for the platform (central warehouse) ClickPost account — credentials, pickup address, courier partner map, parcel defaults, webhook secret, and the live active-courier lookup. This is the account used when an admin fulfills a sub-order with credentialSource=platform; sellers shipping under their own ClickPost account configure the mirror surface in vendor/shipping-clickpost.md.

Source: api-modules/shipping-clickpost/src/controllers/admin-clickpost-config.controller.ts.

The endpoints are a typed wrapper over the admin.shipping.clickpost.* settings group. They exist as a dedicated surface because clickpost.courier_map is a record of objects — the generic settings editor can edit an existing value but cannot add keys to it.


Conventions

Authentication

All endpoints require a Better-Auth admin session and a role granting the matching permission. Uses the adminSetting resource — the same resource that gates the underlying settings group, so no separate grant is needed to manage ClickPost.

EndpointPermission
GET /admin/shipping/clickpost/configadminSetting: read
GET /admin/shipping/clickpost/active-couriersadminSetting: read
PATCH /admin/shipping/clickpost/configadminSetting: update

Response envelope

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

Error envelope

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

Domain types

Identical to the vendor surface — see vendor/shipping-clickpost.md for the full field-by-field notes on ClickPostCourierEntry, weights/dimensions units, and where to obtain cpId / accountCode.

ClickPostConfigResponse

type ClickPostConfigResponse = {
  apiKey: string;
  username: string;
  webhookSecret: string;
  pickupPincode: string;                   // Indian 6-digit
  enabledCouriers: string[];
  courierMap: Record<string, { cpId: number; accountCode: string }>;

  pickupName: string;
  pickupAddress: string;
  pickupCity: string;
  pickupState: string;
  pickupPhone: string;
  pickupEmail: string;
  pickupTin: string;   // TIN / GSTIN

  defaultParcel: {
    weight: number;    // grams
    length: number;    // centimetres
    breadth: number;
    height: number;
  } | null;

  /** Computed from PUBLIC_API_BASE_URL + the platform webhook route.
   *  Null when PUBLIC_API_BASE_URL isn't set on the API process. */
  webhookUrl: string | null;
};

Unlike the vendor variant, webhookUrl resolves to the platform route (/webhooks/shipping/clickpost/platform), not a per-vendor one.

ActiveCourier

type ActiveCourier = {
  code: string;         // our internal courier code, e.g. "DELHIVERY"
  courierName: string;  // name as shown on the ClickPost dashboard
  cpId: number;
  accountCode: string;
};

Platform ClickPost config

Base path: /admin/shipping/clickpost.

GET /admin/shipping/clickpost/config — Get config

Returns the platform warehouse ClickPost credentials, pickup address, courier map, parcel defaults, and the resolved platform webhook URL.

Response 200ClickPostConfigResponse.

{
  "data": {
    "apiKey": "cp_live_...",
    "username": "acme-warehouse",
    "webhookSecret": "whsec_...",
    "pickupPincode": "560001",
    "enabledCouriers": ["DELHIVERY", "BLUEDART"],
    "courierMap": {
      "DELHIVERY": { "cpId": 4, "accountCode": "DL_ACME_002" },
      "BLUEDART": { "cpId": 12, "accountCode": "BD_ACME_001" }
    },
    "pickupName": "Acme Central Warehouse",
    "pickupAddress": "123 Industrial Area",
    "pickupCity": "Bengaluru",
    "pickupState": "Karnataka",
    "pickupPhone": "9876543210",
    "pickupEmail": "dispatch@acme.com",
    "pickupTin": "29ABCDE1234F1Z5",
    "defaultParcel": { "weight": 500, "length": 20, "breadth": 15, "height": 10 },
    "webhookUrl": "https://api.example.com/webhooks/shipping/clickpost/platform"
  },
  "message": "Success",
  "statusCode": 200
}

Errors

StatusCodeWhen
403FORBIDDENCaller lacks adminSetting:read

GET /admin/shipping/clickpost/active-couriers — Active couriers

Calls ClickPost's fetch-accounts API with the saved platform API key and returns only the active accounts whose courier name matches a platform-supported code (CLICKPOST_SUPPORTED_COURIERS), each with its cpId and accountCode. The config UI uses this to offer only couriers that will actually work and to prefill the courier map.

Returns an empty array — never an error — when the API key isn't saved yet or ClickPost is unreachable, so an optional lookup never breaks the page.

Response 200ActiveCourier[].

{
  "data": [
    {
      "code": "DELHIVERY",
      "courierName": "Delhivery",
      "cpId": 4,
      "accountCode": "DL_ACME_002"
    }
  ],
  "message": "Success",
  "statusCode": 200
}

Errors

StatusCodeWhen
403FORBIDDENCaller lacks adminSetting:read

PATCH /admin/shipping/clickpost/config — Update config

Partial update — fields not in the body are left untouched. The body is .strict() so unknown keys are rejected at the zod layer. Each field maps to a setting under admin.shipping.clickpost.* and is written via SettingsService.setMany (audit row per changed key, one transaction).

Body — same shape as the vendor PATCH:

{
  "apiKey": "cp_live_...",
  "username": "acme-warehouse",
  "webhookSecret": "whsec_...",
  "pickupPincode": "560001",
  "enabledCouriers": ["DELHIVERY", "BLUEDART"],
  "courierMap": {
    "DELHIVERY": { "cpId": 4, "accountCode": "DL_ACME_002" },
    "BLUEDART": { "cpId": 12, "accountCode": "BD_ACME_001" }
  },
  "pickupName": "Acme Central Warehouse",
  "pickupAddress": "123 Industrial Area",
  "pickupCity": "Bengaluru",
  "pickupState": "Karnataka",
  "pickupPhone": "9876543210",
  "pickupEmail": "dispatch@acme.com",
  "pickupTin": "29ABCDE1234F1Z5",
  "defaultParcel": { "weight": 500, "length": 20, "breadth": 15, "height": 10 }
}
FieldTypeConstraintsSetting key
apiKeystring?Trimmed; 1..500 charsclickpost.api_key
usernamestring?Trimmed; 1..200 charsclickpost.username
webhookSecretstring?Trimmed; 32..500 charsclickpost.webhook_secret
pickupPincodestring?Trimmed; exactly 6 digits (/^\d{6}$/)clickpost.pickup_pincode
enabledCouriersstring[]?Each entry non-emptyclickpost.enabled_couriers
courierMapRecord<string, { cpId: number; accountCode: string }>?cpId positive int; accountCode 1..120 charsclickpost.courier_map
pickupNamestring?Trimmed; 1..120 charsclickpost.pickup_name
pickupAddressstring?Trimmed; 1..500 charsclickpost.pickup_address
pickupCitystring?Trimmed; 1..120 charsclickpost.pickup_city
pickupStatestring?Trimmed; 1..120 charsclickpost.pickup_state
pickupPhonestring?Trimmed; 6..20 charsclickpost.pickup_phone
pickupEmailstring?Valid email, max 200 charsclickpost.pickup_email
pickupTinstring?Trimmed; 1..40 charsclickpost.pickup_tin
defaultParcel{ weight, length, breadth, height }?All four positive integers; weight in grams, rest in cm. Required in practice — see belowclickpost.default_parcel

defaultParcel is not optional in practice. getCredentials rejects a config without it, and buildCreateOrderPayload sends length / breadth / height from it on every shipment — ClickPost's v3 payload carries no per-item dimensions, so this is the only source. Only weight behaves as a true fallback (item.weight ?? defaultParcel.weight).

enabledCouriers gates nothing on the server. It drives the config UI's courier picker, but no code path validates a shipment against it: resolveCourier and methodsForPlatform both key off courierMap. A courier is usable when it has a courierMap entry, whether or not it appears in enabledCouriers.

Response 200 — updated ClickPostConfigResponse (re-read after the write).

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod, or a value fails its registry schema
403FORBIDDENCaller lacks adminSetting:update

Fulfillment flow

When an admin marks a sub-order fulfilled via POST /admin/orders/vendors/:orderVendorId/fulfilled with providerId="clickpost" and credentialSource="platform", ClickPostShippingProvider.createShipment reads these settings instead of the vendor's. credentialSource="vendor" reads the seller's own vendor.admin.shipping.clickpost.* keys.

GET /admin/orders/vendors/:orderVendorId/fulfillment-options returns both accounts with their selectable couriers; the platform account's list is the intersection of CLICKPOST_SUPPORTED_COURIERS with the keys of the courierMap configured here — so a courier with no mapping simply cannot be picked.

The remaining mechanics (v3 payload construction, async 102/202 handling, variant weight/dimension fallbacks) are identical to the vendor flow — see vendor/shipping-clickpost.md.


Webhook receiver

Tracking events for platform-fulfilled bags arrive at POST /webhooks/shipping/clickpost/platform, HMAC-verified against admin.shipping.clickpost.webhook_secret and resolved by AWB globally (not vendor-scoped). See webhooks/shipping-clickpost.md.


  • shipping — provider-agnostic config; clickpost must appear in admin.shipping.enabled_providers. See admin/shipping.md.
  • settingsadmin.shipping.clickpost.* keys live in the admin settings registry under the shipping group; these endpoints are a typed wrapper. See admin/settings.md.
  • order — admin fulfillment dispatch and the credentialSource choice. See admin/order.md.
  • admin-rbac — gates every endpoint via adminSetting:*. See admin/admin-rbac.md.

On this page