Shadowfax is one of India's largest last-mile logistics companies, running express e-commerce delivery, reverse pickups, hyperlocal and quick commerce out of Bengaluru. For a connector it is a carrier, not a sales channel: the objects that matter are serviceability by pincode, order placement with AWB and label, tracking with event history, proof of delivery, delivery failure and RTO or RTS, and cancellation. Unusually among Indian carriers, Shadowfax runs a genuinely public developer platform at developer.shadowfax.in with a staging environment, published status vocabulary, webhook documentation and an interactive API reference. The docs were last modified on 2026-08-02, so they are current.
At a glance
What it is
Shadowfax is an Indian third-party logistics company headquartered in Bengaluru. As of 2026-09-21 its own site claims 200 crore or more parcels delivered, 3,500 or more trucks, 53 lakh or more square feet of operational space, 16,372 or more pincodes covered and 2.9 lakh or more quarterly delivery partners. It publishes investor relations material, so it is a late-stage or listed company rather than a startup.
It operates its own network rather than aggregating other carriers, which is the main structural difference from ShipDelight, Vamaship or iThink Logistics. Service lines are express parcel for e-commerce and D2C, returns, same-day and next-day delivery, hyperlocal, quick commerce dark-store delivery and fulfilment.
The developer platform splits by product, and the products do not share a backend. Forward, Reverse and Exchange sit on the "client gateway" (dale.shadowfax.in). Hyperlocal and Quick Commerce run on separate backends with their own serviceability model, their own token endpoint and their own throttling. Treat them as three different integrations, not one.
API access
- Documentation: developer.shadowfax.in/docs/home. Sections per product plus a Reference section covering authentication, serviceability, rate limits, errors, test data and a glossary, and an interactive API Reference playground.
- Base URLs for Forward, Reverse and Exchange:
- Staging and production use separate tokens. Staging mirrors production hubs, pincodes and routing logic; orders placed there do not trigger real pickups, but webhook callbacks still fire, so an end-to-end test is possible. Going live is documented as a base URL and token swap with no other code changes.
- Credentials come from the SFX 360 Partner Portal for most products. Hyperlocal Dedicated Store is the exception: its keys are shared by the Shadowfax team by email.
- A Test Data page publishes staging AWBs and pincodes, which is a good sign for integration speed.
- No official SDK is published. The docs ship curl samples throughout.
Authentication
Two methods, and which one you can use depends on the product.
Static token. Send the token on every request. It does not expire and there is no exchange or refresh step.
Authorization: Token your_api_token
OAuth 2.0 client credentials. Exchange a Base64-encoded client_id:client_secret pair for a short-lived Bearer token.
curl --location 'https://dale.staging.shadowfax.in/api/v1/clients/token/' \ --header "Authorization: Basic $CLIENT_BASIC_AUTH_TOKEN" \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials'
{
"access_token": "KrCTg7CZ8Ykr7do3gdRre0z6zCjObG",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "read write"
}
Then send the returned value in an Authorization: Bearer header. There is no refresh-token grant: to renew, repeat the credentials exchange.
Availability and token lifetime by product:
Multi-account support is one credential set per channel_account_id, plus a per-product dimension, since a client using both Forward and Quick Commerce holds two different credentials.
Objects we can read
Serviceability
One endpoint covers forward and reverse, and it is the part of this API most likely to catch you out.
GET /v1/clients/serviceability/?service=SERVICE&pincodes=PINCODE1,PINCODE2
An order is serviceable only if every leg is serviceable, and each leg is a separate service value, configured independently:
The response lists tiers available at the pincode, and you must match the tier to your account's supply chain. A Regular client and a Surface client read different tier names off the same response:
Other tier values appear in responses (Large, Slotted, large_RTO, large_dc_pickup, Connect_RTS). The docs are explicit: treat anything that is not your tier as not applicable, never as a fallback. A pincode appearing in the response is not the same as it being serviceable for you.
Hyperlocal and Quick Commerce use their own serviceability endpoints and do not follow this model.
Shipments and tracking
Single tracking, on API v4:
curl https://dale.staging.shadowfax.in/api/v4/clients/orders/SF1234567890/track/ \ -H "Authorization: Token your_api_token"
{
"message": "Success",
"order_details": {
"awb_number": "SF1234567890",
"client_order_id": "FWD-2026-001",
"status": "recd_at_fwd_hub",
"status_display": "Received At Forward Hub"
},
"tracking_details": [
{
"created": "2026-06-09T10:30:00Z",
"location": "BANGALORE HUB",
"status_id": "picked",
"status": "Picked Up",
"remarks": "Item picked up from seller",
"awb_number": "SF1234567890"
}
]
}
Addresses in the tracking response are partially masked for privacy. order_details.status and status_display are overwritten with the most recent tracking event, so they are derived, not independent.
Bulk tracking takes up to 50 AWBs per call and returns the same per-order shape as a list:
curl -X POST https://dale.staging.shadowfax.in/api/v4/clients/bulk_track/ \
-H "Authorization: Token your_api_token" \
-H "Content-Type: application/json" \
-d '{"awb_numbers": ["SF1234567890", "SF1234567891"]}'
Exceeding 50 returns HTTP 400 with "Number of AWBs exceeded. Max count allowed is 50".
The core status vocabulary is published. Branch on status_id:
The docs state plainly that there is no single generic NDR status: cid, nc, na and on_hold are the delivery-failure class, and "NDR" is the industry term, not a value you will see. Less common values exist for QC failures, e-way bill holds and hyperlocal partial delivery; the complete list is on the OrderDetails status field in the API Reference.
Proof of delivery
curl -X POST https://dale.staging.shadowfax.in/api/v1/clients/pod_details/ \
-H "Authorization: Token your_api_token" \
-H "Content-Type: application/json" \
-d '{"awb_numbers": ["SF1234567890"]}'
{
"message": "Success",
"pod_details": {
"SF1234567890": {
"recipient": "Customer",
"recipient_name": "Rahul Sharma",
"recipient_contact": "9876543210",
"recipient_signature": []
}
}
}
The same endpoint handles one AWB or up to 100. POD is populated only for orders in delivered, rts_d or rto_d. A single-AWB call with an invalid status returns 400; a bulk call returns an empty object for that AWB instead. Orders older than roughly 6 months also come back empty. Recipient name, contact and signature are PII.
Returns and cancellations
Reverse pickups are first-class orders, not a variant of a forward order. POST /api/v1/clients/pickup/orders/ with customer_details (who to collect from), return_details (where it goes, return_type of origin or seller), order_details and sku_details[] including return_reason. Reverse tracking is a different path: GET /api/v4/clients/requests/{awb_number}.
Exchange is a separate product that combines a forward delivery and a reverse pickup in one rider visit.
RTO and RTS are triggered through the Order Update endpoint's status_update field, not by a dedicated call.
Orders, order items, products, listings, inventory, settlements
No catalogue, inventory or settlement objects exist. Orders exist only as delivery orders you created. Line items travel as product_details[] (forward) or sku_details[] (reverse) with sku_name, sku_id, price, category and, on returns, return_reason.
Writing back: listings, price and stock
Not applicable, this is a carrier. Shadowfax holds no product catalogue, price or sellable stock, so there is nothing to write back in the listings sense.
The write surface is the delivery lifecycle:
Forward order creation is flat at the top level, with five blocks: customer_details, order_details, pickup_details, return_details and product_details[].
curl -X POST https://dale.staging.shadowfax.in/api/v3/clients/orders/ \
-H "Authorization: Token your_api_token" \
-H "Content-Type: application/json" \
-d '{
"customer_details": {"name":"Rahul Sharma","contact":"9876543210","address_line_1":"42 MG Road, Koramangala","city":"BANGALORE","pincode":560034},
"order_details": {"client_order_id":"FWD-TEST-001","product_value":1299.0,"payment_mode":"prepaid","cod_amount":0,"order_service":"Regular"},
"pickup_details": {"pickup_type":"seller","name":"TechStore Pvt Ltd","contact":"9876543211","address_line_1":"15 Industrial Area Phase 2","city":"BANGALORE","pincode":560058},
"return_details": {"return_type":"seller","name":"TechStore Pvt Ltd","contact":"9876543211","address_line_1":"15 Industrial Area Phase 2","city":"BANGALORE","pincode":560058},
"product_details": [{"sku_name":"Wireless Bluetooth Headphones","sku_id":"SKU-HEADPHONE-001","price":1299.0,"category":"Electronics"}]
}'
return_type of seller sends a failed delivery back to the seller; origin sends it to your warehouse. The response carries awb_number, which is the key for every later call. Marketplace is the default order type; Warehouse, D2D and MPS orders differ and are covered on the Order Types page.
Label generation returns a signed URL rather than bytes:
{
"message": "Success",
"data": { "label_url": "https://storage.googleapis.com/clients/labels/SF1234567890_labels.pdf" }
}
file_type is pdf or prn. The URL is valid for 2 days, so fetch and store the file. Labels can be generated only for Marketplace and Warehouse orders, only before pickup, and only one AWB per call. Asking for a label on an already-picked or cancelled order returns 400.
Pickup is not a separate call: pickup_details on the order is what schedules it.
Webhooks and notifications
Webhooks are the recommended integration for status, and the docs say so directly: they are real time and cost no rate-limit quota.
- Register the URL in the SFX 360 Partner Portal, or with your account manager during integration. Separate URLs can be set for forward and reverse orders. HTTPS is required.
- Method
POST,Content-Type: application/json, expected response200 OK, timeout 10 seconds. - There is no automatic retry. A failed or timed-out callback is dropped. Use tracking to reconcile.
- The same event may be delivered more than once, so the handler must be idempotent.
The callback body is not a fixed schema. It is a per-client template built by placeholder substitution, agreed with your account manager during integration. Available placeholders include {client_order_id}, {awb_number}, {status}, {status_id}, {remarks}, {current_location}, {rider_name}, {rider_contact}, {delivery_otp}, {cancellation_remarks}, {total_amount}, {payMode}, {codAmount}, {created_date}, {created_time}, {updated_date}, {updated_time}, {last_updated}, {otp_verified} (Y, N or NA), {client_id}, {recipient_info} (POD details, populated on delivered and rts_d), {estimatedDeliveryDate} and {shipmenttype} (F for the forward leg, R for an RTS or return leg). Timestamps are IST.
A payload built from those placeholders looks like:
{
"awb_number": "SF1234567890",
"client_order_id": "FWD-2026-001",
"status": "Received At Forward Hub",
"status_id": "recd_at_fwd_hub",
"remarks": "Item dispatched to destination hub",
"current_location": "BANGALORE HUB"
}
Two things follow from the template model. First, you cannot write a connector against a fixed callback schema: capture the agreed template per client account as configuration, and log the raw body before parsing. Second, no signature or HMAC verification is documented for callbacks. Use an unguessable callback path and verify the AWB exists on your side before writing anything.
Callbacks fire on assigned for pickup, picked, received at forward hub, assigned for customer delivery, out for delivery, delivered, the four delivery-failure statuses, reopen_ndr, RTS initiated and completed, and cancelled.
Rate limits and pagination
Shadowfax throttles per client and does not publish the numbers. The rate-limits page is unusually candid about what that means in practice:
- Throttling can trigger at low request volumes, well below any per-minute figure quoted to you. Do not size polling against an assumed ceiling.
- Recovery is not immediate. A block can persist for more than a minute, so a tight retry loop will keep failing.
- Limits differ between staging and production, so staging throughput is not a guide.
A throttled request returns HTTP 429 with the responseCode and responseMsg envelope:
{ "responseMsg": "Request Blocked Temporarily", "responseCode": 429 }
Published guidance, which is also the right sync design: prefer webhooks over polling; use bulk tracking (50 AWBs) rather than per-AWB calls; back off exponentially on both 429 and 5xx, starting at 1 second and capping at 60; cache serviceability results because pincode coverage changes infrequently.
Practical cadence: webhooks as the primary feed, one bulk tracking sweep per day over open AWBs as reconciliation, bulk POD (100 per call) at settlement close, serviceability refreshed weekly per origin.
There is no cursor or page token anywhere. Batching is by identifier list.
Mapping to the unified model
Gaps and open questions
- Rate limits are deliberately unpublished and are set per account. Get yours in writing before designing any sweep.
- The callback body is a per-client template, so there is no canonical webhook schema to code against. Get the agreed template from the account manager.
- No signature or HMAC verification is documented for callbacks, and there is no automatic retry, so reconciliation by tracking is mandatory rather than optional.
- API versions are mixed across the surface:
v1for token, serviceability, pickup orders and POD,v3for forward order placement,v4for tracking and bulk tracking, and an unversioned/api/client/generate_label/. There is no published deprecation policy. - No COD remittance or settlement API is documented anywhere in the developer platform, despite COD being a first-class field on orders. Ask whether a remittance feed exists.
- Hyperlocal and Quick Commerce were not read in depth for this page. They have separate backends, a separate token endpoint for Hyperlocal Marketplace, their own serviceability model and their own throttling.
- ClickPost lists Shadowfax as partner id 9 with order creation, cancellation, polling, webhook, POD and NDR supported but pickup request and AWB generation unsupported; Shadowfax's own docs document AWB pre-generation, so the aggregator matrix is not a reliable guide here.
Sources
- Shadowfax Developer Platform, read 2026-09-21. Pages read: Authentication, Serviceability, Rate Limits, Forward Logistics Quickstart, Order Lifecycle, Tracking, Label and POD, Callbacks, Bulk Operations, Reverse Logistics Quickstart. All carry "Last modified on August 2, 2026".
- Shadowfax homepage, read 2026-09-21. Scale claims and service lines.
- ClickPost, Shadowfax carrier integration, read 2026-09-21. Third-party capability matrix, partner id 9. It disagrees with Shadowfax's own documentation on AWB generation.