Run a day of deliveries
From first sign-in to a reconciled cash shift. Written for the person in the dispatcher seat.
Getting started
You need a browser for the dispatcher console and, for each courier, a phone with the courier app. Store builds of the app are not published yet.
- 1
Open the console
Use the Open live demo button or go to the console address your deployment uses.
- 2
Sign up or sign in
A service signs itself up: name, phone, first warehouse and your email. A sign-in link arrives by email and works for 15 minutes. Whoever signs the service up becomes its owner.
- 3
Read the map
Each courier has one line colour everywhere: on the map, in lists and in plans. A short label beside the name shows whether they are on shift, on break or off shift.
Team and roles
A service has three roles. The owner runs the company: team, warehouses, the recipient page and the plan. The dispatcher runs the day. The courier works in the app. One person can belong to several services and switch between them.
- 1
Invite people
Open Company, then Team, and press Invite. Choose a role and enter a name. The console gives you a link to copy. If you add an email address, the link is emailed too.
- 2
Hand over the app
The courier opens the link on their phone. The app accepts the invitation, shows the service name, and explains why location is needed before the phone asks for permission.
- 3
Disable when needed
A disabled member cannot sign in, and a disabled courier cannot be assigned orders. A courier who lost access can get a new sign-in link from the same menu.
Create an order with a pin
The pin is what routing uses. The address text is for people.
- 1
Start a new order
Enter the recipient’s name and phone number.
- 2
Place the pin
Click the map where the parcel goes. Pins must sit inside Armenia; the API refuses coordinates outside it.
- 3
Label the address
Armenian is required. Russian and English are optional but make the courier and tracking screens read naturally in each language.
- 4
Add cash or a code
For cash on delivery, switch it on and set the amount in AMD. To require a one-time delivery code, switch that on; the recipient reads it from their tracking link.
- 5
Save and mark ready
An order moves draft, ready, assigned, picked up, arrived, delivered. A failed delivery returns to the dispatcher, who can put it back in the queue.
Assign or optimise
Assign by hand for one order, or ask for a plan for many.
- 1
Assign one order
Pick a ready order and an active courier. Reassigning cancels the previous assignment and records both events.
- 2
Request a plan
Select orders and couriers and ask the optimiser for a suggestion. It proposes a sequence of stops per courier.
- 3
Review and edit
The suggestion is not guaranteed optimal. Move stops between couriers, change the order, re-optimise what is left.
- 4
Apply once
Applying assigns every stop in the accepted sequence or changes nothing. If an order moved on while you were reviewing, the plan is refused as stale.
Share a tracking link
Give the recipient a page of their own, with nothing they should not see.
- 1
Create the link
Open the order and copy its tracking link. Send it by any channel you already use.
- 2
What they see
Status, ETA, a coarse courier position, the time of the last update and, if required, the delivery code to read to the courier.
- 3
What they never see
Other stops, route history or an internal order number. The courier’s phone shows only if the owner turns it on in the recipient page settings.
- 4
Revoke at any time
Revoking takes effect immediately. A new link replaces the old one. Links also expire after delivery.
Courier app basics
What to tell a courier on their first morning.
- 1
Start the shift
Tap start on the shift card. Location is only collected on shift; break pauses it and end stops it.
- 2
Work the run
Stops are listed in the planned order. Tap one to see where to go and open navigation in one tap.
- 3
Mark progress
Picked up, arrived, then delivered. If delivery fails, choose a reason: recipient absent, refused, wrong address or other.
- 4
Record proof
Take a photo, enter who received the parcel, or ask for the one-time code when the order requires it.
- 5
Lose signal safely
Changes wait on the phone and send automatically when signal returns. The status bar shows how many are queued.
Cash on delivery and reconciliation
Cash is counted at the door and settled at the end of the shift.
- 1
Collect at the door
On a cash order the app shows the amount due and prefills what was collected, with change worked out.
- 2
Track what is held
The courier’s home screen shows a running total still to hand over. The dispatcher sees the same figure per courier.
- 3
Hand over
At the end of the shift the courier taps hand over cash. The balance shows as awaiting confirmation.
- 4
Confirm receipt
The dispatcher confirms in the cash reconciliation panel. The balance returns to zero.
API overview
Everything the console and the apps do goes through one HTTP API. Requests carry a bearer token from POST /auth/login or a sign-in link; refresh tokens rotate on use. Every request works within the user’s active company. Errors are small JSON problem objects with a type, title and status.
| Area | Main endpoints |
|---|---|
| Authentication | /auth/signup, /auth/login, /auth/magic-link, /auth/refresh, /auth/logout, /auth/switch-company, /me |
| Company and team | /company, /company/depots, /company/members, /company/invites, /company/billing, /auth/invite/accept |
| Orders | /orders, /orders/{id}, /orders/{id}/status, /orders/{id}/events, /orders/{id}/notify-late |
| Assignment and plans | /orders/{id}/assign, /plans/recompute, /plans/move-stop, /plans/apply, /geo/optimize |
| Couriers | /couriers, /couriers/{id}, /couriers/{id}/eta, /courier/me, /courier/shift/start|break|end |
| Courier work | /courier/orders, /courier/orders/{id}/status, /courier/location |
| Cash and earnings | /courier/cash, /cash/settlements, /courier/earnings, /courier/history |
| Recipient tracking | /orders/{id}/tracking, /track/{token}, /track/{token}/rating |
| Live events | /events (server-sent events), /events/latest-cursor |
| Geo | /geo/route, /geo/matrix, /geo/optimize, /healthz |
Geo endpoints are for signed-in dispatchers and couriers only; the public tracking page computes its own ETA on the server.
Running it yourself
One deployment serves many services. Each sees only its own orders, couriers and settings.
- 1
Check health
GET /healthzanswers 200 when routing, optimisation, the database and tiles are up, and 503 with the failing part named when they are not. - 2
Keep the map fresh
Refresh OpenStreetMap data weekly; one command downloads, rebuilds the routing graph and smoke-tests a route.
- 3
Back up and drill
Nightly database backups are verified when written. Run the restore drill after schema changes and monthly.
- 4
Set retention
Location history and dead tracking tokens are pruned on a schedule. The defaults are placeholders until counsel sets the real periods.
The full runbook is OPERATIONS.md in the repository.