NimbusPost is an Indian shipping aggregator for D2C brands and small marketplace sellers. It resells negotiated rates across roughly 25 to 30 domestic and international couriers (Delhivery, Blue Dart, DTDC, XpressBees, Ecom Express, Shadowfax, Amazon Shipping and others), and sells the usual aggregator bundle around them: rate comparison at checkout, label and manifest generation, branded tracking, NDR calling, RTO reduction and COD remittance. Its Partners API is published openly as a Postman collection and there is an official PHP SDK, so it is one of the more tractable Indian aggregator integrations.
At a glance
What it is
NimbusPost (Nimbus Technologies, Gurugram) launched in 2019 and targets the small to mid D2C seller: Shopify, WooCommerce and marketplace sellers who do not have their own carrier contracts. The company publishes seller apps on both app stores and markets COD confirmation, an RTO suite, same day and next day delivery, hyperlocal delivery and a fulfilment (warehousing) arm alongside the aggregation business.
For the unified model it is a source of shipments only. It is not a sales channel, so orders inside NimbusPost are shipment orders, not commerce orders: they are created by the seller or pulled from the seller's connected store, and they carry only the fields a courier needs.
API access
- Self-serve. Create a seller account at nimbuspost.com and log in at
app.nimbuspost.com. The same email and password authenticate the API. - Base URL:
https://api.nimbuspost.com/v1/. Support is by email to tech@nimbuspost.com; there is no developer console, no app registration and no approval step documented. - There is an older API on a different host,
https://ship.nimbuspost.com/api/, authenticated with a staticNP-API-KEYheader. The official SDK still carries it as its "V1" module. Treat it as legacy and build againstapi.nimbuspost.com/v1. - Official SDK: PHP, published by the NimbusPost engineering org at tech-nimbuspost/nimbuspost-api, installable as
composer require nimbuspost/nimbuspost. No other first party SDK exists. Several unaffiliated Python and WooCommerce packages exist on GitHub and should be treated as community code. - No sandbox. Every call hits the live account.
Authentication
A two step JWT exchange, one credential pair per seller account.
- POST the account email and password to the login endpoint.
- Read the JWT out of
data. It is returned as a bare string, not an object. - Send it as
Authorization: Beareron every subsequent request, alongsideContent-Type: application/json. - Re-login when it expires. There is no refresh token.
POST /v1/users/login HTTP/1.1
Host: api.nimbuspost.com
Content-Type: application/json
{
"email": "seller@example.com",
"password": "12376767"
}
{
"status": true,
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE2MTE3MzY3MDgs..."
}
Decoding the sample token published in the collection, the claims are iat, jti, nbf, exp and a data object carrying user_id and parent_id. The gap between iat and exp in the sample is 10,800 seconds, so the token lifetime is 3 hours. Cache the token and refresh on expiry or on the first 401, do not log in per request.
parent_id in the token implies a parent and child account model, which is how sub sellers or franchise accounts are likely represented, but the multi account behaviour is not documented. For several sellers, hold one email, password and token per account.
curl -X GET "https://api.nimbuspost.com/v1/courier" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json"
Failed login returns HTTP 401 with {"status": false, "message": "Invalid email or password"}. Every endpoint uses the same envelope: a boolean status, a message on failure, and data on success.
Objects we can read
Orders
The Partners API has no orders read. Orders exist only as the request body of a shipment creation call, keyed on the seller's own order_number, and the creation response returns a NimbusPost order_id. The legacy ship.nimbuspost.com/api/ host does expose orders, orders/{id}, orders/create, orders/cancel, orders/ship and orders/autoship_order, which the official PHP SDK wraps as getOrdersList, getSpecificOrder, createOrder, cancelOrder and shipByOrderId. Those routes are not in the published Partners collection, so their request and response shapes are unverified.
Shipments and tracking
Single shipment: GET https://api.nimbuspost.com/v1/shipments/track/{awb}. No body parameters.
Bulk: POST https://api.nimbuspost.com/v1/shipments/track/bulk with up to 100 AWBs per call.
{
"status": true,
"data": [
{
"id": "123",
"order_id": "456",
"order_number": "#001",
"created": "2022-08-25",
"awb_number": "4152919624263",
"rto_awb": "",
"courier_id": "1",
"warehouse_id": "113",
"rto_warehouse_id": "113",
"status": "pending pickup",
"rto_status": "",
"shipment_info": "MUM/KCK",
"history": [
{
"status_code": "PP",
"location": "Gurgaon_Behrampur_C (Haryana)",
"event_time": "2022-08-25 12:01",
"message": "Manifest uploaded"
}
]
}
]
}
Status codes: PP pending pickup, IT in transit, EX exception, OFD out for delivery, DL delivered, RT RTO, RT-IT RTO in transit, RT-DL RTO delivered.
Note the separate rto_awb and rto_status: an RTO leg gets its own waybill, so the return journey is a second shipment identity on the same record.
There is no pagination on either tracking call. Bulk tracking is the pagination: keep the set of open AWBs and read them 100 at a time.
NDR
GET https://api.nimbuspost.com/v1/ndr returns the current NDR list.
{
"status": true,
"data": [
{
"awb_number": "NMBC0002111111",
"event_date": "2021-04-05",
"courier_remarks": "Customer Not Responding",
"total_attempts": "1"
}
]
}
The official SDK passes a per_page parameter to this endpoint, so paging exists, but no page parameter or total count is documented in the collection.
Couriers, serviceability and rates
GET /v1/courierreturns the couriers enabled on the account as{id, name}pairs, for example{"id": "5", "name": "Bluedart Express"},{"id": "6", "name": "Delhivery Surface"}. Weight slabs are separate courier ids, not a parameter.GET /v1/courier/serviceabilityreturns the entire pincode table with a COD and a prepaid flag per pincode. The sample carries"count": 29070, so this is a full dump, not a lookup. Cache it rather than calling it per order.POST /v1/courier/serviceabilityis the rate and serviceability check for one lane. Request body:origin,destination,payment_type(codorprepaid),order_amount(required for COD), and optionalweightin grams (default 500),length,breadth,heightin cm (default 10).
{
"status": true,
"data": [
{
"id": "8",
"name": "DTDC Air",
"freight_charges": 61.36,
"cod_charges": 40.12,
"total_charges": 101.48,
"min_weight": 500,
"chargeable_weight": 1000
}
]
}
Locations
Not in the Partners API. The legacy host exposes warehouse and warehouse/create through the SDK's getWarehousesList and createWarehouse. In the Partners API a pickup location is supplied inline on each shipment as the pickup object, and a warehouse_id and rto_warehouse_id come back on the tracking read.
Not available
No products, listings, inventory, customers or settlements. No proof of delivery endpoint. No COD remittance endpoint, despite COD remittance being a marketed feature, so payouts must come from the seller panel.
Writing back: listings, price and stock
Not applicable, this is a carrier aggregator. NimbusPost holds no catalogue, price or stock. The write path is the shipment lifecycle.
Create a shipment and get an AWB
POST https://api.nimbuspost.com/v1/shipments
{
"order_number": "#001",
"payment_type": "cod",
"order_amount": 1000,
"shipping_charges": 40,
"cod_charges": 30,
"discount": 100,
"package_weight": 300,
"package_length": 10,
"package_breadth": 10,
"package_height": 10,
"request_auto_pickup": "yes",
"consignee": {
"name": "Customer Name",
"address": "190, ABC Road",
"address_2": "Near Bus Stand",
"city": "Mumbai",
"state": "Maharastra",
"pincode": "400001",
"phone": "9999999999"
},
"pickup": {
"warehouse_name": "warehouse 1",
"name": "Vikalp Sharma",
"address": "140, MG Road",
"city": "Gurgaon",
"state": "Haryana",
"pincode": "122001",
"phone": "9999999999"
},
"order_items": [
{ "name": "product 1", "qty": "18", "price": "100", "sku": "sku001" }
],
"courier_id": "1",
"is_insurance": "0",
"tags": "tag1, tag2"
}
payment_type accepts cod, prepaid and reverse, so a return pickup is created through the same endpoint. package_weight is in grams and dimensions are in centimetres. order_number is capped at 20 characters. request_auto_pickup: "yes" raises the courier pickup request in the same call, which is why there is no separate pickup endpoint in this API version. The docs warn that order_amount is not computed server side: send the correct total or COD collection will be wrong.
{
"status": true,
"data": {
"order_id": 3351555,
"shipment_id": 1929242,
"awb_number": "59632220664",
"courier_id": "5",
"courier_name": "Bluedart",
"status": "booked",
"additional_info": "BOM / TEC",
"payment_type": "cod",
"label": "http://nimubs-assets.s3.amazonaws.com/labels/20210127140158-79.pdf"
}
}
The label PDF URL is returned inline. There is no separate label endpoint in the Partners API (the legacy host has shipments/label).
Hyperlocal
POST /v1/shipments/hyperlocal takes the same request body plus latitude and longitude on both consignee and pickup, and accepts "courier_id": "autoship" to let NimbusPost choose. Only cod and prepaid are valid here.
Manifest and cancel
POST /v1/shipments/manifestwith{"awbs": ["4152911775885", "NMBC0001789312"]}.POST /v1/shipments/cancelwith{"awb": "59632218892"}. Failure returns HTTP 404 with"Unable to cancel".
NDR actions
POST /v1/ndr/action takes an array of up to 100 actions. Supported action values are re-attempt (with action_data.re_attempt_date), change_address (name, address_1, address_2) and change_phone (phone). The response is an array with one {status, awb, message} per element, so partial success is normal. An action is only accepted while the courier has an open exception on the AWB.
Webhooks and notifications
No webhooks are published in the Partners API collection, and the official SDK has no callback registration. NimbusPost markets branded tracking pages and customer notifications, which are sent by NimbusPost to the buyer, not to the seller's server. Assume pull only unless the account manager confirms otherwise.
Recommended polling: keep the set of AWBs that are not in a terminal state (DL, RT-DL, cancelled), read them through shipments/track/bulk in batches of 100 every 20 to 30 minutes, and tighten to 10 minutes for anything in OFD. Poll GET /v1/ndr once or twice a day, since NDR is a human workflow with same day SLAs rather than a real time one. Refresh the full pincode serviceability dump weekly, not per order.
Rate limits and pagination
No rate limits, quota headers, burst allowance or 429 semantics are published anywhere in the collection, the SDK or the site. The only stated batch limits are 100 AWBs per bulk tracking call and 100 actions per NDR action call.
Pagination is thin. Bulk tracking has none (batch by identifier). NDR list takes per_page in the SDK but no documented page cursor. The serviceability dump returns all 29,000 or so rows in one response with a count, which is a heavy call: fetch it on a schedule, never in a request path.
Given the unpublished limits, serialise calls, cap concurrency at a small number, and back off on any 5xx.
Mapping to the unified model
Gaps and open questions
- No webhook mechanism is documented. If NimbusPost has added one since the collection was last revised, it is not public.
- Rate limits are entirely unpublished, as are quota headers and any 429 behaviour.
- The token lifetime of 3 hours is derived by decoding the sample JWT in the published collection, not from a stated figure. Confirm before hard coding it.
parent_idin the JWT suggests parent and child accounts, but sub account access, scoping and whether one token can act across accounts are undocumented.- The legacy
ship.nimbuspost.com/api/surface (orders, warehouse, label, pickups) is only visible through the SDK source. Its request and response shapes, and whether it is still supported, are unverified. - No proof of delivery endpoint, and no COD remittance or settlement endpoint despite COD being a headline feature.
- No pagination contract on the NDR list beyond a
per_pageargument in the SDK. - No changelog, versioning policy or deprecation notice. The API has been
v1throughout and the collection carries no version tag.