Skip to main content

Operatives and dispatch

Operatives​

  • GET /v1/operatives lists everyone, with app status, invite time and photo URL.
  • POST /v1/operatives with { name, email?, phone?, trackingLicence?, sendInvite? } adds someone. sendInvite: true emails the Tracker app invite (needs email). Past the plan's active operatives you get 402 operative_limit.
  • PATCH /v1/operatives/{id} changes details, the background-tracking licence, or active. Reactivating counts towards the limit again.
  • POST /v1/operatives/{id}/invite sends or resends the invite, valid for 7 days.
  • POST /v1/operatives/{id}/pairing-code returns a code to type into the app, valid for 24 hours.
  • POST /v1/operatives/{id}/sign-out-devices signs them out of every phone.

Photos​

curl -X PUT "$TRACKER/v1/operatives/opv_…/photo" \
-H "Authorization: Bearer $TRACKER_KEY" \
-H "Content-Type: image/jpeg" \
--data-binary @sam.jpg

Send the image itself: JPEG, PNG or WebP, under 1 MB. Anything else gets 415 photo_type, and larger files 413 photo_too_large. Send a square crop at about 480 px with location and camera details removed; the admin does this in the browser before uploading. DELETE the same path to remove it.

Customers only see the photo while that operative is on the way to them or has arrived.

Dispatch​

  • GET /v1/dispatch?date=2026-11-02 returns the day's board: a lane per active operative, plus the unassigned lane, each with its visits in order.
  • PUT /v1/dispatch/2026-11-02 with the lanes you're changing, each listing its visits in order:
{
"lanes": [
{ "operativeId": "opv_sam", "journeyIds": ["jrn_a", "jrn_b"] },
{ "operativeId": null, "journeyIds": ["jrn_c"] }
]
}

operativeId: null is the unassigned lane. A visit can only be in one lane (400 duplicate_visit). Lanes you leave out don't change. The response is the updated board, and customers see their operative's new name straight away.