On-demand delivery: what the platform has to handle

· 6 min read

On-demand delivery: what the platform has to handle

In short

An on-demand delivery platform has to build the plan after the day has already started. Every new order invalidates the plan from thirty seconds ago, so three things carry the whole operation: assignment speed, honest ETAs, and a defined answer for when nobody accepts the job.

  • Scheduled delivery is a planning problem solved the night before. On-demand is a re-planning problem solved continuously, all day.
  • The number that governs everything else is assignment lag:
Assignment lag = time a named person accepted the job
                 - time the order arrived
  • Aim for assignment lag in seconds. Past roughly two minutes, the ETA you showed the customer was already wrong before anyone moved.
  • "Nobody accepted it" is not an edge case, it is a daily event. The platform needs a written escalation ladder: widen the radius, then push to the office, then tell the customer, each on a timer.
  • An ETA that is a straight-line distance estimate will be wrong by the time it matters. It has to include the unassigned wait, the current task in hand, and the time spent at the door.

The difference that changes the software

With scheduled routes, you have a quiet hour the night before. You can look at 140 stops, argue about two of them, and print the manifests. The plan is a document.

On-demand has no quiet hour. An order lands at 11:42 and somebody has to be moving towards it by 11:43. The plan is never a document, it is a running state that is wrong again the moment you look away. Route planning and dispatch are genuinely different jobs, and on-demand work is almost entirely the second one.

That means most of what a routing tool is good at, optimising a fixed set of stops, matters less than you would think. What matters is how the system behaves in the ninety seconds after a new order appears, and in the ninety seconds after something breaks.

The five moments an on-demand delivery platform has to handle

Here are the moments that actually break, in the order they happen.

1. The order arrives and has to become a job. Not a row in a queue. A job with an address that has been checked, a time promise attached, and a named person responsible for it. If the order sits in a queue waiting for a human to look at it, your assignment lag is however long it takes somebody to look up from what they were doing.

What the platform must do: validate the address on arrival, flag the ones it cannot geocode cleanly, and start the assignment clock immediately so the delay is visible rather than invisible.

2. The job has to find the right person, not the nearest person. Nearest is a tempting default and it is wrong often enough to hurt. The nearest rider may be forty minutes into a run going the other way, may not have the right vehicle for a 40kg item, may not carry the cold bag, may be six minutes from the end of their shift.

What the platform must do: score on nearest-after-current-commitments, plus hard filters for vehicle, capacity, skill and shift end. A suggestion that ignores the shift end is how you end up paying overtime you did not plan.

3. Somebody has to accept it. This is where the honest platforms and the demo-ware separate. Assignment is not completion of the job handover. Acceptance is. Until a named person has tapped accept, the job is unowned, and an unowned job with an ETA on it is a promise nobody made.

What the platform must do: show unaccepted jobs as a distinct state with a visible timer, not mixed in with assigned work.

4. Nobody accepts it. On a wet Friday evening, offers get declined. If your process for this is "the dispatcher notices eventually", then on your busiest day it fails worst, because that is the day nobody is watching one job.

What the platform must do: an automatic ladder with timers you set. For example: re-offer inside the first radius for 60 seconds, widen the radius for the next 90, then raise it to the office as an alert, then release the customer-facing ETA and send a revised one. Every step on a clock, so nothing waits on attention.

5. The plan changes mid-route. The driver is at a door that will not open. A better-placed rider has just gone free. A customer has moved their slot. Each of these is a re-plan of everything downstream.

What the platform must do: make the change in one action with the knock-on effects shown before you commit. A reassignment that silently moves four other stops into the next hour is worse than no reassignment.

Honest ETAs, and why most of them are not

Most ETAs are built from distance and an assumed speed. That estimate is missing the two biggest components of the actual wait.

The first is the unassigned gap, meaning the time between the order arriving and somebody accepting it. If that averages four minutes at lunch and you do not include it, every lunchtime ETA is four minutes optimistic before the vehicle has turned a wheel.

The second is dwell time: the minutes at the door. Finding the entrance, the lift, the code, the person. For some kinds of delivery this is the single largest line item in the journey and it is almost never modelled, because getting to the address is solved and getting inside is not.

A workable ETA looks like this:

Customer ETA = expected assignment wait
             + remaining time on the courier's current job
             + travel time
             + dwell time for this address type
             + a buffer you publish and keep

There is no credible public benchmark for dwell time by building type, and anyone quoting you one has made it up. You can measure your own in two weeks: the field app already knows the arrival timestamp and the completion timestamp, and the gap between them is the answer. Split it by apartment block, house, office reception and retail back door, and you will usually find they differ by more than you would have guessed.

One rule worth holding to: show a range you will keep rather than a precise time you will miss. "Between 2:10 and 2:30" that lands at 2:24 reads as accurate. "2:15" that lands at 2:24 reads as late by nine minutes, for the same delivery.

A test you can run this week

Pick ten orders from your busiest hour and reconstruct the timeline from your own logs. For each one, write down four timestamps: order received, job assigned, job accepted, job completed. Then work out three gaps.

  • Order to assigned. If this is more than a few seconds, something human is in the loop that should not be.
  • Assigned to accepted. This is your acceptance friction. If it is routinely over a minute, the offers are going to the wrong people, or the app is not getting their attention.
  • Accepted to completed versus the ETA you showed. The sign of the error matters more than the size. Consistently late by a steady amount is a modelling gap you can fix today by adding dwell and assignment wait. Randomly late in both directions means the plan is being rebuilt by hand and nobody can see the whole board.

Then count, for the same hour, how many jobs were offered and declined at least once. That count is the honest size of your no-accept problem, and most operations have never measured it.

OkPilot handles the on-demand case by letting the office type the instruction — reassign these three stops, widen the offer radius after a minute — and approving the suggestion before anything moves; it will not reassign a job or message a customer on its own. If you want the mechanics of the dispatch side, the delivery management and courier management pages go into it.

See OkPilot running your own operation

A live walkthrough with a real person, configured to your jobs on the call. About ten minutes. Setup takes around 48 hours.

No commitment. We will reach out within one business day.

← All posts