REST API Reference

Courier Tracking REST API Documentation

A single standardized REST JSON API to track shipments across Indian courier networks with normalized statuses, delivery attempt diagnostics, and stuck-shipment detection.

Quickstart

To query any active consignment, make an HTTP GET request to /v1/track/:carrier/:awb passing your provisioned API key in the X-API-Key request header.

cURL Quickstart GET /v1/track/delhivery/123456789012
curl -s -H "X-API-Key: ct_live_your_api_key_here" \
  "https://api.cleartrackpromise.in/v1/track/delhivery/123456789012"
Need a test key? Generate an instant 14-day free trial API key with 100 lookups on our free trial page.

Authentication

All endpoints under /v1/ require authentication. You must supply your live API key via the X-API-Key HTTP request header.

Header Format Description
X-API-Key ct_live_[64-character-hex] Required on all authenticated API v1 calls.

Requests missing the X-API-Key header return HTTP 401 with code missing_api_key. Invalid or revoked keys return HTTP 401 with code invalid_api_key.

Track a Shipment by AWB

Retrieve normalized tracking details by specifying the courier slug and the consignment number (AWB) in the request URL path.

HTTP Endpoint GET Method
GET https://api.cleartrackpromise.in/v1/track/:carrier/:awb

Path Parameters

Parameter Type Description
:carrier string Canonical carrier slug or recognized alias (e.g. delhivery, bluedart, indiapost).
:awb string Consignment number / Air Waybill (:tracking_number is also accepted as an alias).

Standard Normalized Response JSON

JSON (Illustrative Example) 200 OK
{
  "awb": "CP100000001IN",
  "tracking_number": "CP100000001IN",
  "carrier": "indiapost",
  "status": "delivered",
  "status_text": "Item Delivered",
  "is_delivered": true,
  "is_rto": false,
  "origin": {
    "office": null,
    "city": "New Delhi",
    "state": "Delhi",
    "pincode": null
  },
  "destination": {
    "office": null,
    "city": "Bengaluru",
    "state": "Karnataka",
    "pincode": null
  },
  "estimated_delivery_at": null,
  "delivered_at": "2026-10-08T14:30:00.000Z",
  "first_scan_at": "2026-10-05T10:15:00.000Z",
  "last_location": "Bengaluru",
  "last_known_location": "Bengaluru",
  "last_updated_at": "2026-10-08T14:30:00.000Z",
  "last_polled_at": "2026-10-08T14:35:00.000Z",
  "cached": true,
  "stale": false,
  "shipment": {
    "service_type": null,
    "weight_grams": null,
    "origin": {
      "office": null,
      "city": "New Delhi",
      "state": "Delhi",
      "pincode": null
    },
    "destination": {
      "office": null,
      "city": "Bengaluru",
      "state": "Karnataka",
      "pincode": null
    },
    "booked_at": "2026-10-05T10:15:00.000Z"
  },
  "milestones": {
    "booked_at": "2026-10-05T10:15:00.000Z",
    "picked_up_at": null,
    "in_transit_at": "2026-10-05T18:40:00.000Z",
    "out_for_delivery_at": "2026-10-07T08:00:00.000Z",
    "first_attempt_at": null,
    "delivered_at": "2026-10-08T14:30:00.000Z",
    "rto_initiated_at": null,
    "rto_delivered_at": null
  },
  "delivery_attempts": {
    "count": 1,
    "attempts": [
      {
        "at": "2026-10-08T14:30:00.000Z",
        "outcome": "delivered",
        "reason_code": null,
        "reason_text": null
      }
    ]
  },
  "insights": {
    "transit_days_elapsed": 3.2,
    "hours_since_last_scan": null,
    "is_stuck": false,
    "is_late_vs_carrier_edd": null,
    "delay_days_vs_carrier_edd": null,
    "hub_count": 2,
    "current_stage": "delivered",
    "requires_attention": false,
    "attention_reason": null,
    "benchmark": {
      "median_transit_days_for_route": null,
      "sample_size": null,
      "expected_delivery_by": null
    }
  },
  "events": [
    {
      "timestamp": "2026-10-08T14:30:00.000Z",
      "status": "delivered",
      "status_text": "Item Delivered",
      "code": "delivered",
      "facility": "Bengaluru",
      "location": "Bengaluru",
      "description": "Item Delivered"
    },
    {
      "timestamp": "2026-10-07T08:00:00.000Z",
      "status": "out_for_delivery",
      "status_text": "Item Out for Delivery",
      "code": "out_for_delivery",
      "facility": "Bengaluru",
      "location": "Bengaluru",
      "description": "Item Out for Delivery"
    },
    {
      "timestamp": "2026-10-06T09:20:00.000Z",
      "status": "in_transit",
      "status_text": "Item Received at Bengaluru NSH",
      "code": "received",
      "facility": "Bengaluru",
      "location": "Bengaluru",
      "description": "Item Received at Bengaluru NSH"
    },
    {
      "timestamp": "2026-10-05T18:40:00.000Z",
      "status": "in_transit",
      "status_text": "Item Dispatched to Delhi NSH",
      "code": "dispatched",
      "facility": "New Delhi",
      "location": "New Delhi",
      "description": "Item Dispatched to Delhi NSH"
    },
    {
      "timestamp": "2026-10-05T10:15:00.000Z",
      "status": "picked_up",
      "status_text": "Item Booked at New Delhi GPO",
      "code": "booked",
      "facility": "New Delhi",
      "location": "New Delhi",
      "description": "Item Booked at New Delhi GPO"
    }
  ]
}

Normalized Status Values

Top-level status values are normalized to a consistent enum across all carriers:

pending order_placed awaiting_pickup picked_up shipped in_transit out_for_delivery delivered exception returned cancelled

Supported Couriers

ClearTrack supports 11 Indian courier networks directly via verified canonical slugs and accepted aliases:

Canonical Slug Courier Network Common Aliases
delhiveryDelhiverydelhivery
bluedartBlue Dartblue-dart, blue_dart
trackonTrackontrackon
shiprocketShiprocketshiprocket
shreemarutiShree Maruti Couriermaruti, shree-maruti
indiapostIndia Postindia-post, india_post
speedpostSpeed Postspeed-post, speed_post
shadowfaxShadowfaxshadowfax
xpressbeesXpressbeesexpressbees, xpress-bees
ekartEkart Logisticsekart-logistics, ekart_logistics
professionalThe Professional Courierstpc, professional-courier

Errors & Rate Limits

The API returns standard HTTP status codes accompanied by a structured JSON error payload:

Status Error Code Description
400 invalid_awb AWB string is missing or shorter than 4 characters.
400 unsupported_carrier Specified carrier slug is not recognized.
401 missing_api_key X-API-Key request header is absent.
401 invalid_api_key API key is malformed, suspended, or revoked.
402 payment_required Plan validity has expired. Contact support to renew.
404 shipment_not_found No tracking scans exist for this consignment in carrier networks.
429 rate_limit_exceeded Per-second burst rate exceeded (retry after backoff).
429 plan_quota_exceeded Monthly period lookup quota exhausted.
429 daily_quota_exceeded Daily abuse quota reached (resets at UTC midnight).
502 upstream_error Carrier network temporarily unreachable and no cached record exists.

Lookup Counting & Billing

ClearTrack bills strictly on lookups, not on distinct consignments:

  • Every HTTP request to /v1/track/... consumes 1 lookup from your period quota.
  • Active in-transit shipments are cached for 30 minutes; calls within that window return cached data in milliseconds and consume 1 lookup.
  • Terminal consignments (delivered, returned, cancelled) are permanently cached.
  • You can monitor your remaining lookups and period validity via GET /v1/usage.

For full plan options and rates, review our dedicated Pricing Page.

Code Examples: cURL

Use cURL to track shipments from shell scripts or command-line pipelines:

cURL Terminal Command
# Track a Blue Dart consignment
curl -s -X GET "https://api.cleartrackpromise.in/v1/track/bluedart/12345678901" \
  -H "X-API-Key: ct_live_your_api_key_here" \
  -H "Accept: application/json"

Code Examples: Node.js

Native fetch example compatible with Node.js 18+ and modern JavaScript runtimes:

JavaScript Node.js 18+
async function trackShipment(carrier, awb) {
  const apiKey = process.env.CLEARTRACK_API_KEY || "ct_live_your_api_key_here";
  const url = `https://api.cleartrackpromise.in/v1/track/${encodeURIComponent(carrier)}/${encodeURIComponent(awb)}`;

  const response = await fetch(url, {
    method: "GET",
    headers: {
      "X-API-Key": apiKey,
      "Accept": "application/json",
    },
  });

  const data = await response.json();
  if (!response.ok) {
    throw new Error(`Tracking API Error (${response.status}): ${data.error?.message || "Unknown error"}`);
  }

  console.log("Status:", data.status);
  console.log("Delivered:", data.is_delivered);
  console.log("Current Stage:", data.insights?.current_stage);
  return data;
}

// Example usage
trackShipment("delhivery", "123456789012").catch(console.error);

Code Examples: Python

Integration using the popular Python requests library:

Python requests
import os
import requests

def track_shipment(carrier: str, awb: str) -> dict:
    api_key = os.getenv("CLEARTRACK_API_KEY", "ct_live_your_api_key_here")
    url = f"https://api.cleartrackpromise.in/v1/track/{carrier}/{awb}"
    headers = {
        "X-API-Key": api_key,
        "Accept": "application/json"
    }

    response = requests.get(url, headers=headers, timeout=15)
    response.raise_for_status()
    data = response.json()

    print(f"Status: {data.get('status')}")
    print(f"Delivered: {data.get('is_delivered')}")
    print(f"Stage: {data.get('insights', {}).get('current_stage')}")
    return data

if __name__ == "__main__":
    track_shipment("indiapost", "CP100000001IN")

Code Examples: PHP

Standard PHP cURL implementation for WooCommerce stores and PHP backends:

PHP cURL
<?php

function trackShipment(string $carrier, string $awb): array {
    $apiKey = getenv('CLEARTRACK_API_KEY') ?: 'ct_live_your_api_key_here';
    $url = "https://api.cleartrackpromise.in/v1/track/" . rawurlencode($carrier) . "/" . rawurlencode($awb);

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            "X-API-Key: {$apiKey}",
            "Accept: application/json",
        ],
        CURLOPT_TIMEOUT => 15,
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $data = json_decode($response, true);
    if ($httpCode >= 400) {
        $message = $data['error']['message'] ?? 'API error';
        throw new Exception("ClearTrack API Error ({$httpCode}): {$message}");
    }

    return $data;
}

// Example usage
$result = trackShipment('delhivery', '123456789012');
echo "Status: " . $result['status'] . PHP_EOL;
echo "Stage: " . ($result['insights']['current_stage'] ?? 'unknown') . PHP_EOL;