Skip to content
OkadaDrop

Developers

API reference

Ten keyed endpoints cover the whole lifecycle, plus one open read for tracking. Bodies are JSON in and JSON out, times are ISO-8601 in UTC, money is in Ghana cedis and every id is a UUID.


  • POST/partner/quotes

    Price a pickup → drop-off pair.

    Costs nothing and commits to nothing. Uses the same rate card as the app: a base fare, a distance fee over the real road distance, and a flat service fee.

  • POST/partner/deliveries

    Book a delivery.

    Priced and dispatched server-side. Returns immediately with status `pending`; a rider is found within seconds and you are told about it by webhook.

  • GET/partner/deliveries

    List your deliveries, newest first.

    Paginated with `limit` (default 20, max 100) and `offset`.

  • GET/partner/deliveries/{id}

    Fetch one delivery.

    Includes the full event trail — every status change with its timestamp.

  • POST/partner/deliveries/{id}/cancel

    Cancel a delivery.

    Allowed until the rider has picked the parcel up. Free before a rider accepts.

  • GET/partner/payment-methods

    List the Mobile Money accounts you can be debited from.

    Default first. Never returns anything provider-internal.

  • POST/partner/payment-methods

    Register a Mobile Money account to pay for deliveries.

    The first account you register becomes the default automatically.

  • DELETE/partner/payment-methods/{id}

    Remove a Mobile Money account.

    Stops future bookings debiting it. Deliveries already booked against it, and money already taken, are unaffected.

  • GET/partner/webhook

    Read your configured callback URL.

  • PUT/partner/webhook

    Set, replace or clear your callback URL.

    Setting a URL returns a fresh signing secret and invalidates the previous one. Send `null` to stop receiving callbacks.

  • GET/track/{id}/public

    Redacted progress, route and the rider's live position. No key.

    Outside /partner deliberately: the delivery id is the credential, so this is the one endpoint you can call from your customer's browser. See Tracking.

Quote a route

Optional — booking prices the delivery itself. Use it to show a customer a fare before they commit.

Request
POST https://api.okadadrop.com/api/v1/partner/quotes

{
  "pickup_lat": 5.5560,
  "pickup_lng": -0.1820,
  "dropoff_lat": 5.6360,
  "dropoff_lng": -0.1530
}
200 response
{
  "base_fare": 10.0,
  "distance_km": 7.4,
  "distance_fee": 14.36,
  "service_fee": 2.0,
  "total_fare": 26.36
}

Book a delivery

The one call that matters. OkadaDrop prices the route, charges it to the payment method you name, and starts looking for a rider immediately.

curl -X POST https://api.okadadrop.com/api/v1/partner/deliveries \
  -H "Authorization: Bearer $SOMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pickup_address": "Osu, Accra",
    "pickup_lat": 5.5560, "pickup_lng": -0.1820,
    "dropoff_address": "East Legon, Accra",
    "dropoff_lat": 5.6360, "dropoff_lng": -0.1530,
    "package_size": "small",
    "package_description": "Two shirts, boxed",
    "recipient_name": "Ama",
    "recipient_phone": "+233209876543",
    "payment_method": "paystack",
    "verification_method": "otp"
  }'
201 response
{
  "id": "8f3b2c1e-...",
  "status": "pending",
  "pickup_address": "Osu, Accra",
  "dropoff_address": "East Legon, Accra",
  "package_size": "small",
  "recipient_name": "Ama",
  "recipient_phone": "+233209876543",
  "rider_id": null,
  "base_fare": 10.0,
  "distance_km": 7.4,
  "distance_fee": 14.36,
  "service_fee": 2.0,
  "total_fare": 26.36,
  "payment_method": "paystack",
  "payment_status": "pending",
  "verification_method": "otp",
  "created_at": "2026-07-30T10:14:03Z",
  "events": [
    { "status": "pending", "created_at": "2026-07-30T10:14:03Z" }
  ]
}

Request fields

Fields accepted when booking a delivery
pickup_addressTypestringNotesHuman-readable, shown to the rider.
pickup_lat / pickup_lngTypenumberNotesWhere the rider collects. Accuracy here is what makes a pickup quick.
dropoff_addressTypestringNotesHuman-readable, shown to the rider.
dropoff_lat / dropoff_lngTypenumberNotesWhere it is going.
package_sizeTypesmall | medium | largeNotesWhat a bike can carry: an envelope, a backpack, a boot-sized box.
recipient_nameTypestringNotesWho the rider is handing it to.
recipient_phoneTypestringNotesGhana format, e.g. +233209876543. Used for masked calling, never shared in the clear.
payment_methodTypepaystackNotesThe only value. Deliveries are prepaid by Mobile Money — riders carry no cash. See Paying for deliveries.
payment_method_idTypeUUID · optionalNotesWhich registered MoMo account to debit. Omit and your default is used.
package_descriptionTypestring · optionalNotesA note for the rider — 'fragile', 'ask for Ama at reception'.
verification_methodTypenone | otp | photo · optionalNotesProof of handover. `otp` texts the recipient a code the rider must enter; `photo` requires an uploaded picture.
scheduled_atTypeISO-8601 · optionalNotesBook ahead. Omit to dispatch now.
additional_stopsTypearray · optionalNotesUp to 10 earlier drop-offs, visited in the order given before the address above. One rider carries the lot.

Turning an address into coordinates

Booking takes latitude and longitude, so text addresses have to be resolved first. Two open endpoints do it — no API key, and they are the same ones the OkadaDrop app searches with, so they know Ghanaian addresses that a general geocoder does not.

  • GET/places/autocomplete?q=

    Search addresses, returning suggestions with a place_id each.

  • GET/places/resolve?place_id=

    Turn one suggestion into the coordinates you book with.

# 1. Search. No key needed on either of these.
curl "https://api.okadadrop.com/api/v1/places/autocomplete?q=A%26C%20Mall"

# [{ "place_id": "ChIJ…", "title": "A&C Mall", "subtitle": "East Legon, Accra" }]

# 2. Turn the one you want into coordinates.
curl "https://api.okadadrop.com/api/v1/places/resolve?place_id=ChIJ…"

# { "address": "A&C Mall, East Legon, Accra", "lat": 5.6360, "lng": -0.1530 }

Resolve once, when the customer picks the address — not on every booking. A stored coordinate is faster, cheaper and cannot drift on you between the order and the dispatch.

Multiple drop-offs

One rider can carry up to ten earlier stops before the destination in the fields above. Send them in additional_stops, in the order you want them visited — each is a drop in its own right, with its own recipient, phone and parcel. The fare is priced over the whole route, and the delivery only reaches delivered once the last stop is handed over.

Booking body
{
  "pickup_address": "Osu, Accra",
  "pickup_lat": 5.5560, "pickup_lng": -0.1820,

  "additional_stops": [
    {
      "dropoff_address": "Airport Residential, Accra",
      "dropoff_lat": 5.6050, "dropoff_lng": -0.1760,
      "recipient_name": "Kofi",
      "recipient_phone": "+233201234567",
      "package_size": "small"
    }
  ],

  "dropoff_address": "East Legon, Accra",
  "dropoff_lat": 5.6360, "dropoff_lng": -0.1530,
  "package_size": "small",
  "recipient_name": "Ama",
  "recipient_phone": "+233209876543",
  "payment_method": "paystack"
}
Fields of one entry in additional_stops
dropoff_addressTypestringNotesHuman-readable, shown to the rider.
dropoff_lat / dropoff_lngTypenumberNotesWhere this stop is.
recipient_nameTypestringNotesWho takes the parcel at this stop.
recipient_phoneTypestringNotesGhana format. Each stop is called on its own number.
package_sizeTypesmall | medium | largeNotesWhat this stop's parcel is.
package_descriptionTypestring · optionalNotesA note for the rider about this stop.

Track a delivery

Fetch one by id for its current status and full event trail, or list the account’s deliveries newest-first. Both are the same records the dashboard shows.

curl "https://api.okadadrop.com/api/v1/partner/deliveries?limit=20&offset=0" \
  -H "Authorization: Bearer $SOMA_API_KEY"

Statuses

A delivery moves forward only. Three of these are terminal — nothing follows them.

Delivery statuses and what each one means
pendingMeaningBooked. Looking for a rider.
acceptedMeaningA rider took the job and is riding to your pickup.
picked_upMeaningThe parcel is on the bike.
in_transitMeaningOn the way to the drop-off.
deliveredMeaningHanded over. Terminal.
cancelledMeaningCalled off by you or by the sender. Terminal.
expiredMeaningNo rider could be found before the deadline. Terminal — book again.

Cancel a delivery

POST /partner/deliveries/{id}/cancel works until the rider has the parcel in hand. Before a rider accepts it costs nothing. Afterwards you are cancelling a rider already on their way, so do it quickly or not at all. Past picked_up the call returns a 400: the parcel is on a bike across town, and the way to deal with that is to call the rider from the delivery record.

Pagination

List endpoints take limit (default 20, max 100) and offset. They return a plain JSON array — there is no envelope and no cursor. Page until you get back fewer rows than you asked for.

NextWebhooksStatus callbacks and signature verification.