Your checkout. Our riders.
Plug Nigeria's delivery network into your store or app: pull a live delivery quote at checkout, create the order the moment payment clears, and stream tracking to your customer — all over a clean REST API with webhooks.
# 1. Quote the delivery at checkout curl -G https://api.travo.ng/v1/service-quotes \ -H "Authorization: Bearer $TRAVO_SECRET_KEY" \ --data-urlencode "pickup=6.4281,3.4216" \ --data-urlencode "dropoff=6.6018,3.3515" \ --data-urlencode "service_type=sendparcel" # → { "id": "service_quote_...", "amount": 245000, "currency": "NGN" } # 2. Customer paid — create the order curl -X POST https://api.travo.ng/v1/orders \ -H "Authorization: Bearer $TRAVO_SECRET_KEY" \ -d '{ "service_quote": "service_quote_...", "dispatch": true, ... }'
Overview
The Travo API gives your application direct access to the same logistics engine that powers travo.ng — quoting, dispatch, rider allocation, tracking and proof-of-delivery. It's a straightforward JSON REST API built around four battle-tested concepts — Places, Entities, Orders and Service Quotes — so if you've integrated any modern delivery or payments API, this will feel familiar in minutes.
The typical integration is three steps: quote a delivery when your customer is at checkout, create the order when payment succeeds, then listen on webhooks (or poll) as the order moves from dispatch to delivered — pushing live status to your customer under your own brand.
https://api.travo.ng/v1 · All requests over HTTPS, all bodies JSON, all monetary amounts in kobo (₦2,450.00 = 245000).Authentication
Every request is authenticated with a secret API key in the Authorization header. Keys are issued per organisation from the Travo Console (Console → Developers → API Keys) and come in two flavours:
travo_test_…— sandbox: full API behaviour, no real dispatch, no charges. Build against this.travo_live_…— production: real quotes, real riders, real money.
Authorization: Bearer travo_live_xxxxxxxxxxxxxxxx Content-Type: application/json
Don't have keys yet? Request access with your company name and website — integration accounts are approved with a short review.
Quickstart — first quote in 60 seconds
With a test key exported as TRAVO_SECRET_KEY:
curl -G "https://api.travo.ng/v1/service-quotes" \ -H "Authorization: Bearer $TRAVO_SECRET_KEY" \ --data-urlencode "pickup=6.4281,3.4216" \ --data-urlencode "dropoff=6.6018,3.3515" \ --data-urlencode "service_type=sendparcel"
{
"id": "service_quote_9f3b2c",
"amount": 245000,
"currency": "NGN",
"service_type": "sendparcel",
"expires_at": "2026-07-25T16:45:00Z"
}That's a live price for a Victoria Island → Ikeja parcel: ₦2,450. Hold the id — you'll pass it when creating the order so the customer pays exactly what they were quoted.
1 · Delivery quotes
Query available service quotes for a pickup/dropoff pair. Coordinates (lat,lng) give the most precise pricing; street addresses are geocoded automatically.
| Parameter | Type | Description |
|---|---|---|
| pickup | string | Coordinates "6.4281,3.4216", an address string, or an existing place_… ID |
| dropoff | string | Same formats as pickup |
| service_type | string | One of the service types, e.g. sendparcel. Omit to get quotes for all services covering the route |
| scheduled_at | ISO 8601 | Optional — future pickup time for scheduled deliveries |
| total_weight | number | Optional — total kg, used for weight-tiered services (haulage, bulk) |
Quotes are firm until expires_at (typically 30 minutes) — long enough for any checkout. Requote if the customer edits their address.
const res = await fetch(
"https://api.travo.ng/v1/service-quotes?" + new URLSearchParams({
pickup: "12 Adeola Odeku St, Victoria Island, Lagos",
dropoff: customer.address,
service_type: "sendparcel"
}),
{ headers: { Authorization: `Bearer ${process.env.TRAVO_SECRET_KEY}` } }
);
const [quote] = await res.json();
// show quote.amount / 100 as the delivery fee at checkout2 · Create an order
When payment succeeds, turn the quote into a dispatched order. Pass the service_quote so pricing is locked to what the customer saw, the parcel details as entities, and dispatch: true to send it straight to rider allocation.
{
"service_quote": "service_quote_9f3b2c",
"type": "sendparcel",
"pickup": { "name": "Duro Fashion Store", "address": "12 Adeola Odeku St, VI, Lagos", "phone": "+2348030000000" },
"dropoff": { "name": "Chiamaka O.", "address": "4 Allen Avenue, Ikeja, Lagos", "phone": "+2348151112222" },
"entities": [
{ "name": "Ankara gown (order #1042)", "weight": 1.2, "weight_unit": "kg", "declared_value": 4500000 }
],
"meta": { "store_order_id": "1042" },
"dispatch": true,
"notes": "Call on arrival; gate code 4421"
}{
"id": "order_7d1e4a",
"status": "created",
"tracking_number": "TRV-84620-NG",
"type": "sendparcel",
"amount": 245000,
"currency": "NGN",
"driver_assigned": null,
"created_at": "2026-07-25T15:04:22Z"
}Store id and tracking_number against your own order record — meta is a free-form object echoed back on every webhook, which is the cleanest way to reconcile Travo orders with yours.
3 · Tracking & order lifecycle
Returns the current order state including driver details once assigned (name, phone, live position) and the proof-of-delivery record on completion. Order status moves through:
For customer-facing tracking without exposing your API, link them to the public tracker with the tracking number: https://travo.ng/track/TRV-84620-NG.
4 · Webhooks
Register an HTTPS endpoint in the Console (Developers → Webhooks) and Travo POSTs a JSON event on every order transition — no polling. Events carry the full order object plus your meta.
| Event | Fired when |
|---|---|
order.created | Order accepted into the system |
order.dispatched | Sent to rider allocation |
order.driver_assigned | Rider confirmed — driver name/phone now on the order |
order.picked_up | Parcel collected (pickup proof recorded) |
order.completed | Delivered — POD photo/PIN recorded |
order.canceled | Canceled by merchant or ops, with reason |
{
"event": "order.completed",
"created_at": "2026-07-25T17:41:09Z",
"data": {
"id": "order_7d1e4a",
"status": "completed",
"tracking_number": "TRV-84620-NG",
"meta": { "store_order_id": "1042" },
"proof_of_delivery": { "type": "photo+pin", "completed_at": "2026-07-25T17:40:52Z" }
}
}2xx quickly, and treat deliveries as at-least-once (dedupe on data.id + event).Objects & fields
Place
| Field | Type | Notes |
|---|---|---|
| name | string | Contact/location name shown to the rider |
| address | string | Street address — geocoded server-side |
| coordinates | [lng, lat] | Optional; overrides geocoding when supplied |
| phone | string | E.164 preferred (+234…) — used for rider contact & SMS updates |
Entity (parcel/item)
| Field | Type | Notes |
|---|---|---|
| name | string | What's being carried — appears on the waybill |
| weight / weight_unit | number / string | e.g. 1.2, "kg" |
| dimensions | object | {length, width, height, unit} — used for volumetric services |
| declared_value | integer | Kobo — drives insurance handling on high-value goods |
Service types
The service_type / type values map to Travo's live order configurations — the same ones behind the booking site:
Most e-commerce integrations only need sendparcel (same-day/next-day parcels) and occasionally haulage for bulk. Quoting without a service_type returns every service available on the route so you can offer tiers (e.g. standard vs bulk) at checkout.
Errors
Standard HTTP semantics with a consistent JSON error body:
{ "errors": [ "Dropoff address could not be resolved to a serviceable area." ] }| Status | Meaning |
|---|---|
401 | Missing/invalid API key — check the Bearer header and key environment |
404 | Unknown resource ID (expired quote IDs return this too) |
422 | Validation failed — the errors array names each field problem |
429 | Rate limited — back off and retry with exponential delay |
5xx | Our side — safe to retry idempotently; creating with the same service_quote won't double-book |
E-commerce recipe — quote at checkout, ship on payment
The integration pattern that fits WooCommerce, Shopify (via app proxy), Magento or any custom cart:
- Checkout loads → your backend calls
GET /service-quoteswith your store's pickup and the customer's address → renderamount/100as the delivery fee (add your margin if you mark up) - Customer pays → payment webhook on your side calls
POST /orderswith the held quote ID, parcel entities andmeta.store_order_id - Travo webhooks → update your order status and email/SMS the customer; on
order.driver_assignedshow rider name and the public tracking link - Delivered →
order.completedcloses your fulfilment, with POD evidence on record if there's ever a dispute
$ch = curl_init("https://api.travo.ng/v1/orders");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("TRAVO_SECRET_KEY"),
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode([
"service_quote" => $quoteId,
"type" => "sendparcel",
"pickup" => $storePickup,
"dropoff" => ["name" => $order->customer_name, "address" => $order->address, "phone" => $order->phone],
"entities" => [[ "name" => "Order #{$order->id}", "weight" => $order->weight_kg, "weight_unit" => "kg" ]],
"meta" => ["store_order_id" => (string)$order->id],
"dispatch" => true
])
]);
$travoOrder = json_decode(curl_exec($ch), true);Selling on the network instead of just shipping? Our Storefront platform lets you launch a full branded shop (web + iOS/Android) running on this same engine — talk to us about a hosted build.
Tooling & resources
- REST-first — no SDK required: every example on this page works with curl, fetch, Guzzle, axios or any HTTP client your stack already uses
- JavaScript SDK & Postman collection — available on request for typed access to Places, Orders and tracking; message the line with
DEV API:and we'll send the package for your stack - Branded apps on the same engine — customer-facing storefront apps (web + iOS/Android) and driver apps can be built and hosted on this platform under your brand; ask us for a scoping call
- Deep integration or custom order flows — bespoke order configurations, custom fields and dedicated environments are available for platform partners
Developer support
Integrating? We'd genuinely like to help you ship it — a working integration makes both of us money. Message the line with the "DEV API:" prefix for routing to someone technical, or email hello@travoservices.com.
