Ataboy Business
API docsLog inDashboardSign up
Sign up
Menu
API docsLog inDashboardSign up

Business portal

Partner API integration guide

Everything a business needs to connect their store, marketplace, or ops system to Ataboy — authentication, creating deliveries, tracking, webhooks, and going live.

Base URL: https://api.ataboyexpress.com
Dashboard: /dashboard, Sign up: /signup

In this guide
  1. How the Partner API works
  2. Account & go-live onboarding
  3. Test vs live keys
  4. Integration Hub (partner differences)
  5. Authentication
  6. Quickstart
  7. Estimate a delivery fee
  8. Create a delivery
  9. List, track, and cancel
  10. Webhooks
  11. Errors & status codes
  12. Go-live checklist
  13. Demo credentials

1. How the Partner API works

The Partner API lets your backend create and manage deliveries on Ataboy without using the customer booking UI. Typical flow:

  1. Your checkout or warehouse system collects pickup and dropoff details.
  2. You call Ataboy to estimate fee, then create a delivery.
  3. Ataboy assigns a rider and moves the parcel through status updates.
  4. Your system receives webhook events (or polls track endpoints) and updates your customers.

All partner calls use API Key + API Secret headers. Secrets are shown once when a key is created, store them in your secrets manager, never in frontend code.

2. Account & go-live onboarding

Onboarding follows a Paystack-style model:

  1. Create a business account on this portal — sign up here.
  2. You immediately receive test keys (atb_test_…).
  3. Build and test your integration against local/test traffic.
  4. In the dashboard, open Compliance and submit CAC, address, director ID, and use case.
  5. After Ataboy admin approval, generate live keys (atb_live_…) under Integration Hub → Credentials.
Tip: Keep using test keys until your webhook handler, fee display, and cancel flows are verified. Switching to live is only a credential change, your request shapes stay the same.

3. Test vs live keys

ModeKey prefixWhen availableUse for
Testatb_test_Immediately after signupIntegration, QA, staging
Liveatb_live_After compliance approvalProduction customer orders
If you call the API with a live key before compliance is approved, the API returns 403 and tells you to use test keys.

4. Integration Hub (partner differences)

The Partner API stays the same for every business. Differences (custom checkout rates, markup, connectors) live in the Integration Hub on the Business dashboard.

Your store checkout
      │
      ▼
Integration Hub  (rate cards / markup / connectors)
      │
      ▼
Stable Partner API  (/v1/partner/*)
      │
      ▼
Ataboy logistics

Pricing modes

  • ataboy_default, platform formula (distance, weight, vehicle)
  • custom_rates, fixed fees by destination LGA and optional place (Correct Gadgets–style). Place beats LGA so Lakowe ≠ Dangote Refinery.
  • markup, Ataboy default + your % markup (optional free delivery threshold)

Configure in Business dashboard → Integration Hub. Estimate and create still use POST /v1/partner/deliveries/estimate and POST /v1/partner/deliveries — only the fee resolution changes. Responses include pricingSource and optional matchedRateName.

For place-level rates, send dropoff.lga and dropoff.place (e.g. Ibeju-Lekki + Lakowe). Matching order: place → LGA → legacy city zones → Ataboy default. Optional packageSize (small | medium | large); if omitted, size is inferred from weightKg.

5. Authentication

Send these headers on every /v1/partner/* request:

X-Api-Key: atb_test_xxxxxxxxxxxx
X-Api-Secret: <your_secret>
Content-Type: application/json

Security rules

  • Only call the Partner API from your server (never from a browser app).
  • Rotate keys from the Business dashboard if a secret is leaked.
  • Revoke unused keys; prefer separate keys for staging vs production.

6. Quickstart: your first request

Estimate a fee with a demo test key:

curl -X POST https://api.ataboyexpress.com/v1/partner/deliveries/estimate \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: atb_test_fmdemo01" \
  -H "X-Api-Secret: demo_secret_freshmart_00000001" \
  -d '{
    "pickup": { "city": "Lagos", "state": "Lagos" },
    "dropoff": { "city": "Lagos", "state": "Lagos" },
    "weightKg": 2,
    "vehicle": "bike",
    "insurance": false
  }'

A successful response looks like:

{
  "estimate": {
    "baseFee": 800,
    "distanceFee": 400,
    "weightFee": 100,
    "insuranceFee": 0,
    "total": 1300,
    "currency": "NGN",
    "etaMinutes": 45
  }
}

7. Estimate a delivery fee

POST /v1/partner/deliveries/estimate

Use this before checkout so customers see the delivery fee. Required fields:

  • pickup.city, pickup.state (optional lat/lng)
  • dropoff.city, dropoff.state (optional lat/lng)
  • Optional: weightKg (default 1), vehicle (bike | car | van), insurance

8. Create a delivery

POST /v1/partner/deliveries

Creates a delivery under your enterprise account. Ataboy returns the delivery object plus the fee estimate used. Pass receiverEmail so Ataboy can email the shopper a delivered confirmation from Ataboy Express (with a no-login Rate this delivery button) when the order completes.

curl -X POST https://api.ataboyexpress.com/v1/partner/deliveries \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: atb_test_fmdemo01" \
  -H "X-Api-Secret: demo_secret_freshmart_00000001" \
  -d '{
    "pickup": {
      "street": "12 Admiralty Way",
      "city": "Lagos",
      "state": "Lagos",
      "country": "Nigeria",
      "landmark": "Near Shoprite"
    },
    "dropoff": {
      "street": "15 Adeola Odeku",
      "city": "Lagos",
      "state": "Lagos",
      "country": "Nigeria"
    },
    "receiverName": "Chioma Okeke",
    "receiverPhone": "+2348012345678",
    "receiverEmail": "chioma@example.com",
    "description": "Grocery order #1042",
    "weightKg": 3,
    "vehicle": "bike",
    "insurance": false
  }'

Important response fields

  • delivery.id, store this in your system as the Ataboy delivery reference
  • delivery.trackingNumber, share with customers for tracking
  • delivery.status, starts as pending / awaiting dispatch
  • delivery.fee, fee charged for the trip (NGN)
  • delivery.deliveryCode, arrival confirmation; custody photos prove parcel condition
Map your internal order ID into description (e.g. Order #1042) so support can reconcile Ataboy deliveries with your OMS.

9. List, track, and cancel

List your deliveries

GET /v1/partner/deliveries, returns deliveries created with your enterprise account.

Get one delivery + timeline

GET /v1/partner/deliveries/:id, includes delivery and status events.

Track by tracking number

GET /v1/partner/track/:trackingNumber, useful for customer support UIs. May include rider summary (status, vehicle, rating) when assigned.

curl https://api.ataboyexpress.com/v1/partner/track/ATB-XXXXXX \
  -H "X-Api-Key: atb_test_fmdemo01" \
  -H "X-Api-Secret: demo_secret_freshmart_00000001"

Cancel a delivery

POST /v1/partner/deliveries/:id/cancel

You cannot cancel deliveries that are already delivered or cancelled (400).

10. Webhooks (status updates)

Prefer webhooks over polling. Configure them in the Business dashboard (Integration Hub → Webhooks) or via API:

  • GET /v1/partner/webhooks
  • PUT /v1/partner/webhooks

Configure via API

curl -X PUT https://api.ataboyexpress.com/v1/partner/webhooks \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: atb_test_fmdemo01" \
  -H "X-Api-Secret: demo_secret_freshmart_00000001" \
  -d '{
    "url": "https://your-app.com/webhooks/ataboy",
    "events": [
      "delivery.created",
      "delivery.assigned",
      "delivery.picked_up",
      "delivery.in_transit",
      "delivery.completed",
      "delivery.cancelled",
      "delivery.failed"
    ],
    "active": true,
    "rotateSecret": true
  }'

When rotateSecret is true (or on first create), the response includes webhook.secret once, save it.

Events you can subscribe to

These fire automatically as a delivery moves through its lifecycle:

  • delivery.created, we accepted your order and it is waiting for a rider
  • delivery.assigned, a rider took the job; the rider object is now populated
  • delivery.picked_up, the rider has your package
  • delivery.in_transit, on the way to the receiver
  • delivery.completed, handed over; completedAt is set
  • delivery.cancelled, cancelled by you or by Ataboy
  • delivery.failed, the rider could not complete the drop-off
  • delivery.updated, delivery details changed, e.g. the delivery code was regenerated

These are accepted on subscription and reserved for upcoming milestones, but are not dispatched yet — subscribe now if you want them, just don’t build a flow that waits on them: delivery.accepted, delivery.pickup.arrived, delivery.arriving, delivery.returned, payment.completed, payment.failed.

delivery.delivered is deprecated in favour of delivery.completed. Existing subscriptions to it keep working, but the event name on the wire is always delivery.completed, so match on both if you are migrating.

Headers Ataboy sends

HeaderExampleNotes
Content-Typeapplication/jsonBody is always JSON.
X-Ataboy-Eventdelivery.completedThe event name, identical to the event field in the body.
X-Ataboy-Signaturesha256=<hex>HMAC-SHA256 of the raw request body, keyed with your webhook secret.
X-Ataboy-Timestamp1786213329Unix seconds when the request was signed. Reject anything older than 5 minutes.
X-Ataboy-Delivery<uuid>Unique ID for this delivery attempt. Use it as an idempotency key, retries of the same event arrive with a new value, so de-duplicate on the body's id instead.

Payload envelope

Every webhook has the same four top-level keys. id is unique per event and is the value to de-duplicate on, a retried event keeps the same id.

  • id, string (uuid), unique ID for this event
  • event, string, the event name
  • createdAt, string, ISO 8601 timestamp
  • timestamp, number, the same moment in Unix seconds
  • data, object, the delivery snapshot described below

Example payload

A delivery.completed event with a rider attached. Every field listed below is always present on delivery events, using null rather than omission when there is no value:

{
  "id": "7f1c0f0e-2a3b-4c5d-8e9f-0a1b2c3d4e5f",
  "event": "delivery.completed",
  "createdAt": "2026-08-08T14:22:09.145Z",
  "timestamp": 1786213329,
  "data": {
    "deliveryId": "3a9d1b52-1f47-4a26-9c3e-77b0a1d4e812",
    "businessOrderId": "DC-10482",
    "trackingNumber": "ATB-8F3K2Q",
    "status": "delivered",
    "fee": 2150,
    "receiverName": "Chioma Okeke",
    "receiverPhone": "+2348031234567",
    "pickupCity": "Lagos",
    "dropoffCity": "Lagos",
    "pickupLga": "Eti-Osa",
    "pickupPlace": "Lekki Phase 1",
    "dropoffLga": "Ikeja",
    "dropoffPlace": "Allen Avenue",
    "pricingSource": "partner_rate_card",
    "matchedRateName": "Lekki to Ikeja (Bike)",
    "trackingUrl": "https://track.ataboyexpress.com/ATB-8F3K2Q",
    "deliveryCode": "4821",
    "custodyPhotoUrl": "https://cdn.ataboyexpress.com/custody/sample.jpg",
    "custodyPhotoUrls": [
      "https://cdn.ataboyexpress.com/custody/sample.jpg",
      "https://cdn.ataboyexpress.com/custody/sample-2.jpg"
    ],
    "completedAt": "2026-08-08T14:22:07.902Z",
    "rider": {
      "id": "b2c7f5a1-9e34-4c88-bb10-6d2f0a5c7e93",
      "name": "Emeka Nwosu",
      "phone": "+2348090001122",
      "avatarUrl": "https://cdn.ataboyexpress.com/riders/b2c7f5a1.jpg",
      "vehicle": "bike",
      "plateNumber": "LAG-472-KJA"
    }
  }
}

Fields in data

FieldTypeDescription
deliveryIdstring (uuid)Ataboy's ID for the delivery. Store it against your order.
businessOrderIdstring | nullYour own order reference. Taken from externalOrderId when you set it on create, otherwise parsed out of description. Null if neither is present.
trackingNumberstringPublic tracking code, e.g. ATB-8F3K2Q.
statusstringDelivery status at the time of the event: pending, assigned, picked_up, in_transit, delivered, cancelled or failed.
feenumberDelivery fee in naira (not kobo).
receiverNamestringName of the person receiving the package.
receiverPhonestringReceiver's phone number in E.164 format.
receiverEmailstring | nullReceiver's email when provided on create. Used by Ataboy to send delivered confirmation + review link.
pickupCitystringPickup city.
dropoffCitystringDropoff city.
pickupLgastring | nullPickup local government area, when the address resolved to one.
pickupPlacestring | nullPickup landmark or estate, when known.
dropoffLgastring | nullDropoff local government area, when the address resolved to one.
dropoffPlacestring | nullDropoff landmark or estate, when known.
pricingSourcestring | nullHow the fee was calculated: ataboy_default, partner_rate_card or partner_markup.
matchedRateNamestring | nullName of the Integration Hub rate card row that priced this delivery, or the markup label. Null on default pricing.
trackingUrlstringCustomer-facing tracking page for this delivery.
deliveryCodestring4-digit code the receiver reads out to the rider to confirm handover. Safe to show the receiver, never the public.
custodyPhotoUrlstring | nullLatest chain-of-custody photo (parcel condition at pickup, or proof at delivery). Null until a photo is uploaded.
custodyPhotoUrlsstring[]All custody photos from the latest capture (pickup may include up to 5). Empty array until photos are uploaded.
completedAtstring | nullISO timestamp of completion. Only set once status is delivered, null otherwise.
riderobject | nullAssigned rider, or null before assignment. See the rider fields below.

Fields in data.rider

rider is null on delivery.created and populated from delivery.assigned onwards.

FieldTypeDescription
rider.idstring (uuid)Ataboy rider ID.
rider.namestring | nullRider's full name.
rider.phonestring | nullRider's phone number, for customer support calls.
rider.avatarUrlstring | nullRider photo, safe to show the customer.
rider.vehiclestringbike, car, van or truck.
rider.plateNumberstring | nullVehicle plate number.

Test events

Sending a test event from your dashboard delivers the same envelope with a stub body, so guard against it before touching your order records:

{
  "id": "0c9a...",
  "event": "delivery.assigned",
  "createdAt": "2026-08-08T14:22:09.145Z",
  "timestamp": 1786213329,
  "data": {
    "test": true,
    "message": "Ataboy Express Integration Hub test event"
  }
}

Verify signatures (Node.js)

Always verify using the raw request body (not a re-serialized JSON object):

import crypto from "node:crypto";

function verifyAtaboySignature(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  const provided = (signatureHeader || "").replace(/^sha256=/, "");
  const a = Buffer.from(expected);
  const b = Buffer.from(provided);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Also reject requests where X-Ataboy-Timestamp (or the body’s timestamp) is more than 5 minutes away from your clock, so a captured request cannot be replayed.

Retries & what to respond

Reply 2xx as soon as you have stored the event and do the real work afterwards. Anything else , a non-2xx status or no response within 10 seconds, counts as a failure.

  • Up to 5 attempts per event
  • Exponential backoff between attempts: 250ms, 500ms, 1s, then 2s
  • 10 second timeout on each attempt
  • The first 4000 characters of your response body are kept in the delivery log
Retries mean the same id can arrive more than once, and events can arrive out of order. Treat handlers as idempotent: key off data.deliveryId and ignore an event whose status is behind the one you already recorded.

11. Errors & status codes

CodeMeaningWhat to do
400Validation / business rule errorFix payload (or don’t cancel completed deliveries)
401Missing/invalid API credentialsCheck key + secret; ensure key is active
403Live key locked / suspendedUse test keys or finish compliance
404Delivery / tracking not foundConfirm ID belongs to your account

Error body shape:

{ "message": "Invalid API credentials" }

12. Go-live checklist

  1. Estimate + create delivery works with test keys
  2. Your OMS stores delivery.id and trackingNumber
  3. Webhook endpoint verifies signatures and handles all subscribed events
  4. Cancel flow tested for pending/assigned orders
  5. Compliance submitted and approved in Business dashboard
  6. Live keys generated and stored securely (test keys kept for staging)
  7. Production base URL and webhook URL updated

13. Demo credentials

Use these against https://api.ataboyexpress.com while developing:

  • FreshMart (test only)
    Key: atb_test_fmdemo01
    Secret: demo_secret_freshmart_00000001
  • DrinkCravings (test)
    Key: atb_test_dcdemo01
    Secret: demo_secret_drinkcravings_test1
  • DrinkCravings (live, compliance approved)
    Key: atb_live_dcdemo01
    Secret: demo_secret_drinkcravings_0001

Use the test and live API keys from your Partner dashboard after signup. Live keys require compliance approval.