Book a delivery
Booking turns a quote into a delivery. Reeds charges your wallet (or adds the delivery to your monthly invoice) and returns the tracking code at once.
Book from a quote
POST /deliveries with the quote_id. The quote must be unexpired and unused, and the price is exactly what the quote showed. The package is the one you quoted, so it has already been checked against what Reeds carries.
The Idempotency-Key header is required on this call. Reuse the same key when you retry, so a network error can never book twice. See Idempotency.
| Field | Type | Description |
|---|---|---|
quote_id | string | required. An unexpired, unused quote. |
ready | boolean | Default true. Send false if the item isn't packed yet; the delivery waits in requires_action until you mark it ready. |
reference | string | Your order number. Shown in the dashboard and in webhooks. It doesn't have to be unique. |
shipper | object | Platform accounts only, and required for them: business_name (required), phone (required) and merchant_id. Business accounts leave it out; it is ignored if sent. See Platforms. |
pickup_instructions | string | Instructions for this delivery only. |
dropoff_instructions | string | Instructions for this delivery only. |
metadata | object | Any key-value data you want back on the delivery and in webhooks. |
- cURL
- Node.js
- PHP
- Python
curl https://api.getreeds.co/shipping/v1/deliveries \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN" \
-H "Idempotency-Key: order-10045-book" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "qt_2bX9Wn4K",
"reference": "ORDER-10045",
"pickup_instructions": "Call on arrival",
"metadata": { "store_id": "42" }
}'
const res = await fetch('https://api.getreeds.co/shipping/v1/deliveries', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.REEDS_ACCESS_TOKEN}`,
'Idempotency-Key': 'order-10045-book',
'Content-Type': 'application/json',
},
body: JSON.stringify({
quote_id: 'qt_2bX9Wn4K',
reference: 'ORDER-10045',
pickup_instructions: 'Call on arrival',
metadata: { store_id: '42' },
}),
});
const { data } = await res.json();
console.log(data.id, data.tracking_code);
<?php
$ch = curl_init('https://api.getreeds.co/shipping/v1/deliveries');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('REEDS_ACCESS_TOKEN'),
'Idempotency-Key: order-10045-book',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'quote_id' => 'qt_2bX9Wn4K',
'reference' => 'ORDER-10045',
'pickup_instructions' => 'Call on arrival',
'metadata' => ['store_id' => '42'],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $body['data']['id'], ' ', $body['data']['tracking_code'];
import os
import requests
res = requests.post(
"https://api.getreeds.co/shipping/v1/deliveries",
headers={
"Authorization": f"Bearer {os.environ['REEDS_ACCESS_TOKEN']}",
"Idempotency-Key": "order-10045-book",
},
json={
"quote_id": "qt_2bX9Wn4K",
"reference": "ORDER-10045",
"pickup_instructions": "Call on arrival",
"metadata": {"store_id": "42"},
},
)
data = res.json()["data"]
print(data["id"], data["tracking_code"])
{
"status": "success",
"data": {
"id": "dlv_9Kd3Qx7M",
"status": "scheduled",
"tracking_code": "HQ3W5F2",
"tracking_url": "https://getreeds.co/packages/HQ3W5F2",
"reference": "ORDER-10045",
"cancellable": true,
"fee": { "total": 280000, "currency": "NGN", "status": "charged", "billing": "wallet" },
"...": "other delivery fields, see below"
}
}
If the wallet can't cover the price you get 402 INSUFFICIENT_BALANCE; an invoice account over its limit gets 402 CREDIT_LIMIT_REACHED. See Errors.
What happens after booking
The tracking code is reserved at booking and returned in the response, so you can show it to your customer immediately. Reeds then sets the delivery up with its riders and hubs, usually within seconds, and the delivery moves on through its statuses.
In the rare case that Reeds can't set the delivery up within 30 minutes, Reeds cancels the delivery with a full refund. You receive a delivery.cancelled webhook whose cancellation.reason is processing_failed. See Cancellations.
The delivery object
{
"id": "dlv_9Kd3Qx7M",
"livemode": false,
"channel": "platform",
"shipper": { "business_name": "Tola Fabrics", "phone": "08051234567", "merchant_id": "m_8812" },
"reference": "ORDER-10045",
"status": "picked_up",
"required_actions": [],
"cancellable": false,
"tracking_code": "HQ3W5F2",
"tracking_url": "https://getreeds.co/packages/HQ3W5F2",
"service": "standard",
"route": { "type": "via_hub", "distance_km": 13.5 },
"pickup": {
"address": { "id": "adr_7Hq2Lk9P", "contact": { "...": "..." }, "location": { "...": "..." } },
"instructions": "Call on arrival",
"completed_at": "2026-10-26T13:05:00+01:00"
},
"dropoff": {
"address": { "id": "adr_5Vb1Jc8D", "contact": { "...": "..." }, "location": { "...": "..." } },
"instructions": null,
"completed_at": null
},
"package": { "description": "2 pairs of sneakers", "quantity": 1, "weight_kg": 1.5, "declared_value": 4500000 },
"liability": { "covered_amount": 4500000, "cap": 5000000 },
"fee": {
"delivery_fee": 255000, "vat": 19125, "service_charge": 5875, "discount": 0,
"total": 280000, "currency": "NGN",
"status": "charged",
"billing": "invoice"
},
"schedule": {
"pickup_by": "2026-10-26T19:00:00+01:00",
"deliver_by": "2026-10-27T19:00:00+01:00",
"earliest_delivery": "2026-10-26T19:00:00+01:00"
},
"ready": true,
"auto_book": false,
"rider": { "first_name": "Tunde" },
"hold_reason": null,
"cancellation": null,
"events": [
{ "status": "scheduled", "at": "2026-10-26T10:20:00+01:00", "note": null },
{ "status": "rider_assigned", "at": "2026-10-26T11:40:00+01:00", "note": null },
{ "status": "picked_up", "at": "2026-10-26T13:05:00+01:00", "note": null }
],
"metadata": { "store_id": "42" },
"created_at": "2026-10-26T10:20:00+01:00",
"booked_at": "2026-10-26T10:20:00+01:00",
"updated_at": "2026-10-26T13:05:00+01:00"
}
| Field | Type | Description |
|---|---|---|
id | string | The delivery id, starting dlv_. |
livemode | boolean | false for Test mode deliveries. |
channel | string | direct (a business account), platform (a platform account) or store (a Reeds store). |
shipper | object or null | The merchant a platform ships for. null except on platform deliveries. |
reference | string or null | Your own order number. |
status | string | See Delivery statuses. Clients must tolerate new values. |
required_actions | array | What is still outstanding on a draft or unready delivery. See Drafts and required actions. |
cancellable | boolean | true until the rider sets off for the pickup. See Cancellations. |
tracking_code | string or null | null on a draft, until it is booked. |
tracking_url | string or null | Public tracking page for the receiver: https://getreeds.co/packages/<tracking_code>. |
service, route | string, object | As on the quote: standard; direct or via_hub. |
pickup, dropoff | object | address is the copy taken at booking (later edits to the saved address don't change it), plus instructions and completed_at. |
package | object | description, quantity, weight_kg, declared_value (kobo) and, if you sent it, dimensions_cm. |
liability | object | covered_amount and cap (kobo): what Reeds covers if the parcel is lost or damaged. See What Reeds carries. |
fee | object or null | The price in kobo. null until priced. status is unpriced, quoted (priced, not charged), charged or refunded. billing is wallet or invoice. |
schedule | object | pickup_by, and the delivery range: earliest_delivery to deliver_by. See Delivery promise. |
ready | boolean | Whether the item is packed. Not a status. |
auto_book | boolean | Whether Reeds books a draft by itself once it can. |
rider | object or null | The rider's first_name only. |
hold_reason | string or null | Why Reeds paused the delivery, when status is on_hold. |
cancellation | object or null | null until cancelled. See Cancellations. |
events | array | Each status change, with status, at and an optional note. |
metadata | object | Whatever you stored. |
created_at, booked_at, updated_at | datetime | ISO 8601 with the Lagos offset. booked_at is null on a draft. |
Get a delivery
GET /deliveries/{id} returns one delivery.
curl https://api.getreeds.co/shipping/v1/deliveries/dlv_9Kd3Qx7M \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN"
List deliveries
GET /deliveries returns your deliveries, newest first, paginated.
| Query | Description |
|---|---|
status | Only deliveries in this status. |
reference | Only deliveries with this reference. |
merchant_id | Platform accounts: only that merchant's deliveries (shipper.merchant_id). |
created_from, created_to | Only deliveries created in this window. |
ids | Comma-separated ids, for example ids=dlv_a,dlv_b. Fetches up to 50 specific deliveries in one call. |
curl "https://api.getreeds.co/shipping/v1/deliveries?status=scheduled&reference=ORDER-10045" \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN"
Prefer webhooks to polling; use ids for the occasional reconciliation.
Update a delivery
PATCH /deliveries/{id} changes reference, pickup_instructions, dropoff_instructions and metadata.
curl -X PATCH https://api.getreeds.co/shipping/v1/deliveries/dlv_9Kd3Qx7M \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "dropoff_instructions": "Gate code 4411" }'
The API can't change a stop's contact name and phone. To change the receiver's name or phone after booking, email support@getreeds.co with the delivery id. An address can't be changed through the API after booking either: ask Reeds support to move it. The price difference is charged or refunded through your wallet.