Integrate Odeliver's powerful delivery services directly into your applications. Create shipments, track packages, and manage deliveries programmatically.
{
"pickup": {
"company": "My Store",
"address1": "123 Main St",
"city": "Port of Spain"
},
"dropoff": {
"name": "John Doe",
"address1": "456 Oak Ave"
}
}
Clean, predictable endpoints following REST conventions
Secure API key authentication with HTTPS encryption
Test integration safely before going live
Consistent JSON format for all responses
Get up and running with our API in minutes
Sign up for a free merchant account to access the developer dashboard and generate your API credentials.
Navigate to Settings > API in your dashboard. Generate a sandbox token for testing and a production token for live operations.
Include your token in the Authorization header as a Bearer token. Use sandbox paths for testing before going live.
// Include your API token in every request curl -X GET "https://odeliver.com/api/v1/shipments" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" // Or using JavaScript fetch('https://odeliver.com/api/v1/shipments', { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_API_TOKEN', 'Content-Type': 'application/json' } })
Use different base paths depending on your token type. Sandbox tokens must use sandbox paths, and production tokens must use production paths.
https://odeliver.com/sandbox/v1/shipments
https://odeliver.com/sandbox/v1/instant-shipments
https://odeliver.com/api/v1/shipments
https://odeliver.com/api/v1/instant-shipments
All API requests require authentication using a Bearer token.
Include your token in the Authorization header.
/sandbox/v1/ paths)
/api/v1/ paths)
X-RateLimit-Limit - Requests allowed per periodX-RateLimit-Remaining - Requests remainingX-RateLimit-Reset - Time until limit resetsCore endpoints to manage your deliveries
Hub & Spoke delivery (1-2 business days)
Same-day delivery (within hours)
All tracking endpoints return delivery_status (integer) and delivery_status_label (human-readable).
Returns { "success": true, "data": { "time": "...", "status": "alive" } }. No authentication required.
Hub & Spoke delivery — city IDs are integers from your account settings
{
"pickup": {
"company": "My Store Ltd",
"address1": "123 Main Street",
"address2": "Suite 100",
"city": 1,
"zip": "00000",
"phone": "18685551234",
"lat": 10.6549,
"lng": -61.5019
},
"dropoff": {
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "18685555678",
"address1": "456 Oak Avenue",
"city": 2,
"zip": "00000",
"lat": 10.2833,
"lng": -61.4667,
"instructions": "Leave at front door"
},
"size": [2],
"item_cost": 250.00,
"payment_on_delivery": 1,
"shipping_cost": 0,
"delivery_type": 1
}
{
"success": true,
"data": {
"id": 12345,
"shipment_id": "OD-7X9K2M4P",
"message": "Created"
}
}
// Same pickup/dropoff structure, plus: { ... "size": [2, 2], "item_cost": 150.00, "payment_on_delivery": 1, "shipping_cost": 0 } // Response { "success": true, "data": { "id": 6789, "shipment_id": "OD-A3B5C7D9", "collect": 185.00, "message": "Created Successfully" } }
Required and optional fields for creating shipments
| Parameter | Type | Description |
|---|---|---|
company |
string | Business name (optional) |
address1 * |
string | Street address |
address2 |
string | Suite, unit, etc. |
city * |
integer | City ID (must exist in system) |
zip * |
string | Postal code (digits only) |
phone * |
string | Phone number (exactly 11 digits) |
lat * |
float | Latitude coordinate |
lng * |
float | Longitude coordinate |
| Parameter | Type | Description |
|---|---|---|
name * |
string | Recipient name (max 50 chars) |
email |
string | Email for notifications |
phone * |
string | Phone number (exactly 11 digits) |
address1 * |
string | Street address |
address2 |
string | Apt, suite, etc. |
city * |
integer | City ID (must exist in system) |
zip * |
string | Postal code (digits only) |
lat * |
float | Latitude coordinate |
lng * |
float | Longitude coordinate |
instructions |
string | Delivery instructions (max 150 chars) |
| Parameter | Type | Description |
|---|---|---|
size * |
array | Package sizes array. Standard: 1-5 items, values 1-4. Instant: 1-4 items, value 2. |
item_cost |
float | Cost of item being shipped (min 0) |
payment_on_delivery * |
0 or 1 | 1 = driver collects payment from customer |
shipping_cost * |
0 or 1 | 0 = customer pays shipping, 1 = seller pays |
delivery_type |
integer | 1 = Delivery, 2 = Exchange, 3 = Collection |
round_trip |
0 or 1 | 1 = round trip delivery |
customer_approval |
0 or 1 | 1 = require customer approval before dispatch |
| Parameter | Type | Description |
|---|---|---|
oprotect |
0 or 1 | 1 = enable OProtect insurance |
ins_amt |
float | Insurance coverage amount |
ins_paid_by |
0 or 1 | 0 = customer pays, 1 = seller pays |
| Instant Scheduling (instant shipments only) | ||
schedule_date |
string | YYYY-MM-DD (omit for ASAP delivery) |
schedule_slot |
string | Slot code from /v1/instant-shipments/slots |
| Standard Only | ||
delivery_window |
string | Delivery window preference (standard shipments) |
print_label |
0 or 1 | 1 = auto-generate shipping label |
blind_shipping |
0 or 1 | 1 = hide sender info from recipient |
Retrieve a paginated list of your shipments with optional filters.
Works the same for both /v1/shipments and /v1/instant-shipments.
page |
Page number (default: 1) |
per_page |
Results per page (default: 25, max: 100) |
delivery_status |
Filter by delivery status (integer) |
from |
Start date filter (YYYY-MM-DD) |
to |
End date filter (YYYY-MM-DD) |
sort_by |
Sort field: id, created_at, delivery_status (default: created_at) |
sort_dir |
asc or desc (default: desc) |
{
"success": true,
"data": {
"items": [
{
"id": 12345,
"shipment_id": "OD-7X9K2M4P",
"delivery_status": 0,
"created_at": "2026-01-15 14:30:00"
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 150,
"pages": 6,
"sort_by": "created_at",
"sort_dir": "desc",
"filters": {
"from": null,
"to": null,
"delivery_status": null
}
}
}
}
Calculate delivery cost before creating a shipment. The two shipment types use different inputs.
pickup.city * |
City ID (integer) |
dropoff.city * |
City ID (integer) |
size * |
Array of sizes (1-5 items, values 1-4) |
delivery_window |
Delivery window preference |
pickup.lat, pickup.lng * |
Pickup coordinates |
dropoff.lat, dropoff.lng * |
Dropoff coordinates |
// Standard Estimate Request { "pickup": { "city": 1 }, "dropoff": { "city": 2 }, "size": [2] } // Response { "success": true, "data": { "estimated_delivery_total": 85.00, "currency": "TTD" } }
// Instant Estimate Request { "pickup": { "lat": 10.6549, "lng": -61.5019 }, "dropoff": { "lat": 10.2833, "lng": -61.4667 } } // Response { "success": true, "data": { "estimated_delivery_total": 45.00, "currency": "TTD", "is_peak": false, "peak_window": "11:00-13:00" } }
All errors follow a consistent format with an error code and optional field-level details.
| 200 | Success |
| 201 | Created (returned on successful create) |
| 401 | Unauthorized — invalid or missing Bearer token |
| 403 | Forbidden — sandbox token on production path (or vice versa) |
| 404 | Not Found — resource doesn't exist or not owned by you |
| 409 | Conflict — shipment cannot be cancelled in current state |
| 422 | Validation Error — invalid or missing fields |
| 429 | Rate Limited — too many requests (check retry_after) |
| 500 | Server Error |
{
"success": false,
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"errors": [
{
"field": "pickup.address1",
"message": "Required",
"code": "REQUIRED"
},
{
"field": "dropoff.phone",
"message": "Must be exactly 11 digits",
"code": "PHONE_11"
}
]
}
{
"success": false,
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"errors": {
"retry_after": 60
}
}
{
"success": false,
"error": "Sandbox tokens must use /sandbox/ path"
}
Create your merchant account to get API tokens and start building. Our sandbox environment lets you test without any real transactions.