Track delivery orders in real-time. The tracking API provides public access to order status, delivery milestones, and estimated delivery times. No authentication required - perfect for sharing tracking links with customers.
Dropcolis provides two tracking endpoints:
Returns tracking information as JSON. Perfect for API integrations and custom tracking pages.
Returns a beautiful HTML tracking page. Share this URL directly with customers - no coding required!
Orders progress through the following statuses:
| Status | Display Name | Description |
|---|---|---|
pending |
Order Received | Order created and awaiting processing |
accepted |
Order Accepted | Order accepted by Dropcolis system |
courier_assigned |
Courier Assigned | A courier has been assigned to the order |
picked_up |
Package Picked Up | Package collected from pickup location |
in_transit |
In Transit | Package is on the way to destination |
out_for_delivery |
Out for Delivery | Package is out for final delivery |
delivered |
Delivered | Package successfully delivered |
failed |
Delivery Failed | Delivery attempt failed (will retry) |
cancelled |
Cancelled | Order was cancelled |
Use GET /track/{order_id} to get tracking information as JSON. This is perfect
for building custom tracking interfaces or integrating with your application.
import requests
def track_order(order_id):
"""Track an order - no authentication required"""
base_url = "http://localhost:5000"
response = requests.get(f"{base_url}/track/{order_id}")
if response.status_code == 200:
tracking_info = response.json()
print(f"Order Status: {tracking_info['status_display']}")
print(f"Estimated Delivery: {tracking_info.get('estimated_delivery', 'N/A')}")
return tracking_info
elif response.status_code == 404:
print(f"Order {order_id} not found")
return None
else:
print(f"Error: {response.status_code}")
return None
# Example usage
track_order("dc_9f7a1f2e3d4c5b6a")
async function trackOrder(orderId) {
const baseUrl = 'http://localhost:5000';
try {
const response = await fetch(`${baseUrl}/track/${orderId}`);
if (response.ok) {
const trackingInfo = await response.json();
console.log('Order Status:', trackingInfo.status_display);
console.log('Estimated Delivery:', trackingInfo.estimated_delivery);
return trackingInfo;
} else if (response.status === 404) {
console.log(`Order ${orderId} not found`);
return null;
} else {
console.error('Error:', response.status);
return null;
}
} catch (error) {
console.error('Network error:', error);
return null;
}
}
// Example usage
trackOrder('dc_9f7a1f2e3d4c5b6a');
# Track order - no authentication needed
curl -X GET "http://localhost:5000/track/dc_9f7a1f2e3d4c5b6a"
# Pretty print JSON response
curl -X GET "http://localhost:5000/track/dc_9f7a1f2e3d4c5b6a" | jq
{
"order_id": "dc_9f7a1f2e3d4c5b6a",
"partner_order_id": "PH-2025-000123",
"status": "out_for_delivery",
"status_display": "Out for Delivery",
"created_at": "2025-11-08T10:30:00Z",
"updated_at": "2025-11-09T14:20:00Z",
"estimated_delivery": "2025-11-09T17:00:00-05:00",
"tracking_url": "https://dropcolis.ca/track/dc_9f7a1f2e3d4c5b6a",
"service_level": "standard",
"status_history": [
{
"status": "accepted",
"timestamp": "2025-11-08T10:30:00Z"
},
{
"status": "courier_assigned",
"timestamp": "2025-11-08T11:00:00Z"
},
{
"status": "picked_up",
"timestamp": "2025-11-09T09:00:00Z"
},
{
"status": "out_for_delivery",
"timestamp": "2025-11-09T14:20:00Z"
}
],
"courier": {
"name": "S. Diop",
"phone": "+1-514-111-2222"
}
}
Use GET /track/{order_id}/html to get a beautiful, ready-to-use HTML tracking page.
Simply share this URL with your customers - no integration needed!
https://dropcolis.ca/track/dc_9f7a1f2e3d4c5b6a/html
<html>
<body>
<h2>Your Order is on the Way!</h2>
<p>Track your delivery:</p>
<a href="https://dropcolis.ca/track/dc_9f7a1f2e3d4c5b6a/html">
View Tracking Page
</a>
</body>
</html>
<iframe
src="https://dropcolis.ca/track/dc_9f7a1f2e3d4c5b6a/html"
width="100%"
height="600"
frameborder="0">
</iframe>
import React, { useState, useEffect } from 'react';
function TrackingWidget({ orderId }) {
const [tracking, setTracking] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchTracking() {
try {
const response = await fetch(
`http://localhost:5000/track/${orderId}`
);
const data = await response.json();
setTracking(data);
} catch (error) {
console.error('Error fetching tracking:', error);
} finally {
setLoading(false);
}
}
fetchTracking();
// Poll every 30 seconds for updates
const interval = setInterval(fetchTracking, 30000);
return () => clearInterval(interval);
}, [orderId]);
if (loading) return <div>Loading...</div>;
if (!tracking) return <div>Order not found</div>;
return (
<div className="tracking-widget">
<h3>Order Status: {tracking.status_display}</h3>
<p>Estimated Delivery: {tracking.estimated_delivery}</p>
{tracking.courier && (
<div>
<p>Courier: {tracking.courier.name}</p>
<p>Phone: {tracking.courier.phone}</p>
</div>
)}
<div className="status-history">
{tracking.status_history.map((event, idx) => (
<div key={idx}>
{event.status} - {event.timestamp}
</div>
))}
</div>
</div>
);
}
export default TrackingWidget;
import time
import requests
def poll_tracking(order_id, interval=30, max_polls=60):
"""Poll tracking endpoint for status updates"""
base_url = "http://localhost:5000"
last_status = None
for i in range(max_polls):
response = requests.get(f"{base_url}/track/{order_id}")
if response.status_code == 200:
tracking = response.json()
current_status = tracking['status']
if current_status != last_status:
print(f"Status changed: {last_status} → {current_status}")
last_status = current_status
# Check if delivered
if current_status == 'delivered':
print("Order delivered!")
break
else:
print(f"Status: {current_status} (no change)")
else:
print(f"Error: {response.status_code}")
time.sleep(interval)
return last_status
# Poll every 30 seconds
poll_tracking("dc_9f7a1f2e3d4c5b6a", interval=30)
{
"error": {
"code": "not_found",
"message": "Order dc_9f7a1f2e3d4c5b6a not found"
}
}
Common causes:
POST /v1/orders to create an order and get the order_id