Blowhorn

Blowhorn publishes a public REST API at doc.blowhorn.com: API key auth, shipment orders, tracking, POD, serviceability, full WMS inbound, SKU and inventory, plus webhooks.

Blowhorn is a Bengaluru-based logistics company running same-day and hyperlocal delivery plus integrated fulfilment out of a network of micro-warehouses. It is unusual in this catalogue because it is both a carrier and a warehouse operator: alongside the expected shipment, tracking and proof-of-delivery endpoints, its API exposes a complete warehouse management surface with purchase orders, advance shipping notices, goods receipt notes, SKUs and inventory. Documentation is public at doc.blowhorn.com, with a sandbox, a Postman collection, published order statuses, real rate-limit headers and webhook subscription.

At a glance

What it is

Blowhorn is an Indian logistics company operating three product lines: Integrated Fulfilment (a network of micro-warehouses holding a brand's inventory close to its customers), Hyperlocal (delivery within roughly 8 km of a neighbourhood) and Transportation (dedicated fleet with trained drivers). It sells on a pay-per-use basis to D2C brands and retailers, and runs its own driver network rather than aggregating other couriers.

The micro-warehouse model is what shapes the API. A brand does not just hand Blowhorn parcels; it front-loads stock into Blowhorn hubs, and Blowhorn picks, packs and delivers. That is why the API has purchase orders, advance shipping notices and goods receipt notes on the inbound side, SKU and inventory master data in the middle, and shipping labels and manifests on the outbound side. For a commerce database this means Blowhorn can populate inventory and locations, not only shipments.

Blowhorn also publishes a status page at blowhorn.instatus.com and support contact at tech@blowhorn.net.

API access

  • Documentation: doc.blowhorn.com. Note the host is doc, singular. docs.blowhorn.com is a media CDN for the marketing site and returns HTTP 403 at its root, which is a common wrong turn.
  • The docs expose a GitBook llms.txt index and per-page .md variants, which makes the whole reference easy to pull programmatically.
  • Base URLs:
  • A Postman collection is offered with a "Run in Postman" button. The documented setup is to add the key in Postman as a header API_KEY with your key id as the value.
  • Two account types exist, customer and partner, with separate authentication endpoints and separate key issuance. A retailer is a customer; a delivery or fleet partner is a partner.
  • No official SDK is published. The docs ship Python and PHP samples for the authentication flow.
  • No API version appears in any path. The surface is unversioned, so expect changes without a version bump.
Warning

The docs warn explicitly that any request made with a valid API key affects real-time data in your Blowhorn account. Use the beta.blowhorn.com sandbox for anything exploratory, and keep sandbox and production keys in separate credential records.

Authentication

A single static API key authenticates everything. The only question is how you obtain it.

  1. Blowhorn emails the API key to a customer. Alternatively, call the authentication endpoint.
  2. Customer: POST /customer/auth with Base64-encoded username and password. Partner: POST /orders/customer/authtoken with the same shape. Both return the key:
{ "status": "PASS", "api_key": "Bj143Lm09qjQ" }
  1. Send the key on every subsequent request in an API_KEY header.
curl "https://blowhorn.com/api/orders/SH-22T70ZX/status" \
  -H "Content-Type: application/json" \
  -H "API_KEY: $BLOWHORN_API_KEY"
  1. No expiry, refresh or scope model is documented. Multi-account support is one key per channel_account_id.
Note

The published Python and PHP samples for the auth call are internally inconsistent: they send the Base64 credentials in an Authorization header using GET, while the reference describes a POST with username and password in the body, and the Python sample then Base64-decodes the returned api_key while the PHP sample uses it directly. Confirm the exact call and whether the returned key needs decoding before you build against it.

Objects we can read

Orders and order items

GET /orders/shipment/{orderId} returns the full order, keyed by the reference number you supplied at creation.

{
  "status": "PASS",
  "message": {
    "order_details": {
      "order_id": 4892552,
      "reference_number": "000000005-2-7",
      "awb_number": "SH-22T70ZX",
      "status": "Complete",
      "delivery_hub_sn": "Taj MG Road Bengaluru",
      "delivery_address": "MyCornerBakery, Hosa Road, Golden Hill Square, Bangalore, 560068, Karnataka, India",
      "delivery_postal_code": "560068",
      "pickup_address": "Taj MG Road, Bengaluru, Karnataka, India",
      "pickup_postal_code": "560001",
      "customer_name": "John Doe",
      "customer_mobile": 9876543210,
      "delivery_hub": "Koramangala [BH Microwarehouse]",
      "item_details": {
        "2714539": {
          "item_name": "Fusion Backpack",
          "item_quantity": 1,
          "item_qty_picked": 1,
          "item_qty_delivered": 1
        }
      },
      "return_address": "Distribution Logistics Infrastructure Pvt Ltd, Bengaluru, Karnataka, India",
      "return_postal_code": "562107",
      "return_hub": "testcustomer_bengaluru_hub",
      "cash_on_delivery": "59.00"
    }
  }
}

item_details is an object keyed by an internal item id, not an array, so it must be iterated as a map. item_qty_picked and item_qty_delivered alongside item_quantity mean partial fulfilment and partial delivery are both first-class. Customer name, mobile and both addresses are PII.

POST /orders/booking covers marketplace orders as a separate creation path.

Shipments and tracking

  • GET /orders/{AWB}/status returns the current status.
  • GET /orders/{orderId}/status/history returns the event history.
  • GET /shipment/order/{orderId}/get-estimated-arrival returns the ETA.
  • GET /order/{orderId}/get-driver-details returns the assigned delivery partner.

The status vocabulary is published in full:

Attempted is the NDR signal and Returned is the RTO signal. There is no separate NDR object or reason-code list.

Proof of delivery

GET /orders/shipment/{orderId}/get-pods returns the delivery documents:

{
  "status": "PASS",
  "message": [
    {
      "documnt_type": "Signature",
      "document_link": "https://blowhorn/media/order_1JHL9N",
      "uploaded_on": "12 Jan 2020, 04:30"
    }
  ]
}

The key is spelled documnt_type in the published sample. Treat that as the real field name until proven otherwise.

Serviceability and locations

GET /pincodes/ answers both "which pincodes does this city cover" and "is this pincode serviceable", with query parameters city, pincode and customer_hubs_only:

[
  { "pincodes": [560037, 560087, 560103], "blowhorn_hub": "Koramangala Hub" },
  { "pincodes": [560035, 560085], "blowhorn_hub": "Bellandur Hub" }
]

An unserviceable city returns a 400 with {"error": "blowhorn does not provide service in this city"}. customer_hubs_only switches the response between the customer's own hubs and Blowhorn's micro-warehouses.

GET /hubs/ and GET /hub/coverage complete the picture. Location master data is writable through POST /locationtypes, POST /storagetypes, POST /locationzones and POST /locations.

Inventory and products

This is the part that distinguishes Blowhorn from a pure carrier.

Tracking level models nested units of measure ("1 BOX = 10 EACHES, 1 PALLET = 100 BOXES"), and pack config links a SKU's packaging to that tracking level. Inventory is a physically tagged stock record linked to a SKU and a warehouse location. Inventory transactions are emitted on every merge or split (receiving, shipping and so on) and are explicitly described as an event stream for downstream applications, which makes GET /wms/inventory-transaction the right endpoint for an incremental stock feed.

Inbound

GET/POST /wms/client (the inventory owner), /wms/supplier, /wms/purchase-order, /wms/advance-shipping-notice, and GET /wms/goods-receipt-note. This is a full receiving workflow: raise a purchase order, send an ASN, and read the GRN of what actually arrived with SKU, quantity and price.

Drivers

GET /vehicle/getvehicleclass, GET /driver/availability, GET /api/drivers/drivereligibility, GET /api/drivers/detail, GET /api/drivers/balance and POST /api/drivers/deduction. Relevant only if you are a fleet partner, not a retailer.

Payments and settlements

No settlement API. cash_on_delivery is an order field, and driver balance and deduction endpoints exist on the partner side, but there is no COD remittance statement.

Writing back: listings, price and stock

Not applicable as channel listings, this is a carrier and 3PL: Blowhorn has no storefront, no channel price and no buyable listing, so there is nothing to write back in the listings sense.

Two genuine write surfaces do exist, and they matter.

Warehouse stock. POST and PUT /wms/skus maintain SKU master data, and POST /wms/inventory creates inventory records against a SKU and a location. This is warehouse stock at a 3PL, not sellable stock on a channel, but it is the authoritative quantity for anything Blowhorn fulfils, and it should feed the unified inventory table with location_id set to the Blowhorn hub.

Shipment lifecycle.

On POST /orders/shipment: reference_number is mandatory and must be unique; Blowhorn returns an AWB of the form SH-XXXXXX against it, and the same reference number may be reused if the order is cancelled. awb_number is optional on input and only needed if you label the parcel yourself. is_hyperlocal selects the hyperlocal contract rather than the shipment contract. Delivery and pickup hubs are optional and are deduced from the delivery pincode unless you want specific routing. Kitting is supported, where a KIT SKU expands to a preconfigured set of component SKUs.

Note the path inconsistency: cancellation is documented as PUT /api/orders/cancel/{orderId} while the base URL already ends in /api. Confirm whether the full path really is https://blowhorn.com/api/api/orders/cancel/... or whether the documentation double-counts the prefix.

Pickup is not a separate call; it follows from the pickup address on the order.

Webhooks and notifications

Three webhook topics, all registered through the same pattern:

POST /webhooks/subscribe, PUT /webhooks/update and GET /webhooks/list manage subscriptions. The subscription body carries callbackUrl, a headers object that Blowhorn will send back to you on every callback, and a verify_payload boolean:

{
  "callbackUrl": "https://myserver.com/send/callback/here",
  "headers": { "API_KEY": "bSd74acDFhjzy90vqml" },
  "verify_payload": true
}

The Order Status callback body, for event type updateOrderStatus:

{
  "WaybillNo": "SH-TESTAWB",
  "eventType": "updateOrderStatus",
  "OrderStatus": "Complete",
  "CourierComment": "",
  "StatusDateTime": "2022-07-21T11:33:00"
}
Warning

The documentation describes HMAC authentication in general terms, as a public key identifier plus a private key secret, but then states that "Blowhorn webhooks pass the Business Customer API Key in the API header for use". In other words, what is actually implemented looks like a shared secret echoed in a header you choose, not an HMAC over the request body. That proves the caller knows your key; it does not prove the body is unmodified. Compare the header in constant time, use an unguessable callback path, and read back the order status through GET /orders/{AWB}/status before acting on anything financial. No retry policy or timeout is documented either, so keep a reconciliation sweep.

Rate limits and pagination

Blowhorn publishes a real limit for the endpoint most likely to be hammered. GET /orders/{AWB}/status allows 1 request per second per customer, and exceeding it returns HTTP 429. Successful responses carry:

X-RateLimit-Limit: 1
X-RateLimit-Remaining: 5
X-RateLimit-Reset: 1

X-RateLimit-Limit is the ceiling for the period, X-RateLimit-Remaining is described in the docs as requests made so far, and X-RateLimit-Reset is a Unix timestamp for the reset. The published sample values are internally inconsistent (a limit of 1 with 5 remaining), so trust the headers on live responses rather than the sample.

No limits are published for any other endpoint, and no pagination model is documented anywhere. There is no cursor, page or token parameter in any listed endpoint.

Practical cadence: subscribe to the Order Status and Inventory Status webhooks as the primary feed; use GET /orders/{orderId}/status/history for reconciliation rather than polling status, since the per-second cap makes per-AWB polling unworkable at volume; pull GET /wms/inventory-transaction incrementally for stock; refresh GET /pincodes/ daily.

Mapping to the unified model

Gaps and open questions

  • The documentation footer says "Last updated 1 year ago". Confirm the current state before building.
  • The authentication samples contradict the reference on method, credential placement and whether the returned key must be Base64-decoded.
  • Webhook verification is described as HMAC but implemented, per the same page, as an echoed API key. Ask whether a real body signature is available.
  • No webhook retry policy, timeout or delivery guarantee is documented.
  • The cancellation path appears to double the /api prefix.
  • No pagination exists on any list endpoint, which will be a problem for GET /wms/skus and GET /wms/inventory at any real catalogue size. Ask how large result sets are handled.
  • Rate limits are published for exactly one endpoint. Get numbers for the WMS endpoints before running a stock sync.
  • No COD remittance or settlement reporting exists despite COD being supported.
  • ClickPost lists Blowhorn as an integrated carrier with order creation, cancellation, polling, webhook, POD, NDR and pickup request supported, with labels generated by ClickPost. Blowhorn's own API generates labels, so treat the aggregator matrix as describing ClickPost's implementation rather than Blowhorn's capability.

Sources

  • Blowhorn API Documentation, read 2026-09-21, including the machine-readable index at doc.blowhorn.com/llms.txt and the full text at doc.blowhorn.com/llms-full.txt. Source of every endpoint, field, status value, rate-limit header and sample above.
  • Blowhorn homepage, read 2026-09-21. Product lines Integrated Fulfilment, Hyperlocal and Transportation, micro-warehouse model, pay-per-use positioning.
  • Host probing on 2026-09-21: docs.blowhorn.com returns HTTP 403 at its root and serves marketing images, api.blowhorn.com returns HTTP 503, developer.blowhorn.com and developers.blowhorn.com do not resolve. The documentation host is doc.blowhorn.com.
  • ClickPost, Blowhorn carrier integration, read 2026-09-21. Third-party capability matrix.