Skip to content
Deliveree
Preview · API v1 draft

Plug courier delivery
into your ordering.

A switch in Boom Online Ordering, a REST API for any other ordering system, or a partner key for agencies. The API below is a draft: read it, build against it, tell us what’s missing.

On this page

Ways to integrate

Three ways in, depending on who you are. All three end the same way: the cheapest quote is booked and the guest tracks the courier.

Coming

Boom Online Ordering

One switch in your BOO settings. No code, no keys: delivery orders go out for quotes as they are placed, and guests track the driver on your ordering page.

Request early access →
Preview

Any ordering system

A REST API: ask for quotes, book one, cancel if you need to, and follow every delivery by webhook. One key per merchant.

Read the draft ↓
Early access

Agencies

A partner key that can act for each of the restaurants you manage, with one statement a month. For agencies who resell Deliveree.

See the partner program →

API v1 draft

Preview — API v1 draft, subject to change. The API is in development and not open yet. Field names, responses and events may change before launch. Request API access to hear when they do.

Overview

  • Base URL (draft): https://deliveree.online/api/v1
  • JSON request and response bodies; send Content-Type: application/json.
  • Money is an integer number of cents (value_cents, fee_cents, tip_cents).
  • Times are ISO 8601 in UTC, e.g. 2026-09-22T18:30:00Z.
  • ETAs come from the courier networks and are estimates, not promises.
  • Values in the examples are made up. They are not prices.

The flow is always the same: quote a trip, book one of the options, then follow it by webhook (or poll it).

Authentication

Every request carries a secret key in the Authorization header:

Header
Authorization: Bearer dlv_live_…
  • Live keys start dlv_live_. Test keys start dlv_test_: use them while you build. No courier is sent and nothing is billed on a test key.
  • One key per merchant (per restaurant). A request made with a merchant key acts for that merchant only.
  • Agencies get a partner key that can act for each of their merchants. How a request names the merchant it is for is not settled in this draft.
  • Keys are secrets. Keep them on your server, never in a browser or an app bundle.

Get quotes

POST/api/v1/quotes

Ask the courier networks what a trip would cost. The response lists every option that came back and names the cheapest.

POST /api/v1/quotes request body
FieldTypeDescription
pickupobjectWhere the courier collects the order: name, address, phone; optional lat, lng and ready_at (when the food will be ready).
dropoffobjectWhere it goes: name, address, phone; optional lat, lng and notes for the courier.
orderobjectvalue_cents (the order total) and items, a list of { name, quantity }.
tip_centsoptionalintegerCourier tip, in cents.
curl https://deliveree.online/api/v1/quotes \
  -H "Authorization: Bearer $DELIVEREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pickup": {
      "name": "Luna Pizza",
      "address": "120 Main St, Tampa, FL 33602",
      "phone": "+18135550142",
      "ready_at": "2026-09-22T18:30:00Z"
    },
    "dropoff": {
      "name": "Sam Rivera",
      "address": "845 Bayshore Blvd, Apt 4B, Tampa, FL 33606",
      "phone": "+18135550199",
      "notes": "Buzz 4B"
    },
    "order": {
      "value_cents": 4250,
      "items": [
        { "name": "Large Margherita", "quantity": 1 },
        { "name": "Garlic Knots", "quantity": 2 }
      ]
    },
    "tip_cents": 500
  }'
POST /api/v1/quotes response
FieldTypeDescription
quote_idstringPass this to Book a delivery.
expires_attimestampBook before this time, or ask for a new quote.
optionsarrayOne entry per network that quoted: network, fee_cents, pickup_eta, dropoff_eta.
cheapeststringThe network of the lowest-fee option.
Response · 200
{
  "quote_id": "qt_8Hc2kPz4",
  "expires_at": "2026-09-22T18:10:00Z",
  "options": [
    {
      "network": "doordash",
      "fee_cents": 1000,
      "pickup_eta": "2026-09-22T18:31:00Z",
      "dropoff_eta": "2026-09-22T18:52:00Z"
    },
    {
      "network": "uber",
      "fee_cents": 1100,
      "pickup_eta": "2026-09-22T18:34:00Z",
      "dropoff_eta": "2026-09-22T18:50:00Z"
    }
  ],
  "cheapest": "doordash"
}

Book a delivery

POST/api/v1/deliveries

Book one of the options from a quote. Deliveree picks the option by strategy.

POST /api/v1/deliveries request body
FieldTypeDescription
quote_idstringFrom Get quotes. Must not have expired.
external_idstringYour own order id, echoed back on the delivery and its webhooks.
strategy"cheapest" | "fastest"cheapest books the lowest fee_cents; fastest books the earliest dropoff_eta.
tip_centsoptionalintegerCourier tip, in cents, if different from the one sent with the quote.
curl https://deliveree.online/api/v1/deliveries \
  -H "Authorization: Bearer $DELIVEREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "quote_id": "qt_8Hc2kPz4",
    "external_id": "order_1042",
    "strategy": "cheapest",
    "tip_cents": 500
  }'
Delivery object
FieldTypeDescription
idstringThe delivery id.
statusstringSee Statuses. Starts at pending.
networkstringThe courier network that was booked.
fee_centsintegerThe fee for the booked option, in cents.
tracking_urlstringA page you can send the guest to follow the delivery. Prefer your own page? Build it from the webhooks, including courier.location.
Response · 200
{
  "id": "del_7Qm3Xw9A",
  "status": "pending",
  "network": "doordash",
  "fee_cents": 1000,
  "tracking_url": "https://deliveree.online/t/del_7Qm3Xw9A"
}

Retrieve a delivery

GET/api/v1/deliveries/{id}

Returns the delivery object with its current status. Webhooks are the better way to follow a delivery; use this to check one on demand.

curl https://deliveree.online/api/v1/deliveries/del_7Qm3Xw9A \
  -H "Authorization: Bearer $DELIVEREE_API_KEY"

Cancel a delivery

POST/api/v1/deliveries/{id}/cancel

Asks the courier network to cancel. Returns the delivery object; its status is canceled if the cancel went through.

curl -X POST https://deliveree.online/api/v1/deliveries/del_7Qm3Xw9A/cancel \
  -H "Authorization: Bearer $DELIVEREE_API_KEY"

Statuses

Every delivery follows this flow and ends in one of three final states.

Delivery statuses
FieldTypeDescription
pendingstatusBooked with the network; no courier yet.
courier_assignedstatusA courier has accepted the trip.
picked_upstatusThe courier has the order.
deliveredfinalHanded over at the drop-off.
canceledfinalCanceled before it was delivered.
failedfinalThe network could not complete it.

Webhooks

Give us an HTTPS URL and Deliveree will POST an event to it each time a delivery changes. Each event carries its type and the delivery it is about.

Webhook events
FieldTypeDescription
delivery.createdeventA delivery was booked.
delivery.courier_assignedeventA courier accepted it.
delivery.picked_upeventThe courier collected the order.
delivery.deliveredeventIt was handed over.
delivery.canceledeventIt was canceled.
delivery.failedeventThe network could not complete it.
courier.locationeventThe courier’s position while the delivery is under way.
POST /webhooks/deliveree HTTP/1.1
Content-Type: application/json
Deliveree-Signature: t=1790101992,v1=<hex HMAC-SHA256 of "1790101992.<raw body>">

Verify signatures

Every webhook carries a Deliveree-Signature header of the form t=<unix>,v1=<hex>. v1 is the hex HMAC-SHA256 of the string t.body (the timestamp, a full stop, then the raw request body) keyed with your signing secret.

  • Compute the HMAC over the raw body, before any JSON parsing.
  • Compare in constant time, and reject old timestamps so a captured request cannot be replayed.
  • Answer with any 2xx once you have stored the event.
import crypto from 'node:crypto'

const TOLERANCE_SECONDS = 300 // reject anything signed more than 5 minutes ago

/**
 * rawBody: the request body exactly as received (a string), before JSON.parse.
 * header:  the Deliveree-Signature header, e.g. "t=1790101992,v1=5f2c…"
 * secret:  your webhook signing secret.
 */
export function verifyDelivereeSignature(rawBody, header, secret) {
  const parts = {}
  for (const piece of String(header || '').split(',')) {
    const i = piece.indexOf('=')
    if (i > 0) parts[piece.slice(0, i).trim()] = piece.slice(i + 1).trim()
  }
  const t = Number(parts.t)
  if (!Number.isInteger(t) || !parts.v1) return false
  if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_SECONDS) return false

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex')

  const a = Buffer.from(expected, 'hex')
  const b = Buffer.from(parts.v1, 'hex')
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Not settled yet

This draft deliberately leaves these open. Tell us what you need.

  • The error response format and error codes.
  • Rate limits.
  • How a partner key names the merchant a request is for.
  • Whether fee_cents includes the dispatch fee or it is billed separately.
  • How long a quote lasts, and whether booking the same external_id twice is safe.
  • Whether a cancel after pickup is possible, and what the network charges for it.
  • Webhook retries, and the order events arrive in.

Get access

Nothing here is self-serve yet. If you run an ordering platform and want to build against the draft, or you are a Boom Online Ordering restaurant waiting for the switch, email us and say which.

Request API accessAgencies: apply as a partner →
Deliveree

Delivery dispatch for restaurants, built by Boom Media. Early access, starting with Boom Online Ordering restaurants.

DoorDash and Uber are trademarks of their respective owners. Deliveree is not affiliated with or endorsed by them.