DTDC

DTDC API: a Shipsy hosted booking API keyed by an api-key header, a separate token based tracking service, and a live unauthenticated pincode serviceability call.

DTDC is one of India's oldest and largest express carriers, built on a franchise network that reaches well beyond where the venture funded e-commerce carriers go. For a commerce database it is a carrier connector: no orders, no listings, no stock. What it gives us is serviceability and transit time for an origin and destination pincode pair, a consignment number and a shipping label when we book, and a scan by scan tracking history. Its API is unusual in that it is really three separate systems with three separate authentication schemes: the booking API is hosted by Shipsy, the logistics software vendor, on dtdcapi.shipsy.io; tracking runs on DTDC's own blktracksvc.dtdc.com with a token exchange; and the pincode serviceability call sits on an older host and answers without any credentials at all.

At a glance

Note

The booking API is a Shipsy product with DTDC branding. That is why the paths read /api/customer/integration/consignment/... rather than anything DTDC specific, why the request body talks about consignments and service_type_id, and why the same path shape turns up in other Shipsy powered carriers. If you have built against Shipsy for another carrier, most of the work carries over.

What it is

DTDC Express Limited was founded in 1990 in Bangalore and grew through a franchise model rather than owned branches: thousands of franchise outlets, plus company owned hubs and a line haul network. That structure gives it depth in small towns where a pure e-commerce carrier has no presence, and it is why DTDC often appears in a seller's carrier mix as the option for hard to reach pincodes rather than as the volume default.

It carries both B2C parcels and B2B freight, and the service catalogue reflects that: the live serviceability response distinguishes B2C Priority, B2C Premium, B2C Smart Express, B2C Ground Economy, B2B Smart Express and more, each with its own code and its own published transit time. There is no marketplace and no catalogue. One connection is one DTDC customer code.

Smaller sellers usually reach DTDC through an aggregator. It appears as courier_company_id 6 (DTDC Surface), 18 (DTDC 5kg) and 82 (DTDC 2kg) inside Shiprocket, for example. A direct integration implies a contracted account.

API access

There is no console and no self serve signup. You contract with DTDC, receive a customer code, and the account team issues an api-key for the Shipsy booking API, a username and password for the tracking service (exchanged for an x-access-token), and the API documentation pack.

Hosts, all verified live on 2026-09-22 unless noted:

Probing the booking host on 2026-09-22 shows that everything under /api/customer/integration/ is gated by the API key middleware and returns {"error":{"message":"API key should be present","statusCode":401,"reason":"NO_API_KEY"}}, while a path outside that prefix, such as /api/customer/foo, returns {"error":{"status":404,"statusCode":404,"message":"NOT FOUND","reason":"NOT_FOUND"}}. The middleware sits above the router, so the 401 confirms the prefix is real but does not confirm any individual operation name.

There are no official DTDC SDKs. A community PHP SDK is the most complete public artefact and is cited in Sources.

Authentication

Three different schemes, and you will need all three.

Booking API

A single static header. Nothing to refresh.

curl -X POST 'https://dtdcapi.shipsy.io/api/customer/integration/consignment/softdata' \
  -H 'Content-Type: application/json' \
  -H 'api-key: <your-api-key>' \
  -d '{"consignments": [ ... ]}'

Omitting it returns HTTP 401 with NO_API_KEY, verified live.

Tracking service

A two step exchange, and the token endpoint takes its credentials in the query string of a GET, not a POST body. Verified live: POST to that path returns HTTP 405 Request method 'POST' not supported, and GET without valid credentials returns HTTP 403 Not Authorized.

  1. GET https://blktracksvc.dtdc.com/dtdc-api/api/dtdc/authenticate?username=<u>&password=<p> returns the access token.
  2. Send it as x-access-token alongside the booking api-key on tracking calls.
curl -X POST 'https://blktracksvc.dtdc.com/dtdc-api/rest/JSONCnTrk/getTrackDetails' \
  -H 'Content-Type: application/json' \
  -H 'x-access-token: <token>' \
  -H 'api-key: <your-api-key>' \
  -d '{"trkType": "cnno", "strcnno": "D12345678", "addtnlDtl": "Y"}'

The token lifetime is not published and could not be measured without credentials. Treat it as short, cache it, and re-issue on a 401 or 403.

Pincode serviceability

None. The endpoint is open to the internet.

Multi account: one api-key is one DTDC customer code. The customer_code is also repeated inside the booking request body, so a platform booking for several brands needs one key per brand and must keep the key and the code in step.

Objects we can read

Locations and pincode serviceability

The most useful and most surprising endpoint in this API, because it needs no credentials and returns a great deal in one call. POST http://smarttrack.ctbsplus.dtdc.com/ratecalapi/PincodeApiCall with {"orgPincode": "...", "desPincode": "..."}.

Verified live on 2026-09-22 for 110030 to 411001, trimmed to one element per array:

{
  "ZIPCODE_RESP": [
    {
      "MESSAGE": "SUCCESS", "SERVFLAG": "Y", "SERV_COD": "Y",
      "ORGPIN": "110030", "ORGCOUNTRY": "IN",
      "DESTPIN": "411001", "DESTCITY": "PUNE", "DESTSTATE": "PUNE", "DESTCOUNTRY": "IN"
    }
  ],
  "SERV_LIST": [
    {
      "b2C_SERVICEABLE": "YES", "b2B_SERVICEABLE": "YES",
      "COD_Serviceable": "YES", "b2C_COD_Serviceable": "YES", "b2B_COD_Serviceable": "YES",
      "GEC_Serviceable": "YES", "LITE_Serviceable": "YES",
      "DC_Serviceable": "NO", "IndiaPost_Serviceable": "NO",
      "remote_Delivery_Area": "NO", "special_Destination": "NO"
    }
  ],
  "SERV_LIST_DTLS": [
    { "CODE": "V71", "PCODE": "V71", "NAME": "B2C PREMIUM", "TAT": "1" },
    { "CODE": "P7X", "PCODE": "P7X", "NAME": "B2C PRIORITY", "TAT": "1" },
    { "CODE": "D71", "PCODE": "D71", "NAME": "B2C SMART EXPRESS", "TAT": "4" },
    { "CODE": "G71", "PCODE": "G71", "NAME": "B2C GROUND ECONOMY", "TAT": "4" },
    { "CODE": "D72", "PCODE": "D72", "NAME": "B2B SMART EXPRESS", "TAT": "4" }
  ],
  "PIN_CITY": [
    {
      "PIN": "110030", "CITY": "DELHI", "CITY_CODE": "DEL",
      "STATE_NAME": "DELHI", "STATE_CODE": "DL",
      "TALUKA_AND_DISTRICT": "DELHI,DELHI",
      "PARTIALSERV_AREA_AND_CITY": "FULLY SERVICEABLE"
    }
  ],
  "SERV_ORG_BR": [
    {
      "CODE": "S26", "BR_NAME": "CHATTARPUR BRANCH",
      "BR_ADDRESS": "A-1/1, KHASRA NO 818 MIN VILLAGE,CHATTARPUR, NEW DELHI 110074",
      "PHONE": "9513106055/8792500000", "EMAIL": "branchdel.chattarpur@dtdc.com",
      "LATITUDE": "28.49292", "LONGITUDE": "77.18467"
    }
  ],
  "SERV_BR": [
    {
      "CODE": "P15", "BR_NAME": "MARKET YARD BRANCH",
      "BR_ADDRESS": "WARE HOUSE NO - III,S.NO :- 583/B, GULTEKDI,OPP.POST OFFICE, MARKETYARD",
      "PHONE": "9620765082", "LATITUDE": "18.48999356", "LONGITUDE": "73.87012891"
    }
  ],
  "SERV_FR": [
    {
      "CODE": "PF949", "FR_NAME": "SHANTI KUNJ - STATION ROAD",
      "FR_ADDRESS": "SHOP NO.5  BUILDING - F SHANTI KUNJ,SADHU VASWANI ROAD OPP. GPO PUNE",
      "PHONE": "7276570009/7276870003",
      "LATITUDE": "18.5228594", "LONGITUDE": "73.876524"
    }
  ]
}

Reading it: ZIPCODE_RESP[0].SERVFLAG is the yes or no answer, SERV_COD whether cash on delivery is possible on that lane. SERV_LIST[0] breaks serviceability down by product family, with the B2C and B2B flags separated, and flags for remote delivery area and special destination which are the surcharge triggers. SERV_LIST_DTLS[] is the product list for that specific lane with a transit time in days, which is the closest thing DTDC offers to a rate call. SERV_ORG_BR, SERV_BR and SERV_FR are the origin branch, destination branch and destination franchise outlets with addresses and coordinates. No pagination, and no bulk form: one origin and destination pair per call.

Shipments and tracking

POST https://blktracksvc.dtdc.com/dtdc-api/rest/JSONCnTrk/getTrackDetails

This is a lookup by key: no pagination, no date window and no "changed since" filter. The response shape was not verifiable without credentials. It returns the consignment header plus, when addtnlDtl is Y, the scan history. Treat the field names as unknown until you have your first live response, and store the raw body.

There is no proof of delivery artefact on this API beyond the delivered scan.

Orders, listings, inventory, returns, settlements

None. A reverse shipment is a consignment booked with consignment_type set accordingly, not a separate object. COD remittance and freight invoicing are handled outside the API.

Writing back: listings, price and stock

Not applicable, this is a carrier. There are no listings, no prices and no stock. The write path is the consignment lifecycle on the Shipsy host.

Book a consignment

POST /api/customer/integration/consignment/softdata with the api-key header. The body is a consignments array, so several shipments can be booked in one call:

{
  "consignments": [
    {
      "customer_code": "GL4949",
      "reference_number": "",
      "service_type_id": "B2C SMART EXPRESS",
      "load_type": "NON-DOCUMENT",
      "consignment_type": "Forward",
      "dimension_unit": "cm", "length": "20", "width": "15", "height": "5",
      "weight_unit": "kg", "weight": "0.5",
      "declared_value": "999",
      "cod_amount": 999, "cod_collection_mode": "cash",
      "num_pieces": "1",
      "origin_details": {
        "name": "Main Warehouse", "phone": "9811111111", "alternate_phone": "",
        "address_line_1": "Plot 7, Industrial Area", "address_line_2": "",
        "pincode": "110030", "city": "Delhi", "state": "Delhi"
      },
      "destination_details": {
        "name": "Ramesh Kumar", "phone": "9876543210", "alternate_phone": "",
        "address_line_1": "12, MG Road", "address_line_2": "",
        "pincode": "411001", "city": "Pune", "state": "Maharashtra"
      },
      "pieces_detail": [
        { "description": "Cotton shirt", "declared_value": "999", "weight": "0", "length": "0", "width": "0", "height": "0" }
      ]
    }
  ]
}

Notes that matter:

  • service_type_id takes the product name from the serviceability response, such as B2C SMART EXPRESS or B2C PRIORITY, not the short code. Call the pincode endpoint first and pick a product that is actually available on that lane.
  • reference_number left empty means DTDC assigns the consignment number and returns it.
  • cod_collection_mode is cash for cash on delivery and empty for prepaid; cod_amount is zero for prepaid.
  • load_type distinguishes NON-DOCUMENT from document shipments.

The response is a data array parallel to the request, each element carrying a success boolean and, on success, the reference_number that is your AWB. Branch on data[0].success, not on the HTTP status.

Cancel a consignment

POST /api/customer/integration/consignment/cancel with the api-key header and a body of {"AWBNo": ["D12345678"], "customerCode": "<customer-code>"}. The path is verified live as gated by the API key; the body shape comes from the published SDK.

GET /api/customer/integration/consignment/shippinglabel/stream with the api-key header and query parameters reference_number, label_code (for example SHIP_LABEL_4X6) and label_format (for example pdf). It streams the label rather than returning a URL.

Pickup

No pickup request endpoint appears on the booking host or in any public integration. DTDC pickups are arranged through the franchise or branch relationship and the client panel, not through this API. Stated as a gap rather than guessed at.

Webhooks and notifications

None published, and nothing on any of the three hosts suggests a subscription mechanism. Poll getTrackDetails.

Because the tracking call takes one consignment number at a time in the shape documented publicly, polling cost scales linearly with open shipments. With no published rate limit, a conservative pattern is to poll in flight consignments once every one to two hours, stop once a consignment reaches a terminal scan, and ask your DTDC account manager whether a bulk or feed based alternative exists for your volume. The host name blktracksvc suggests a bulk tracking service, so there may be a batch form of this call in the client documentation pack.

Rate limits and pagination

Neither is published, and neither could be measured without credentials.

  • Pagination: none anywhere. Booking takes an array, tracking is a lookup by key, serviceability is one lane per call.
  • Rate limits: not published. The open pincode endpoint in particular should be treated as fragile: it is unauthenticated, on plain HTTP, and could be rate limited or closed without notice. Cache its answers and do not call it per page view.

Mapping to the unified model

DTDC contributes shipments, and locations in the unusual sense of DTDC's own branches rather than the seller's warehouses.

shipments

ship_to_address maps to destination_details, which is PII. The seller's own pickup location maps to origin_details, sent per consignment rather than registered once, so there is no warehouse registry to read.

locations

The serviceability response is the only location source, and it describes DTDC's network rather than the seller's. location_id and channel_location_id both map to SERV_ORG_BR[].CODE, SERV_BR[].CODE or SERV_FR[].CODE; type is fulfilment_centre for branches and closest to store for franchise outlets; name is BR_NAME or FR_NAME; address is BR_ADDRESS or FR_ADDRESS with LATITUDE and LONGITUDE alongside. This is useful for a drop off experience or for explaining a delay, and it is not what the locations table is normally for. Keep it separate if that distinction matters to you.

Gaps and open questions

  • The tracking response shape is unverified. Every field name on the read side of tracking is unknown without credentials. This is the largest gap on the page: budget for a discovery round against a live consignment number before finalising the schema.
  • Three authentication schemes, three hosts, one carrier. A single 401 could be an expired tracking token, a wrong booking key or a wrong customer code, and the three produce different error bodies.
  • No rate endpoint, no pickup API and no NDR API. SERV_LIST_DTLS names the available products and their transit times but not their price; pricing comes from your contracted rate card. Pickups and failed delivery actions are franchise or panel operations, unlike Delhivery and Shiprocket which expose both.
  • The pincode endpoint is unauthenticated and on plain HTTP. It works today and returns rich data, but it is not a contract. Cache it and keep it off any critical path.
  • The booking API is Shipsy's. If DTDC changes logistics software vendor, the booking API changes wholesale while the tracking and pincode hosts, which are DTDC's own, probably do not. Keep the booking adapter swappable.
  • Sandbox host discrepancy. alphademodashboardapi.shipsy.io is live with the same NO_API_KEY envelope, while the published SDK names demodashboardapi.shipsy.in with a .in top level domain. Resolve which one is yours with your account manager.
  • No published rate limits anywhere.

Sources

Verified live on 2026-09-22 by direct request:

  • https://dtdcapi.shipsy.io/api/customer/integration/consignment/softdata, /cancel, /label, /shippinglabel, /track and /api/customer/integration/pincode/serviceability: all return HTTP 401 {"error":{"message":"API key should be present","statusCode":401,"reason":"NO_API_KEY"}}, confirming the api-key header gate on the /api/customer/integration/ prefix. /api/customer/foo returns HTTP 404 NOT_FOUND, confirming the prefix itself is real
  • https://alphademodashboardapi.shipsy.io/api/customer/integration/consignment/softdata: live, same 401 envelope
  • https://blktracksvc.dtdc.com/dtdc-api/rest/JSONCnTrk/getTrackDetails: HTTP 401 Unauthorized: Authentication token was either missing or invalid
  • https://blktracksvc.dtdc.com/dtdc-api/api/dtdc/authenticate: HTTP 405 on POST (Request method 'POST' not supported), HTTP 403 Not Authorized on GET with invalid credentials, confirming it is a GET endpoint
  • http://smarttrack.ctbsplus.dtdc.com/ratecalapi/PincodeApiCall: HTTP 405 on GET, HTTP 200 on POST with {"orgPincode":"110030","desPincode":"411001"}. The full response quoted above is the live output

Secondary, read for request bodies and host names:

  • shibanashiqc/dtdc-courier-php-sdk, src/DTDC.php and src/DTDCBase.php: the production and demo host names, the api-key and x-access-token headers, the authenticate query string form, the getTrackDetails request body with trkType, strcnno and addtnlDtl, the cancel body with AWBNo and customerCode, and the shippinglabel/stream query parameters reference_number, label_code and label_format
  • Avry123/node-worker, src/actions/deliveryPartner/dtdc.ts: the full softdata request body including consignments[], service_type_id, load_type, consignment_type, origin_details, destination_details and pieces_detail, and the data[0].success and data[0].reference_number response fields