Aldor Partner API

The Aldor Partner API lets your business use Aldor's riders and vendor tools from your own systems. It's a REST API: requests and responses are JSON, and every request is authenticated with your secret key.

Base URL: https://i-dormot.onrender.com/v1

Every response has the same shape: status (true or false), data on success, and message and code on errors.

Authentication

Create a partner account, then create keys in your partner dashboard. Send your secret key in the Authorization header on every request:

request.sh
1curl https://i-dormot.onrender.com/v1/wallet \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY"

Keep secret keys on your server only. Never put them in a mobile app, a website's JavaScript or a public repository. If a key leaks, revoke it from the dashboard and create a new one; the old key stops working at once.

Each key is limited to the products you pick when you create it (Deliveries, Commerce). A key used for a product it doesn't have gets a 403.

Test & live mode

Keys come in two modes. ald_sk_test_… keys work in test mode: no rider is sent and only test money moves. Move a test delivery along with POST /deliveries/:id/simulate to try every status and webhook.

ald_sk_live_… keys book real riders and charge your account. Live keys are available once your business is verified. Test and live data are kept fully separate.

Wallet & billing

Deliveries are paid from your prepaid partner wallet. Fund your live wallet by card from the dashboard. Test mode starts with ₦100,000 of test money and you can add more any time.

  • Create a delivery: the quoted amount is held from your available balance. If it's too low the request fails with 402 and code insufficient_balance.
  • Delivered: the held amount is charged.
  • Cancelled before a rider is assigned: the hold is released in full. After that, a cancellation fee applies. A failed delivery is released in full.

Set a low-balance alert in the dashboard to get a wallet.low_balance webhook before deliveries start failing.

Errors

Errors return a non-2xx status and a message you can show or log:

response.json402
1{
2 "status": false,
3 "message": "Your available balance cannot cover this delivery. Fund your wallet and retry.",
4 "code": "insufficient_balance"
5}
  • 400Bad requestA field is missing or invalid. The message says which.
  • 401UnauthorizedNo API key, or the key is wrong or revoked.
  • 402Payment requiredYour wallet's available balance can't cover this delivery. Fund it and retry.
  • 403ForbiddenThe key can't do this: missing scope, simulate with a live key, or a live key before verification.
  • 404Not foundThe id doesn't exist, or belongs to another partner.
  • 409ConflictDuplicate reference, a quote already used, or a delivery that can no longer be changed.
  • 422UnprocessableValid request that can't be done, e.g. the drop-off is too far.
  • 429Too many requestsRate limit reached. Retry after the Retry-After header.
  • 500Server errorSomething went wrong on our side. Safe to retry with the same Idempotency-Key.

Rate limits

Each key has its own limit, so one integration never slows another. Every response includes RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers. Past the limit you get a 429; wait for the reset and retry.

Idempotency

Send an Idempotency-Key header (any unique string, e.g. your order id) with POST requests. If the network fails and you retry with the same key, Aldor returns the original result instead of booking a second delivery.

Deliveries

Book Aldor riders for your own customers: get a price, create a delivery, track it to the door.

Get a delivery quote

POST/deliveries/quotes

Price and estimated time for a pickup and drop-off. Quotes are valid for 10 minutes and can be used once; pass the quote id when you create the delivery to lock the price. Send latitude and longitude when you have them, otherwise the address is looked up.

Body

  • pickuprequired
    objectWhere the rider collects the package: address (required), latitude, longitude, contact_name, contact_phone.
  • dropoffrequired
    objectWhere the rider delivers, same fields as pickup.
  • package.size
    stringsmall, medium or large. Defaults to small.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/deliveries/quotes \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "pickup": {
6 "address": "Ikeja City Mall, Ikeja, Lagos",
7 "latitude": 6.6018,
8 "longitude": 3.3515,
9 "contact_name": "Front desk",
10 "contact_phone": "+2348030000000"
11 },
12 "dropoff": {
13 "address": "12 Allen Avenue, Ikeja, Lagos",
14 "latitude": 6.6006,
15 "longitude": 3.3601
16 },
17 "package": {
18 "size": "small"
19 }
20 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "qte_8Hx2kP4mQ1aZ",
5 "amount": 1250,
6 "currency": "NGN",
7 "distance_km": 3.4,
8 "eta_minutes": 14,
9 "package": {
10 "size": "small"
11 },
12 "expires_at": "2026-10-14T17:40:00.000Z",
13 "livemode": false
14 }
15}

Create a delivery

POST/deliveries

Books a rider and holds the quoted amount in your wallet. Riders near the pickup are offered the job, and webhooks follow as it moves. Give the pickup_code to whoever hands over the package: the rider must enter it to collect. Send an Idempotency-Key header so a retried request never books twice.

Body

  • quote_idrequired
    stringA quote from POST /deliveries/quotes that hasn't expired or been used.
  • referencerequired
    stringYour own order reference. Must be unique per delivery.
  • items
    arrayWhat's being delivered ({ name, quantity }), shown to the rider.
  • notes
    stringInstructions for the rider, e.g. gate code.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/deliveries \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "quote_id": "qte_8Hx2kP4mQ1aZ",
6 "reference": "ORD-10293",
7 "items": [
8 {
9 "name": "Running shoes",
10 "quantity": 1
11 }
12 ],
13 "notes": "Call on arrival"
14 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "dlv_3Jf9aQ1zWc7T",
5 "reference": "ORD-10293",
6 "status": "searching_rider",
7 "amount": 1250,
8 "currency": "NGN",
9 "pickup_code": "4821",
10 "rider": null,
11 "livemode": false,
12 "created_at": "2026-10-14T17:31:05.000Z"
13 }
14}

Retrieve a delivery

GET/deliveries/:id

Current status, and the rider with their live location once one is assigned. Statuses: searching_rider, rider_assigned, picked_up, delivered, cancelled, failed.

Path & query parameters

  • idrequired
    stringThe delivery id, e.g. dlv_3Jf9aQ1zWc7T.
request.sh
1curl https://i-dormot.onrender.com/v1/deliveries/dlv_3Jf9aQ1z \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY"
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "dlv_3Jf9aQ1zWc7T",
5 "reference": "ORD-10293",
6 "status": "picked_up",
7 "amount": 1250,
8 "rider": {
9 "name": "Tunde A.",
10 "phone": "+2348033333333",
11 "vehicle": "bike",
12 "plate_number": "LSR-123XY",
13 "rating": 4.8
14 },
15 "rider_location": {
16 "latitude": 6.6011,
17 "longitude": 3.3508,
18 "updated_at": "2026-10-14T17:44:12.000Z"
19 },
20 "eta_minutes": 14,
21 "picked_up_at": "2026-10-14T17:42:30.000Z"
22 }
23}

List deliveries

GET/deliveries

Your deliveries, newest first. Filter by status.

Path & query parameters

  • status
    stringsearching_rider, rider_assigned, picked_up, delivered, cancelled or failed.
  • page
    integerPage number, from 1.
  • limit
    integerPer page, up to 100. Defaults to 20.
request.sh
1curl https://i-dormot.onrender.com/v1/deliveries \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY"
response.json200 OK
1{
2 "status": true,
3 "data": [
4 {
5 "id": "dlv_3Jf9aQ1zWc7T",
6 "reference": "ORD-10293",
7 "status": "delivered",
8 "amount": 1250
9 }
10 ],
11 "meta": {
12 "page": 1,
13 "per_page": 20,
14 "total": 1
15 }
16}

Cancel a delivery

POST/deliveries/:id/cancel

Free before a rider is assigned. After a rider is assigned a cancellation fee applies (returned in cancellation_fee). Deliveries can't be cancelled once picked up.

Path & query parameters

  • idrequired
    stringThe delivery id.

Body

  • reason
    stringWhy it's being cancelled.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/deliveries/dlv_3Jf9aQ1z/cancel \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "reason": "Customer cancelled the order"
6 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "dlv_3Jf9aQ1zWc7T",
5 "status": "cancelled",
6 "cancellation_fee": 0
7 }
8}

Simulate rider updates (test mode)

POST/deliveries/:id/simulate

Test keys only. Moves a test delivery along as a rider would, sending the same webhooks and wallet changes as live. Go in order: rider_assigned, picked_up, then delivered (or failed).

Path & query parameters

  • idrequired
    stringA test delivery id.

Body

  • eventrequired
    stringrider_assigned, picked_up, delivered or failed.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/deliveries/dlv_3Jf9aQ1z/simulate \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "event": "rider_assigned"
6 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "dlv_3Jf9aQ1zWc7T",
5 "status": "rider_assigned",
6 "rider": {
7 "name": "Test R.",
8 "vehicle": "bike"
9 }
10 }
11}

Check your wallet

GET/wallet

Balance for the key's mode. available is what new deliveries can use (balance minus held).

request.sh
1curl https://i-dormot.onrender.com/v1/wallet \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY"
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "currency": "NGN",
5 "balance": 98400,
6 "held": 1250,
7 "available": 97150,
8 "livemode": false
9 }
10}

Commerce (coming soon)

Coming soon. For vendors and their systems: keep products and stock in sync, and receive Aldor orders in your own POS or dashboard. The endpoints below show the planned shape.

Create or update products

POST/stores/:store_id/products

Send up to 100 products at a time. Products are matched on your sku, so sending the same sku again updates it.

Path & query parameters

  • store_idrequired
    stringYour Aldor store id.

Body

  • products[].skurequired
    stringYour product code.
  • products[].namerequired
    stringName shown to customers.
  • products[].pricerequired
    numberPrice in naira.
  • products[].stock
    integerUnits available. Omit for unlimited.
  • products[].available
    booleanHide or show the product.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/stores/str_91/products \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "products": [
6 {
7 "sku": "JR-001",
8 "name": "Jollof Rice",
9 "price": 2500,
10 "stock": 40,
11 "available": true
12 },
13 {
14 "sku": "CH-014",
15 "name": "Fried Chicken",
16 "price": 1800,
17 "stock": 0,
18 "available": false
19 }
20 ]
21 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "created": 1,
5 "updated": 1,
6 "failed": []
7 }
8}

List orders

GET/stores/:store_id/orders

Orders placed with your store on Aldor, newest first. Filter by status and date.

Path & query parameters

  • store_idrequired
    stringYour Aldor store id.
  • status
    stringpending, accepted, ready, completed or cancelled.
  • page
    integerPage number, from 1.
request.sh
1curl https://i-dormot.onrender.com/v1/stores/str_91/orders \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY"
response.json200 OK
1{
2 "status": true,
3 "data": [
4 {
5 "id": "ord_7Kp2xV9c",
6 "order_number": "582014",
7 "status": "pending",
8 "total": 6800,
9 "items": [
10 {
11 "sku": "JR-001",
12 "name": "Jollof Rice",
13 "quantity": 2,
14 "price": 2500
15 }
16 ],
17 "created_at": "2026-10-14T17:20:41Z"
18 }
19 ],
20 "meta": {
21 "page": 1,
22 "per_page": 20,
23 "total": 1
24 }
25}

Accept an order

POST/orders/:id/accept

Confirms the order and tells the customer you're preparing it. Use /orders/:id/reject to decline.

Path & query parameters

  • idrequired
    stringThe order id.

Body

  • prep_minutes
    integerHow long until it's ready for the rider.
request.sh
1curl -X POST https://i-dormot.onrender.com/v1/orders/ord_7Kp2xV9c/accept \
2 -H "Authorization: Bearer $ALDOR_SECRET_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "prep_minutes": 15
6 }'
response.json200 OK
1{
2 "status": true,
3 "data": {
4 "id": "ord_7Kp2xV9c",
5 "status": "accepted"
6 }
7}

Webhooks

Add a webhook URL in your dashboard and Aldor sends a POST to it whenever something happens. Reply with a 2xx within 10 seconds. If it fails we retry four more times, after 30 seconds, 2 minutes, 10 minutes and 30 minutes. Every attempt is listed under Webhooks in your dashboard.

  • delivery.rider_assignedA rider accepted the delivery.
  • delivery.picked_upThe rider collected the package.
  • delivery.deliveredThe package was handed over.
  • delivery.failedThe delivery couldn't be completed.
  • delivery.cancelledThe delivery was cancelled.
  • order.createdA customer placed an order with your store (Commerce, coming soon).
  • order.cancelledAn order was cancelled (Commerce, coming soon).
  • wallet.low_balanceYour available balance fell below your alert amount.
  • wallet.fundedA card payment was added to your live wallet.
event.json
1{
2 "id": "evt_2Lq8sY4n",
3 "type": "delivery.delivered",
4 "created_at": "2026-10-14T17:58:30Z",
5 "livemode": false,
6 "data": {
7 "id": "dlv_3Jf9aQ1z",
8 "reference": "ORD-10293",
9 "status": "delivered",
10 "delivered_at": "2026-10-14T17:58:29Z"
11 }
12}

Verifying signatures

Every webhook carries an x-aldor-signature header: an HMAC SHA-512 of the raw request body, signed with your webhook secret. Check it before trusting the event.

index.js
1import crypto from "node:crypto";
2import express from "express";
3 
4const app = express();
5 
6// Keep the raw body: the signature is over the exact bytes received
7app.post("/webhooks/aldor", express.raw({ type: "application/json" }), (req, res) => {
8 const signature = req.header("x-aldor-signature") ?? "";
9 const expected = crypto
10 .createHmac("sha512", process.env.ALDOR_WEBHOOK_SECRET)
11 .update(req.body)
12 .digest("hex");
13 
14 const valid =
15 signature.length === expected.length &&
16 crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
17 if (!valid) return res.sendStatus(401);
18 
19 const event = JSON.parse(req.body.toString());
20 console.log(event.type, event.data.id); // e.g. "delivery.delivered"
21 
22 res.sendStatus(200); // reply fast; do slow work in a queue
23});