Supercommerce API Docs
Vendor API

Shipping ClickPost Module — Vendor surface

Vendor-facing HTTP surface for per-vendor ClickPost integration — credentials, pickup pincode, webhook secret, and the courier allow-list. ClickPost is one shipping provider…

Vendor-facing HTTP surface for per-vendor ClickPost integration — credentials, pickup pincode, webhook secret, and the courier allow-list. ClickPost is one shipping provider plugin (see shipping.md for the provider-agnostic surface and order.md for the fulfillment dispatch).

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


Conventions

Authentication

Both endpoints require a Better-Auth bearer session with an active vendor.

Authorization: Bearer <session-token>

The active vendor is resolved via resolveActiveVendorId(session). Sessions missing an active vendor are rejected with 403 Forbidden. There is no platform RBAC permission — vendor users are not platform staff.

Tenant scoping

Every read and write scopes to the active vendor's id. Config is persisted via VendorSettingsService under vendor.admin.shipping.clickpost.*, so writes are also subject to the registry's forAdmin: true flag — but the controller calls setMany(..., { allowAdminOnly: false }), so any key marked admin-only in the registry would reject with 403 (same rule as vendor/settings).

Response envelope

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

Error envelope

statusCodeerrorCode examples
400BAD_REQUEST, VALIDATION_ERROR
401UNAUTHORIZED
403FORBIDDEN (no active vendor, or payload includes a forAdmin: true key)
500INTERNAL_SERVER_ERROR

Domain types

ClickPostConfigResponse

type ClickPostConfigResponse = {
  apiKey: string;
  username: string;
  webhookSecret: string;
  pickupPincode: string;                   // Indian 6-digit
  enabledCouriers: string[];               // courier ids inside ClickPost
  /** Fully-qualified URL the vendor should configure in ClickPost's
   *  webhook settings. Computed from PUBLIC_API_BASE_URL + the per-vendor
   *  route. Null when PUBLIC_API_BASE_URL isn't set on the API process —
   *  in that case vendor docs should fall back to manual instructions. */
  webhookUrl: string | null;
};

ClickPost config

Base path: /vendor/shipping/clickpost/config.

GET /vendor/shipping/clickpost/config — Get config

Returns the active vendor's ClickPost credentials, pickup pincode, courier allow-list, and the resolved webhook URL.

Response 200ClickPostConfigResponse.

{
  "data": {
    "apiKey": "cp_live_...",
    "username": "acme-bakery",
    "webhookSecret": "whsec_...",
    "pickupPincode": "560001",
    "enabledCouriers": ["bluedart", "delhivery"],
    "webhookUrl": "https://api.example.com/webhooks/shipping/clickpost/01J9..."
  },
  "message": "Success",
  "statusCode": 200
}

Errors

StatusCodeWhen
403FORBIDDENNo active vendor on session

PATCH /vendor/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. The controller maps each field to a setting under vendor.admin.shipping.clickpost.* and writes via VendorSettingsService.setMany (audit row per changed key).

Body

{
  "apiKey": "cp_live_...",
  "username": "acme-bakery",
  "webhookSecret": "whsec_...",
  "pickupPincode": "560001",
  "enabledCouriers": ["bluedart", "delhivery"]
}
FieldTypeConstraintsSetting key
apiKeystring?Trimmed; 1..500 charsclickpost.api_key
usernamestring?Trimmed; 1..200 charsclickpost.username
webhookSecretstring?Trimmed; 8..500 charsclickpost.webhook_secret
pickupPincodestring?Trimmed; exactly 6 digits (/^\d{6}$/)clickpost.pickup_pincode
enabledCouriersstring[]?Each entry non-emptyclickpost.enabled_couriers

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

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod (unknown key, short secret, bad pincode)
403FORBIDDENNo active vendor on session, or payload maps to a forAdmin: true key

Webhook receiver

The ClickPost webhook receiver itself is not on the vendor surface — it's an unauthenticated public endpoint that verifies the per-vendor webhookSecret from the request signature and lands rows on shipping_event. See the webhooks documentation under separated/webhooks/ for that surface.


  • shipping — provider-agnostic config (enabledProviders, flat rate, tracking events). clickpost must appear in vendor.admin.shipping.enabled_providers for these credentials to be used at fulfill time. See shipping.md.
  • settingsvendor.admin.shipping.clickpost.* keys live in the vendor settings registry; this controller is a typed wrapper over vendor-settings. See settings.md.
  • orderPOST /vendor/orders/:id/fulfilled with providerId="clickpost" dispatches to ClickPostProvider.createShipment() which reads these credentials.

On this page