7feastr
Get Rate & ETAAPITrack ShipmentContactBlog
LoginRegister
Documentation/Logistics API
Quotes & shipmentsMenu
Overview

Get started

Getting startedAuthenticationSandbox and production

Plan your integration

Coverage & delivery timesPricing

API reference

Quotes & shipmentsTrackingWallet & disputes

Integrate

WebhooksErrors & rate limits

Resources

Changelog
K
Overview

Get started

Getting startedAuthenticationSandbox and production

Plan your integration

Coverage & delivery timesPricing

API reference

Quotes & shipmentsTrackingWallet & disputes

Integrate

WebhooksErrors & rate limits

Resources

Changelog
7feastr

Nigeria's food delivery and logistics infrastructure. Order from your favourite local restaurants, or ship anywhere in the country with 7feastr Logistics.

support@7feastr.com
+234 905 606 2230
Lagos, Nigeria

Company

  • About Us
  • Blog

Services

  • Nearby Restaurants
  • Logistics
  • Track Shipment
  • API Documentation

Food in Kaduna

  • Food Delivery in Kaduna
  • Shawarma
  • Jollof Rice
  • Chicken
  • Suya & Grills
  • Pizza
  • Swallow & Soup

Partners

  • Become an Agent
  • Become an Ambassador

Support

  • FAQ
  • Contact
  • System status
  • Privacy Policy
  • Terms of Service
  • Monetary Policy
  • Refund Policy

© 2026 7feastr Technologies Ltd. All rights reserved.

API reference

Quotes & shipments

Get a quote with a price and ETA, then book the shipment against your wallet.

Last updated 21 October 2026

Booking a delivery takes two calls. First request a quote, then create the shipment with the quote's quoteId. Quoting first confirms that we deliver to both addresses and locks the price you show your customer.

Service types

Every quote and shipment needs a serviceType:

serviceTypeWhat it meansWeight limit
consolidatedYour parcel shares a vehicle with other parcels on the same route. Billed by route and weight0.01 kg to 200 kg
dedicatedA full vehicle reserved for your load. Billed by route and vehicle0.01 kg to 4,500 kg

See Pricing for the vehicles used and how each service is priced.

Get a quote

POST/rates/estimate

Auth: API key. Returns a price, an ETA and a quoteId that is valid for 10 minutes and can be used once.

Request fields

FieldTypeRequiredDescription
serviceTypestringYesconsolidated or dedicated
packageWeightKgnumberYesWeight in kilograms. 0.01 to 200 for consolidated, 0.01 to 4,500 for dedicated
pickupAddressstringYesStreet address of the pickup, in Nigeria
pickupCitystringYesTown or area of the pickup, for example Ikeja
pickupStatestringYesState of the pickup. Lagos, Lagos State, FCT and Abuja are all accepted
dropoffAddressstringYesStreet address of the recipient, in Nigeria
dropoffCitystringYesTown or area of the dropoff
dropoffStatestringYesState of the dropoff
declaredValuenumberNoValue of the goods in NGN, used for insurance cover
packageDescriptionstringNoWhat is in the package, for example Shoes

Example request

curl -X POST "https://api.7feastr.com/api/v1/logistics/v1/rates/estimate" \
  -H "Authorization: Bearer $SEVENFEASTR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "serviceType": "consolidated",
    "packageWeightKg": 2,
    "pickupAddress": "14 Allen Avenue",
    "pickupCity": "Ikeja",
    "pickupState": "Lagos",
    "dropoffAddress": "8 Admiralty Way",
    "dropoffCity": "Lekki",
    "dropoffState": "Lagos",
    "declaredValue": 45000,
    "packageDescription": "Shoes"
  }'
// Node.js 18+ (run as an ES module, or inside an async function)
const BASE_URL = "https://api.7feastr.com/api/v1/logistics/v1";

const res = await fetch(`${BASE_URL}/rates/estimate`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SEVENFEASTR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    serviceType: "consolidated",
    packageWeightKg: 2,
    pickupAddress: "14 Allen Avenue",
    pickupCity: "Ikeja",
    pickupState: "Lagos",
    dropoffAddress: "8 Admiralty Way",
    dropoffCity: "Lekki",
    dropoffState: "Lagos",
    declaredValue: 45000,
    packageDescription: "Shoes",
  }),
});
const body = await res.json();
if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`);

const quote = body.data;
console.log(quote.quoteId, quote.pricing.total, quote.etaAt);
import os
import requests

BASE_URL = "https://api.7feastr.com/api/v1/logistics/v1"

res = requests.post(
    f"{BASE_URL}/rates/estimate",
    headers={"Authorization": f"Bearer {os.environ['SEVENFEASTR_API_KEY']}"},
    json={
        "serviceType": "consolidated",
        "packageWeightKg": 2,
        "pickupAddress": "14 Allen Avenue",
        "pickupCity": "Ikeja",
        "pickupState": "Lagos",
        "dropoffAddress": "8 Admiralty Way",
        "dropoffCity": "Lekki",
        "dropoffState": "Lagos",
        "declaredValue": 45000,
        "packageDescription": "Shoes",
    },
    timeout=30,
)
body = res.json()
if not body["success"]:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")

quote = body["data"]
print(quote["quoteId"], quote["pricing"]["total"], quote["etaAt"])

Example response

200 OK

JSON
{
  "success": true,
  "message": "OK",
  "sandbox": true,
  "data": {
    "quoteId": "QUOTE-9C41E07B2D5F4A18",
    "quoteExpiresAt": "2026-10-21T09:40:00.000Z",
    "tripType": "intrastate",
    "serviceType": "consolidated",
    "pickup": {
      "address": "14 Allen Ave, Ikeja, Lagos, Nigeria",
      "city": "Ikeja",
      "state": "Lagos",
      "lat": 6.6018,
      "lng": 3.3515
    },
    "dropoff": {
      "address": "8 Admiralty Way, Lekki Phase 1, Lagos, Nigeria",
      "city": "Lekki",
      "state": "Lagos",
      "lat": 6.4474,
      "lng": 3.4706
    },
    "distanceKm": 27.4,
    "packageWeightKg": 2,
    "declaredValue": 45000,
    "etaRawMinutes": 58,
    "etaBufferedMinutes": 1440,
    "etaDays": 1,
    "etaAt": "2026-10-22T09:30:00.000Z",
    "pricing": { "subtotal": 7900, "vatPercent": 7.5, "vatAmount": 592.5, "total": 8492.5 },
    "currency": "NGN"
  }
}

Response fields

FieldTypeDescription
quoteIdstringPass this to POST /shipments. Valid for 10 minutes, single use
quoteExpiresAtISO 8601 stringWhen the quote expires
tripTypestringintrastate (same state) or interstate
serviceTypestringThe service you asked for
pickup, dropoffobjectThe located address: address, city, state, lat, lng
distanceKmnumberDriving distance between the two addresses
packageWeightKgnumberThe weight you sent
declaredValuenumberThe declared value, when you sent one
etaRawMinutesnumberRaw driving time in minutes
etaBufferedMinutesnumberThe delivery promise in minutes (etaDays × 1,440)
etaDaysnumberDelivery time in whole days. See delivery times
etaAtISO 8601 stringEstimated delivery time
pricingobjectsubtotal, vatPercent, vatAmount and total in NGN. See Pricing
currencystringAlways NGN

Errors

HTTPerror.codeWhen
400invalid_requestA required field is missing, serviceType is not valid, or the weight is outside the limit for the service
401authentication_errorMissing, invalid or revoked API key
422unserviceableWe don't deliver to that state, or don't offer door service at that address yet. See Coverage
503service_unavailableAddress lookup or our delivery network is temporarily unavailable. Retry with backoff

Create a shipment

POST/shipments

Auth: API key. Creates the shipment, charges your wallet and books the pickup on our delivery network. Returns 201 Created.

Create it either with a quoteId (recommended: you are charged exactly the quoted price) or with the full address and package fields from POST /rates/estimate, in which case it is priced live at that moment.

Request headers

HeaderRequiredDescription
AuthorizationYesBearer <API key>
Content-TypeYesapplication/json
Idempotency-KeyNoAny unique string, such as your order ID. Repeating a request with the same key returns the original shipment and never charges twice

Request fields

FieldTypeRequiredDescription
quoteIdstringRecommendedA quote from POST /rates/estimate. Fixes the price, route, weight, service type and declared value
pickupContactNamestringYesPerson the rider collects from
pickupContactPhonestringYesNigerian phone number, for example 08031234567 or +2348031234567
pickupContactEmailstringYesEmail of the pickup contact
recipientNamestringYesPerson receiving the package
recipientPhonestringYesNigerian phone number of the recipient
recipientEmailstringYesEmail of the recipient
packageDescriptionstringNoWhat is in the package. Defaults to the description on the quote
brittleTierstringNoHow fragile the package is: low (default), medium or high
containsLiquidbooleanNotrue if the package contains liquid. Defaults to false
scheduledAtISO 8601 stringNoA future date and time for the pickup. Omit it to book the pickup straight away
serviceType, packageWeightKg, pickupAddress, pickupCity, pickupState, dropoffAddress, dropoffCity, dropoffStateWithout quoteIdSame as POST /rates/estimate. Required only when you don't send a quoteId
declaredValuenumberNoWithout quoteId only: value of the goods in NGN for insurance. With a quoteId, the quote's declared value is used

Example request

curl -X POST "https://api.7feastr.com/api/v1/logistics/v1/shipments" \
  -H "Authorization: Bearer $SEVENFEASTR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_48213" \
  -d '{
    "quoteId": "QUOTE-9C41E07B2D5F4A18",
    "pickupContactName": "Adaeze Okafor",
    "pickupContactPhone": "08031234567",
    "pickupContactEmail": "dispatch@adaezestores.ng",
    "recipientName": "Tunde Bakare",
    "recipientPhone": "+2348099876543",
    "recipientEmail": "tunde.bakare@example.com",
    "packageDescription": "Shoes",
    "brittleTier": "low",
    "containsLiquid": false
  }'
// Node.js 18+ (run as an ES module, or inside an async function)
const BASE_URL = "https://api.7feastr.com/api/v1/logistics/v1";

const res = await fetch(`${BASE_URL}/shipments`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SEVENFEASTR_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "order_48213",
  },
  body: JSON.stringify({
    quoteId: "QUOTE-9C41E07B2D5F4A18",
    pickupContactName: "Adaeze Okafor",
    pickupContactPhone: "08031234567",
    pickupContactEmail: "dispatch@adaezestores.ng",
    recipientName: "Tunde Bakare",
    recipientPhone: "+2348099876543",
    recipientEmail: "tunde.bakare@example.com",
    packageDescription: "Shoes",
    brittleTier: "low",
    containsLiquid: false,
  }),
});
const body = await res.json();
if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`);

const shipment = body.data;
console.log(shipment._id, shipment.trackingCode, shipment.price);
import os
import requests

BASE_URL = "https://api.7feastr.com/api/v1/logistics/v1"

res = requests.post(
    f"{BASE_URL}/shipments",
    headers={
        "Authorization": f"Bearer {os.environ['SEVENFEASTR_API_KEY']}",
        "Idempotency-Key": "order_48213",
    },
    json={
        "quoteId": "QUOTE-9C41E07B2D5F4A18",
        "pickupContactName": "Adaeze Okafor",
        "pickupContactPhone": "08031234567",
        "pickupContactEmail": "dispatch@adaezestores.ng",
        "recipientName": "Tunde Bakare",
        "recipientPhone": "+2348099876543",
        "recipientEmail": "tunde.bakare@example.com",
        "packageDescription": "Shoes",
        "brittleTier": "low",
        "containsLiquid": False,
    },
    timeout=30,
)
body = res.json()
if not body["success"]:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")

shipment = body["data"]
print(shipment["_id"], shipment["trackingCode"], shipment["price"])

Example response

201 Created

JSON
{
  "success": true,
  "message": "OK",
  "sandbox": true,
  "data": {
    "_id": "6716a3f2c9e77b0012a4d5e1",
    "trackingCode": "7F-20261021-4F91A2C8",
    "reference": "SHIP-9F3A1B2C4D5E6F70",
    "environment": "sandbox",
    "idempotencyKey": "order_48213",
    "status": "pending",
    "statusHistory": [{ "status": "pending", "at": "2026-10-21T09:32:10.000Z" }],
    "pickupContactName": "Adaeze Okafor",
    "pickupContactPhone": "08031234567",
    "pickupContactEmail": "dispatch@adaezestores.ng",
    "pickupAddress": "14 Allen Ave, Ikeja, Lagos, Nigeria",
    "pickupCity": "Ikeja",
    "pickupState": "Lagos",
    "pickupLat": 6.6018,
    "pickupLng": 3.3515,
    "recipientName": "Tunde Bakare",
    "recipientPhone": "+2348099876543",
    "recipientEmail": "tunde.bakare@example.com",
    "dropoffAddress": "8 Admiralty Way, Lekki Phase 1, Lagos, Nigeria",
    "dropoffCity": "Lekki",
    "dropoffState": "Lagos",
    "dropoffLat": 6.4474,
    "dropoffLng": 3.4706,
    "packageWeightKg": 2,
    "packageDescription": "Shoes",
    "declaredValue": 45000,
    "brittleTier": "low",
    "containsLiquid": false,
    "tripType": "intrastate",
    "serviceType": "consolidated",
    "deliveryType": "instant",
    "distanceKm": 27.4,
    "etaRawMinutes": 58,
    "etaBufferedMinutes": 1440,
    "etaAtOriginal": "2026-10-22T09:30:00.000Z",
    "etaAt": "2026-10-22T09:30:00.000Z",
    "subtotal": 7900,
    "vatPercent": 7.5,
    "vatAmount": 592.5,
    "price": 8492.5,
    "currency": "NGN",
    "isCharged": true,
    "isRefunded": false,
    "pickupBooked": true,
    "deliveryEvents": [{ "description": "Pickup booked", "at": "2026-10-21T09:32:11.000Z" }],
    "proofOfDeliveryAvailable": false,
    "createdAt": "2026-10-21T09:32:10.000Z",
    "updatedAt": "2026-10-21T09:32:11.000Z"
  }
}

Key response fields

FieldTypeDescription
_idstringThe shipment ID. Use it in /shipments/:id calls
trackingCodestringFormat 7F-YYYYMMDD-XXXXXXXX. Share it with your recipient for public tracking
referencestring7feastr's business reference for the transaction
statusstringStarts as pending. See statuses
deliveryTypestringinstant, or scheduled when you sent scheduledAt
subtotal, vatPercent, vatAmountnumberThe price breakdown, identical to the quote
pricenumberThe total charged to your wallet, identical to pricing.total on the quote
pickupBookedbooleantrue once the pickup is confirmed on our delivery network
deliveryEventsarrayDelivery progress as { description, at }, newest first
proofOfDeliveryAvailablebooleantrue when a delivery photo or signature can be downloaded

Errors

HTTPerror.codeWhen
400invalid_requestA required field is missing or invalid, the quote has expired or was already used ("This rate quote has expired or is invalid."), or scheduledAt is not in the future
401authentication_errorMissing, invalid or revoked API key
402insufficient_fundsYour wallet balance is lower than the total. Nothing is created. Fund your wallet and retry with the same quoteId while it is still valid
403permission_errorProduction is not enabled for your account yet
422unserviceableWithout quoteId: we don't deliver to that state or address yet
503service_unavailableOur delivery network is temporarily unavailable. Retry with backoff and the same Idempotency-Key, requesting a new quote if yours has expired

Idempotency

Network timeouts happen. To retry POST /shipments safely, send an Idempotency-Key header with a value that is unique to the order, such as your own order ID:

HTTP
Idempotency-Key: order_48213

If a request with the same key has already created a shipment in the same environment, the API returns that original shipment instead of creating a new one, and your wallet is not charged again. Keys are scoped to your account and environment.

Warning

A quoteId can only be used once. If you retry a request that may have succeeded, always send the same Idempotency-Key. A retry without it will fail with "This rate quote has expired or is invalid." once the first request has consumed the quote.

Scheduled pickups

Send scheduledAt as a future ISO 8601 date, for example "2026-10-23T08:00:00.000Z", to have the shipment picked up at that time. The shipment is created and charged straight away, with deliveryType: "scheduled". A date in the past returns 400 invalid_request.

List shipments

GET/shipments

Auth: API key. Returns your shipments in the key's environment, newest first.

Query parameterTypeRequiredDescription
pageintegerNoPage number, from 1. Default 1
limitintegerNoResults per page, 1 to 100. Default 20
statusstringNoOne of pending, assigned, picked_up, in_transit, delivered, failed, cancelled
fromISO 8601 stringNoOnly shipments created at or after this time
toISO 8601 stringNoOnly shipments created at or before this time
cURL
curl "https://api.7feastr.com/api/v1/logistics/v1/shipments?status=in_transit&page=1&limit=20" \
  -H "Authorization: Bearer $SEVENFEASTR_API_KEY"

200 OK. data is an array of shipment objects like the one above, and meta describes the page:

JSON
{
  "success": true,
  "message": "OK",
  "sandbox": true,
  "data": [
    {
      "_id": "6716a3f2c9e77b0012a4d5e1",
      "trackingCode": "7F-20261021-4F91A2C8",
      "status": "in_transit",
      "price": 8492.5,
      "currency": "NGN",
      "pickupBooked": true,
      "proofOfDeliveryAvailable": false,
      "createdAt": "2026-10-21T09:32:10.000Z"
    }
  ],
  "meta": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
}

The list item above is abridged. Each item has the same fields as GET /shipments/:id.

Errors: 400 invalid_request for an unknown status or an invalid from / to date, and 401 authentication_error.

Get a shipment

GET/shipments/:id

Auth: API key. Returns one shipment, with the same fields as the create response. Use the _id from the create response as :id.

cURL
curl "https://api.7feastr.com/api/v1/logistics/v1/shipments/6716a3f2c9e77b0012a4d5e1" \
  -H "Authorization: Bearer $SEVENFEASTR_API_KEY"

Errors: 404 not_found when the shipment doesn't exist, belongs to another merchant or to the other environment, and 401 authentication_error.

To follow a shipment after it is created, see Tracking.

PreviousPricingNext Tracking

On this page

  • Service types
  • Get a quote
  • Request fields
  • Example request
  • Example response
  • Response fields
  • Errors
  • Create a shipment
  • Request headers
  • Request fields
  • Example request
  • Example response
  • Key response fields
  • Errors
  • Idempotency
  • Scheduled pickups
  • List shipments
  • Get a shipment