Kilo Docs

Docs / Deliveries/ Assign riders

Assign riders

Updated Aug 17, 2026

Same as the dashboard Assign rider button. Your server picks a rider. Kilo does not invent extra limits.

Who appears on GET /riders

Only riders who accepted the fleet invite. Pending invites are never listed and cannot be assigned. There is no query flag for this — Kilo enforces it.

Everyone in the response can take a job.

One rider, many jobs — yes

A rider can be on more than one delivery at the same time. That already works in the dashboard. The API is the same.

POST /assign does not reject a rider because they are on_delivery or active_delivery_count is 2. Stacking is allowed.

Do not skip assignment just because everyone is busy. If you leave the job with no rider, it will not move.

What pickup_lat / pickup_lng do (read this)

They do not hide riders. They measure.

When you send pickup coordinates:

  1. Each rider with GPS gets distance_km (straight line to that pickup).
  2. The list is sorted closer first.
  3. Riders with no GPS stay in the list (distance_km: null).

So: GET /riders?pickup_lat=6.45&pickup_lng=3.40 means “show my accepted fleet, tell me who is closer.” It does not mean “only people inside a circle.”

Optional filters

There is no default radius and no default idle filter. We never drop far or busy riders unless you ask.

Query What it does Default
pickup_lat + pickup_lng Fill distance_km and sort closer first. Does not hide anyone no distances
radius_km Hide riders whose known distance is greater than this. Needs pickup coords. Riders with unknown GPS are kept. no cutoff
idle_only=true Hide anyone not idle in the app — including riders already on a job keep busy riders
  • Omit radius_km (normal): everyone stays. You pick using distance_km.
  • Pass radius_km=8 only if you really want a cutoff. Most fleets should omit it so someone still gets the job.
  • Do not add idle_only=true unless you only want free riders and you accept that the job may stay pending.

Baby steps for an agent

  1. Listen for webhook delivery.created.
  2. If data.object.rider_assigned is already true, stop (someone else assigned).
  3. Call:
curl -X GET 'https://business.kiloapp.org/api/v1/riders?pickup_lat={pickup.latitude}&pickup_lng={pickup.longitude}' \
  -H 'Authorization: Bearer sk_live_...'
  1. Look at the array. First rows are closer (when GPS exists).
  2. Pick one rider. Prefer smallest distance_km. A rider with presence: "on_delivery" is still OK.
  3. Assign:
curl -X POST 'https://business.kiloapp.org/api/v1/deliveries/{deliveryId}/assign' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer sk_live_...' \
  -d '{
  "riderId": "the rider id from step 5"
}'

Use the rider’s id from this list. Do not invent ids. Do not use a user id from somewhere else.

List riders (all query params)

curl -X GET 'https://business.kiloapp.org/api/v1/riders?pickup_lat=6.4474&pickup_lng=3.4721' \
  -H 'Authorization: Bearer sk_live_...'

Scope: deliveries:read

Each rider includes:

Field Meaning
id Send this as riderId on assign
name / vehicle_type Display
presence available (idle in app), on_delivery (already has a job — still OK to assign), unavailable, not_in_app
active_delivery_count How many in-progress jobs they already have. More than 0 is OK
location Last GPS if we have it (fresh = updated in the last 30 minutes)
distance_km km to the pickup you passed, or null if we have no GPS

Assign

curl -X POST 'https://business.kiloapp.org/api/v1/deliveries/{deliveryId}/assign' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer sk_live_...' \
  -d '{
  "riderId": "uuid-from-get-riders"
}'

Scope: deliveries:write

The only Kilo rules (same as the dashboard):

  • Delivery status is awaiting_price, pending, or matched (before pickup starts).
  • Delivery fee is already set (greater than zero).
  • riderId is on this fleet and they accepted the invite.

Kilo does not check “are they free?” You can assign a busy rider.

Success: delivery status is matched, rider_assigned is true, rider has id / name / vehicle_type. Then webhook delivery.status_changed.

Need exact request or response shapes?

Errors

HTTP code When
400 validation_error Missing / invalid riderId
400 assign_not_allowed Pickup already started
400 fee_required No delivery fee yet
400 rider_not_found Id is not on this fleet
400 rider_not_active Invite not accepted
404 not_found Delivery missing

Unassign

curl -X POST 'https://business.kiloapp.org/api/v1/deliveries/{deliveryId}/unassign' \
  -H 'Authorization: Bearer sk_live_...'

Only while status is still matched (before pickup). Status goes back to pending (or awaiting_price if there is no fee).