Driver API

Driver availability, location, trip states and payout settings.

Interactive test consolePaste a dedicated development token below. It stays in this browser tab and is sent only to the API endpoint you test.
Fixed playground responses

These are saved Chromium captures for Onboard Driver · CRZ-ZZZ-0001 · captured 2026-08-28. They remain visible before testing. Paste a bearer token to replace safe GET responses with the current authenticated user's live data; mutations still require an explicit request.

Live Socket events - no polling for rides, notifications or chat

Connect once after authentication and keep the connection for the full app session. Socket events are the immediate UI signal; REST is only the recovery path after reconnect.

StepWhat the app should do
When to connectAfter driver authentication, keep one socket connection alive for the app session.
Immediate useUse socket events for offers, trip updates and chat. Do not poll while connected.
Recovery fetchGET /driver/offers, GET /driver/trips/active, GET /driver/messages and GET /driver/trips/:id/rider-location once after reconnect or app resume.
Trip roomAfter the driver has a trip context, subscribe with socket.emit('trip:subscribe', { tripId }).
Connection pattern
const socket = io(BASE_URL, {
  transports: ['websocket'],
  auth: { token: accessToken }
});

socket.on('connect', () => setRealtimeConnected(true));
socket.on('disconnect', () => setRealtimeConnected(false));
socket.on('connect_error', showRealtimeError);
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
socket.on('${event}', (payload) => onRealtimeEvent('${event}', payload));
Live event contract
EventImportant payloadRender immediately
driver:trip_offertripId, offer.id, expiresAtMANUAL: open accept/decline. AUTO: wait for trip:state_updated confirmation; do not show a decision UI.
driver:trip_offer_expiredtripId, offerId, reasonClose the offer immediately and mark it expired.
driver:trip_offer_retractedtripId, offerId, reasonClose the offer: the rider cancelled matching or another driver accepted.
trip:state_updatedtripId, status, tripRender the confirmed automatic/manual assignment and newest trip state.
rider:location_updatedtripId, location.latitude, location.longitude, location.recordedAtMove the rider marker before pickup only.
rider:location_stoppedtripIdRemove the moving-rider marker and retain the booked pickup pin.
message:receivedtrip_id, body, created_atAppend the chat message immediately.
call:incomingcallId, tripId, status, version, expiresAtOpen the incoming-call screen and offer Accept or Decline.
call:state_changedcallId, tripId, status, versionRender CONNECTING or ACTIVE; request your own join token after acceptance.
call:endedcallId, tripId, status, endedAt, versionDisconnect LiveKit and close the call screen.
Reconnect recovery

Make the recovery fetches only on the first reconnect after a disconnect or app resume. Merge that server state into local state, then keep rendering live socket events.

Token lifecycle: disconnect on sign-out. If the access token expires, refresh it and reconnect with the new token.

Driver-rider voice calls (LiveKit)

Use REST for decisions and recovery, Socket.IO for ringing/state events, and LiveKit for microphone audio. There is no SSE endpoint. Calls are available only when LIVEKIT_ENABLED=true and the trip has the authenticated rider plus its currently assigned driver.

ConnectionEndpoint / eventFrontend action
Backend RESTPOST /api/v1/trips/:id/callsCaller starts; show RINGING until the answer deadline. Send a fresh Idempotency-Key.
Socket.IOio(BASE_URL, { auth: { token: accessToken }, transports: ['websocket'] })Connect after login; the server joins your private user room automatically. Do not emit a call-start socket action.
Socket.IOcall:incomingRecipient opens incoming-call UI and calls accept or decline REST endpoint before expiresAt.
Socket.IOcall:state_changedOn CONNECTING, both apps request their own join-token. On ACTIVE, show the in-call state.
LiveKit WebRTCroom.connect(data.serverUrl, data.token)Connect directly to LiveKit and enable microphone; use LiveKit connection/track events for actual audio status, mute and speaker controls.
Socket.IOcall:endedStop microphone, disconnect the LiveKit room and close the call UI.
REST recoveryGET /api/v1/trips/:id/calls/activeFetch after reconnect/app resume; a null response means no active call.

Payload: events carry { callId, tripId, status, version, callerUserId, recipientUserId, expiresAt, acceptedAt, activeAt, endedAt, createdAt } where IDs are public-prefixed. Ignore events with an older version for the same call. The join-token response alone contains serverUrl, token, identity and expiresAt; never log or persist the token.

Ringing deadline: the backend uses a 120-second default. The caller may request ringTimeoutSeconds from 10 to 300 when starting a call; render the authoritative backend-provided expiresAt countdown. The frontend cannot extend an already-created call.

Flow: start → call:incoming → accept → call:state_changed CONNECTING → both join-token requests → both LiveKit connects → verified webhook sets ACTIVE → either end → call:ended. Decline, the expiresAt timeout, a terminal trip or 60-minute maximum closes the call. A backgrounded app needs registered Expo push notifications plus a recovery GET when it opens; a socket alone cannot wake it reliably.

Setup: mobile apps install their LiveKit platform SDK, request microphone permission, configure native audio routing/background behavior and keep the token only in memory. Backend needs LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, an applied Prisma migration, and the signed LiveKit webhook configured at /api/v1/livekit/webhook. Server credentials never go into the app.

Frontend integration guide

Use the endpoint cards below as the source of truth for request methods, authentication and test payloads. Keep credentials in secure storage and send bearer tokens only over HTTPS.

Required availability order
  1. POST /api/v1/driver/location with current GPS. Location freshness is checked by readiness.
  2. PATCH /api/v1/driver/dispatch-preferences. Manual without a range: {"offerMode":"MANUAL","usePickupRadius":false}. Range-bound auto-accept: {"offerMode":"AUTO","usePickupRadius":true,"pickupRadiusKm":10}.
  3. GET /api/v1/driver/readiness; show and resolve every blocker.
  4. PATCH /api/v1/driver/status with {"status":"ONLINE"}.
  5. Connect Socket.IO for the entire app session, then render offers and trip changes from events.

Auto-accept rule: it is disabled by default and never unbounded. The driver sets the pickup range themselves. Enabling AUTO without an enabled range returns 409 AUTO_ACCEPT_REQUIRES_PICKUP_RANGE. To turn the range off, switch to MANUAL in the same update. The server, not the app timer, decides eligibility and acceptance.

Live activity: connect Socket.IO with auth.token = accessToken. In MANUAL mode, treat driver:trip_offer as an interrupting offer, fetch GET /driver/offers for display/recovery details, and count down to expiresAt; then call POST /driver/offers/:id/respond. In AUTO mode, render trip:state_updated as the confirmation that the range-qualified offer was assigned. Handle driver:trip_offer_expired, driver:trip_offer_retracted and message:received. After every reconnect, refetch active offers, active trips and messages.

Mutating requests should include a unique Idempotency-Key. Render API status and error codes explicitly, and refetch state after reconnecting.

REST response contract

Every response is JSON: { success, data, error }. When success is true, read data. When it is false, use error.code for app logic and error.message for safe UI text.

HTTPMeaningFrontend action
200Request succeeded.Render data.
201Resource created.Persist its returned ID/state.
202Accepted for asynchronous work.Show pending; it is not authentication.
400Invalid request or business rule.Show error.message and field details.
401Token missing, expired or invalid.Refresh session or sign in.
403Access denied.Do not retry.
404Unavailable or hidden resource.Return safely and refresh state.
409State conflict/duplicate/expired resource.Refetch; do not blindly retry.
422Semantically invalid input.Highlight the field.
429Rate limited.Back off, respecting Retry-After.
500Unexpected server failure.Offer a safe retry.

Stable codes: VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, TRIP_ACCESS_DENIED, RIDER_ACTION_RATE_LIMITED and OTP_RATE_LIMITED. Each endpoint guide adds any relevant business codes.

Money and JSON format

All NGN monetary fields ending in Minor are expressed in kobo, not naira. For example, 246500 means NGN 2,465; divide by 100 for display. JSON body editors are automatically pretty-printed when valid JSON is entered.

POST/api/v1/auth/driver/onboarding/otp/request
Public

Request first-time driver OTP

Endpoint guide What to send, parse and expect

Why it exists

Starts first-time driver identity verification with the fleet-issued assigned ID.

Before you call

Use only for a driver who has not set a passcode. Driver OTP is delivered by phone only.

Request fields

assignedId uses CRZ-ABC-0001 format; channel must be phone.

What to parse

Show the masked phone destination and the ten-minute countdown.

Expected result

202 accepts delivery. A completed driver receives DRIVER_ALREADY_ONBOARDED.

Important

The response never exposes the production OTP.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/onboarding/otp/request', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"assignedId":"CRZ-ABC-0001","channel":"phone"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"assignedId":"CRZ-ABC-0001","channel":"phone"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/onboarding/otp/request',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"assignedId":"CRZ-ABC-0001","channel":"phone"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/onboarding/otp/request');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/onboarding/otp/request' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"assignedId":"CRZ-ABC-0001","channel":"phone"}'
Request
Response
HTTP 202 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "accepted": true,
    "channel": "phone",
    "destination": "+234 *** *** 692",
    "expiresInSeconds": 600
  },
  "error": null
}
POST/api/v1/auth/driver/onboarding/otp/verify
Public

Verify OTP and receive passcode setup token

Endpoint guide What to send, parse and expect

Why it exists

Verifies the six-digit OTP and opens the passcode-setup step.

Before you call

Request the OTP first.

Request fields

Send assignedId and the six-digit code.

What to parse

Keep setupToken only in memory, route to Set Passcode, then Confirm Passcode. Compare both entries locally and submit the passcode once.

Expected result

200 returns setupToken, expiresInSeconds and nextStep PASSCODE; it does not authenticate the driver.

Important

The setup token expires after 15 minutes and is single-use.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/onboarding/otp/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"assignedId":"CRZ-ABC-0001","code":"123456"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"assignedId":"CRZ-ABC-0001","code":"123456"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/onboarding/otp/verify',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"assignedId":"CRZ-ABC-0001","code":"123456"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/onboarding/otp/verify');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/onboarding/otp/verify' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"assignedId":"CRZ-ABC-0001","code":"123456"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "setupToken": "<driver-setup-token>",
    "expiresInSeconds": 900,
    "nextStep": "PASSCODE"
  },
  "error": null
}
POST/api/v1/auth/driver/onboarding/passcode
Public

Set confirmed six-digit passcode

Endpoint guide What to send, parse and expect

Why it exists

Sets the confirmed six-digit driver passcode and completes authentication setup.

Before you call

Verify OTP, collect the passcode twice, and submit only after the two local entries match.

Request fields

Send setupToken and one six-digit passcode. Never send a confirmation copy.

What to parse

Store access/refresh tokens securely, request location permission, send the first location, then show setup success and open Driver Home.

Expected result

200 returns the driver session, nextStep LOCATION and status OFFLINE.

Important

Only a bcrypt hash is stored; the setup token is consumed atomically.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/onboarding/passcode', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"setupToken":"<setup-token>","passcode":"246810"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"setupToken":"<setup-token>","passcode":"246810"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/onboarding/passcode',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"setupToken":"<setup-token>","passcode":"246810"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/onboarding/passcode');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/onboarding/passcode' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"setupToken":"<setup-token>","passcode":"246810"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "driver": {
      "id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
      "assignedId": "CRZ-ABC-0001",
      "status": "OFFLINE"
    },
    "nextStep": "LOCATION",
    "accessToken": "<driver-access-token>",
    "refreshToken": "<refresh-token>"
  },
  "error": null
}
POST/api/v1/auth/driver/login
Public

Returning driver passcode login

Endpoint guide What to send, parse and expect

Why it exists

Signs in a returning driver with their fleet-issued assigned ID and saved six-digit passcode.

Before you call

Use after the splash/welcome screen for drivers who completed setup.

Request fields

Send assignedId and passcode.

What to parse

Store tokens in platform secure storage, load /driver/me and /driver/home, and keep the driver OFFLINE until they explicitly go online.

Expected result

200 returns a driver session. Invalid credentials use one generic response.

Important

IP throttling and account-level failed-attempt lockout protect the six-digit credential.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"assignedId":"CRZ-ABC-0001","passcode":"246810"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"assignedId":"CRZ-ABC-0001","passcode":"246810"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/login',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"assignedId":"CRZ-ABC-0001","passcode":"246810"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/login');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/login' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"assignedId":"CRZ-ABC-0001","passcode":"246810"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "driver": {
      "id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
      "assignedId": "CRZ-ABC-0001",
      "status": "OFFLINE"
    },
    "accessToken": "<driver-access-token>",
    "refreshToken": "<refresh-token>"
  },
  "error": null
}
POST/api/v1/auth/driver/passcode-reset/request
Public

Request forgotten-passcode OTP

Endpoint guide What to send, parse and expect

Why it exists

Starts forgotten-passcode recovery using the phone already linked to an eligible driver.

Before you call

Use only after the driver selects Forgot passcode; never send a passcode reset to an unverified contact.

Request fields

Send assignedId and channel phone.

What to parse

Always show the same confirmation screen to avoid revealing account eligibility; start a ten-minute countdown.

Expected result

202 is intentionally generic.

Important

OTP delivery is rate limited and recovery is logged without exposing the destination.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/passcode-reset/request', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"assignedId":"CRZ-ABC-0001","channel":"phone"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"assignedId":"CRZ-ABC-0001","channel":"phone"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/passcode-reset/request',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"assignedId":"CRZ-ABC-0001","channel":"phone"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/passcode-reset/request');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/passcode-reset/request' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"assignedId":"CRZ-ABC-0001","channel":"phone"}'
Request
Response
HTTP 202 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "accepted": true,
    "channel": "phone",
    "expiresInSeconds": 600
  },
  "error": null
}
POST/api/v1/auth/driver/passcode-reset/verify
Public

Verify recovery OTP

Endpoint guide What to send, parse and expect

Why it exists

Verifies the recovery OTP and opens the new-passcode step.

Before you call

Request a recovery OTP first.

Request fields

Send assignedId and six-digit code.

What to parse

Keep resetToken only in memory, then collect and locally confirm the new six-digit passcode.

Expected result

200 returns a 15-minute single-use resetToken and nextStep RESET_PASSCODE.

Important

The OTP is consumed atomically and cannot be reused.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/passcode-reset/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"assignedId":"CRZ-ABC-0001","code":"123456"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"assignedId":"CRZ-ABC-0001","code":"123456"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/passcode-reset/verify',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"assignedId":"CRZ-ABC-0001","code":"123456"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/passcode-reset/verify');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/passcode-reset/verify' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"assignedId":"CRZ-ABC-0001","code":"123456"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "resetToken": "<driver-passcode-reset-token>",
    "expiresInSeconds": 900,
    "nextStep": "RESET_PASSCODE"
  },
  "error": null
}
POST/api/v1/auth/driver/passcode-reset/confirm
Public

Set recovered six-digit passcode

Endpoint guide What to send, parse and expect

Why it exists

Sets a recovered driver passcode and signs the recovered device in.

Before you call

Verify the recovery OTP and compare both new passcode entries locally.

Request fields

Send resetToken and one six-digit passcode.

What to parse

Replace stored credentials with the returned session. Other devices must return to sign-in.

Expected result

200 returns a fresh driver session and nextStep LOCATION.

Important

Prior sessions are revoked atomically; recovery is audited with device and IP context.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/auth/driver/passcode-reset/confirm', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"resetToken":"<reset-token>","passcode":"246810"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"resetToken":"<reset-token>","passcode":"246810"}''')
response = requests.post(BASE_URL + '/api/v1/auth/driver/passcode-reset/confirm',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"resetToken":"<reset-token>","passcode":"246810"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/auth/driver/passcode-reset/confirm');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/auth/driver/passcode-reset/confirm' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"resetToken":"<reset-token>","passcode":"246810"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "driver": {
      "id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
      "assignedId": "CRZ-ABC-0001",
      "status": "OFFLINE"
    },
    "nextStep": "LOCATION",
    "accessToken": "<driver-access-token>",
    "refreshToken": "<refresh-token>"
  },
  "error": null
}
GET/api/v1/driver/me
Bearer token

Driver profile

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/me', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/me',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/me');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/me' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "a2454a62-cf67-476f-b52f-4eaea9978a83",
    "assignedId": "CRZ-ZZZ-0001",
    "fleetId": "fa840a12-3cad-4477-9a31-e9bfc2837c5b",
    "firstName": "Onboard",
    "lastName": "Driver",
    "phone": "+2349054568692",
    "status": "OFFLINE",
    "profileImageKey": null,
    "pickupRadiusKm": 8,
    "usePickupRadius": true,
    "offerMode": "MANUAL",
    "dispatchScore": 500,
    "ratingAverage": 5,
    "ratingCount": 0,
    "vehicle": {
      "id": "2127456d-32d1-439d-9d01-070e959babf9",
      "fleet_id": "fa840a12-3cad-4477-9a31-e9bfc2837c5b",
      "vin": "CRUIZVIN1787920343407379",
      "plate_number": "CRZ407379",
      "brand": "ASTRA Ride",
      "model": "EV Test",
      "battery_capacity_kwh": null,
      "battery_percent": 84,
      "year": 2025,
      "color": "Blue",
      "status": "OFFLINE",
      "odometer_km": null,
      "current_lat": "4.8156",
      "current_lng": "7.0498",
      "last_seen_at": "2026-08-28T12:33:14.546Z",
      "image_key": null,
      "created_at": "2026-08-28T12:32:33.044Z",
      "updated_at": "2026-08-28T12:33:14.546Z"
    },
    "paymentAccountConfigured": false
  },
  "error": null
}
GET/api/v1/driver/home
Bearer token

Driver home dashboard snapshot

Endpoint guide What to send, parse and expect

Why it exists

Returns the driver-home snapshot: readiness, active trip, earnings, completed rides, distance and rating.

Before you call

Call after authentication and whenever the app resumes.

Request fields

No JSON body; identity is derived from bearer authentication.

What to parse

Render readiness.blockers before enabling Online. Monetary Minor values are kobo.

Expected result

200 returns the current dashboard source of truth.

Important

The driver cannot calculate or modify this server-owned snapshot.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/home', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/home',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/home');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/home' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "status": "OFFLINE",
    "readiness": {
      "ready": true,
      "blockers": [],
      "vehicle": {
        "id": "2127456d-32d1-439d-9d01-070e959babf9",
        "batteryPercent": 84,
        "locationRecordedAt": "2026-08-28T12:33:14.546Z"
      },
      "policy": {
        "minBatteryPercent": 30,
        "maxLocationAgeMinutes": 10
      }
    },
    "activeTrip": null,
    "today": {
      "earningsMinor": 0,
      "completedTrips": 0,
      "totalDistanceKm": 0,
      "ratingAverage": 5
    },
    "dispatch": {
      "pickupRadiusKm": 8,
      "usePickupRadius": true,
      "offerMode": "MANUAL",
      "score": 500
    }
  },
  "error": null
}
GET/api/v1/driver/demand-forecast
Bearer token

Predictive demand cells for the driver map

Endpoint guide What to send, parse and expect

Why it exists

Returns privacy-aggregated cells predicting demand for the next 20 minutes.

Before you call

Call when the driver opens the map, after app resume, and once per minute while the map is visible.

Request fields

Optional minLatitude, minLongitude, maxLatitude and maxLongitude define a bounded viewport.

What to parse

Draw polygons in longitude/latitude order and remove the overlay after expiresAt.

Expected result

200 returns methodologyVersion and fleet-scoped zones; an empty zones array is valid.

Important

Only server-produced signals are used and cells with fewer than five distinct riders are suppressed.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/demand-forecast', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/demand-forecast',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/demand-forecast');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/demand-forecast' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "generatedAt": "2026-09-13T18:00:00.000Z",
    "expiresAt": "2026-09-13T18:02:00.000Z",
    "forecastWindowMinutes": 20,
    "methodologyVersion": "cruiz-demand-v1",
    "privacyThreshold": 5,
    "zones": [
      {
        "id": "4.81:7.04",
        "polygon": [
          [
            7.04,
            4.81
          ],
          [
            7.05,
            4.81
          ],
          [
            7.05,
            4.82
          ],
          [
            7.04,
            4.82
          ],
          [
            7.04,
            4.81
          ]
        ],
        "center": {
          "latitude": 4.815,
          "longitude": 7.045
        },
        "level": "HIGH",
        "label": "High demand expected",
        "confidence": "MEDIUM",
        "score": 1.82
      }
    ]
  },
  "error": null
}
POST/api/v1/driver/location
Bearer token

Send verified GPS location

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/location', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"latitude":4.8156,"longitude":7.0498})
});
const result = await response.json();

Python

payload = json.loads(r'''{"latitude":4.8156,"longitude":7.0498}''')
response = requests.post(BASE_URL + '/api/v1/driver/location',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"latitude":4.8156,"longitude":7.0498}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/location');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/location' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"latitude":4.8156,"longitude":7.0498}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "driver-location-1",
    "driver_id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
    "trip_id": null,
    "latitude": "4.8156",
    "longitude": "7.0498",
    "speed_kph": "0",
    "heading": "0",
    "recorded_at": "2026-08-28T18:00:00.000Z",
    "received_at": "2026-08-28T18:00:00.000Z"
  },
  "error": null
}
PATCH/api/v1/driver/dispatch-preferences
Bearer token

Set manual offers or range-bound auto-accept

Endpoint guide What to send, parse and expect

Why it exists

Sets driver-controlled pickup range and offer behaviour. Auto-accept is permitted only inside an enabled pickup range.

Before you call

Pickup range and auto-accept are off by default. Before going online, send current GPS, save this preference, check readiness, then set ONLINE. The driver, not the fleet, controls this setting.

Request fields

MANUAL: { offerMode:"MANUAL", usePickupRadius:false } receives normal offers without a self-set range. AUTO: send { offerMode:"AUTO", usePickupRadius:true, pickupRadiusKm:1-50 }. To disable range while AUTO is enabled, send offerMode:"MANUAL" in that same request.

What to parse

With an enabled range, this driver is eligible only when pickup distance is within pickupRadiusKm. AUTO accepts an eligible offer immediately; MANUAL sends driver:trip_offer and requires POST /driver/offers/:id/respond. A legacy AUTO record without a range fails closed and behaves as MANUAL until corrected.

Expected result

200 confirms the saved pickup-radius and offer-mode preferences. 409 AUTO_ACCEPT_REQUIRES_PICKUP_RANGE explains an invalid AUTO-without-range update and returns the current setting.

Important

The backend merges partial updates with the saved preference before validating them, so a client cannot enable unbounded auto-accept by omitting fields.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/dispatch-preferences', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"pickupRadiusKm":10,"usePickupRadius":true,"offerMode":"AUTO"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"pickupRadiusKm":10,"usePickupRadius":true,"offerMode":"AUTO"}''')
response = requests.patch(BASE_URL + '/api/v1/driver/dispatch-preferences',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"pickupRadiusKm":10,"usePickupRadius":true,"offerMode":"AUTO"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/dispatch-preferences');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X PATCH '<base-url>/api/v1/driver/dispatch-preferences' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"pickupRadiusKm":10,"usePickupRadius":true,"offerMode":"AUTO"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "pickupRadiusKm": 12,
    "usePickupRadius": true,
    "offerMode": "AUTO"
  },
  "error": null
}
GET/api/v1/driver/readiness
Bearer token

Check online eligibility and blockers

Endpoint guide What to send, parse and expect

Why it exists

Explains whether a driver can go online and every blocker preventing it.

Before you call

Call before displaying/enabling the Online switch.

Request fields

No body. The server checks approved documents, active vehicle, battery and fresh location.

What to parse

If ready is false, render each blocker message and resolve it before PATCH status.

Expected result

200 returns readiness whether or not the driver is eligible.

Important

The same checks are enforced again when the driver requests ONLINE.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/readiness', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/readiness',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/readiness');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/readiness' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "ready": true,
    "blockers": [],
    "vehicle": {
      "id": "2127456d-32d1-439d-9d01-070e959babf9",
      "batteryPercent": 84,
      "locationRecordedAt": "2026-08-28T12:33:14.546Z"
    },
    "policy": {
      "minBatteryPercent": 30,
      "maxLocationAgeMinutes": 10
    }
  },
  "error": null
}
PATCH/api/v1/driver/status
Bearer token

Set ONLINE or OFFLINE

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/status', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"status":"ONLINE"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"status":"ONLINE"}''')
response = requests.patch(BASE_URL + '/api/v1/driver/status',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"status":"ONLINE"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/status');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X PATCH '<base-url>/api/v1/driver/status' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"status":"ONLINE"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
    "status": "ONLINE",
    "pickup_radius_km": "12",
    "uses_pickup_radius": false,
    "offer_mode": "MANUAL"
  },
  "error": null
}
GET/api/v1/driver/offers
Bearer token

Read current expiring driver offers

Endpoint guide What to send, parse and expect

Why it exists

Lists only active, unexpired offers created for the authenticated driver.

Before you call

Set driver status ONLINE. Connect Socket.IO first and handle driver:trip_offer, then use this endpoint after reconnecting or app resume.

Request fields

No request body. The API derives the driver from the bearer token.

What to parse

On driver:trip_offer, fetch this endpoint for the safe pickup/drop-off/fare preview and count down to expiresAt. On driver:trip_offer_expired, close the offer and disable both response buttons. Refetch this endpoint after reconnecting.

Expected result

200 returns the current driver-owned offers.

Important

An offer is not a trip assignment; only the assigned driver may view or respond to it.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/offers', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/offers',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/offers');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/offers' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [],
  "error": null
}
POST/api/v1/driver/offers/:id/respond
Bearer token

Accept or decline an expiring driver offer

Endpoint guide What to send, parse and expect

Why it exists

Atomically accepts or declines a single expiring trip offer.

Before you call

Call only from an offer returned by GET offers or a driver:trip_offer socket event. Disable both buttons once tapped.

Request fields

Replace :id with OFF_<uuid>. Raw UUIDs are also accepted. decision is ACCEPT or DECLINE.

What to parse

On ACCEPT render assigned trip details; on DECLINE discard the offer. OFFER_EXPIRED and OFFER_NOT_AVAILABLE mean refetch offers.

Expected result

200 ACCEPT returns kind: ACCEPTED, tripId, riderId, fleetId, driver preview, and rider { id, firstName, lastName, phone, profileImageKey } after atomically assigning the trip and recording its assignment event. 200 DECLINE returns kind: DECLINED and the next matching state. 409 prevents a late, duplicate or unavailable response.

Important

The server rechecks offer owner, expiry, driver availability and vehicle availability within one transaction.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/offers/:id/respond', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"decision":"ACCEPT"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"decision":"ACCEPT"}''')
response = requests.post(BASE_URL + '/api/v1/driver/offers/:id/respond',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"decision":"ACCEPT"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/offers/:id/respond');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/offers/:id/respond' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"decision":"ACCEPT"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "kind": "ACCEPTED",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "riderId": "RDR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "fleetId": "FLT_b1fe6573-3a25-4d13-b41e-55143176d849",
    "selectedDriver": {
      "id": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
      "firstName": "Browser",
      "lastName": "Driver"
    },
    "trip": {
      "id": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
      "status": "DRIVER_ASSIGNED"
    }
  },
  "error": null
}
GET/api/v1/driver/trips/active
Bearer token

Active trips

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/active', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/active',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/active');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/active' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [],
  "error": null
}
GET/api/v1/driver/trips/history
Bearer token

Completed and cancelled ride history

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/history', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/history',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/history');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/history' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "<resource-id>",
    "status": "OK"
  },
  "error": null
}
GET/api/v1/driver/trips/:id
Bearer token

Read assigned trip and pickup verification policy

Endpoint guide What to send, parse and expect

Why it exists

Reads one assigned driver trip, including whether pickup verification is required for its fleet.

Before you call

Use after accepting an offer or after reconnecting, before rendering the pickup controls.

Request fields

Replace :id with the assigned TRIP_<uuid>. No request body.

What to parse

Read pickupVerification.required. When false, after DRIVER_ARRIVED call the normal state endpoint with PASSENGER_ONBOARD; when true, obtain the rider PIN/QR and call pickup/verify.

Expected result

200 returns only a trip assigned to this driver plus pickupVerification { required, mode }. 403 means the trip is not assigned to this driver.

Important

This response exposes policy only, never the rider pickup PIN or QR.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/:id',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/:id' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "<resource-id>",
    "status": "OK"
  },
  "error": null
}
POST/api/v1/driver/trips/:id/state
Bearer token

Transition a driver trip state

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/state', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"status":"DRIVER_EN_ROUTE"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"status":"DRIVER_EN_ROUTE"}''')
response = requests.post(BASE_URL + '/api/v1/driver/trips/:id/state',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"status":"DRIVER_EN_ROUTE"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/state');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/trips/:id/state' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"status":"DRIVER_EN_ROUTE"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "DRIVER_EN_ROUTE",
    "tripVersion": 2
  },
  "error": null
}
POST/api/v1/driver/trips/:id/pickup/verify
Bearer token

Verify rider pickup PIN or QR

Endpoint guide What to send, parse and expect

Why it exists

Verifies the rider's PIN or QR at pickup and atomically advances the ride to PASSENGER_ONBOARD.

Before you call

This is available only when the fleet has pickup verification enabled and the driver has already set DRIVER_ARRIVED.

Request fields

Replace :id with the assigned trip UUID. Send either pin (four digits) or qrPayload read by the driver's scanner.

What to parse

Use data.trip.status as the new source of truth. A repeat tap returns alreadyVerified:true and is safe.

Expected result

200 confirms boarding. 400 is an invalid PIN/QR; 409 identifies an unavailable state, disabled feature or missing arrival.

Important

The rider-only credential never appears in driver detail APIs and the driver cannot choose another trip's PIN.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/pickup/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"pin":"1234"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"pin":"1234"}''')
response = requests.post(BASE_URL + '/api/v1/driver/trips/:id/pickup/verify',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"pin":"1234"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/pickup/verify');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/trips/:id/pickup/verify' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"pin":"1234"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "verified": true,
    "alreadyVerified": false,
    "trip": {
      "id": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
      "status": "PASSENGER_ONBOARD"
    }
  },
  "error": null
}
GET/api/v1/driver/earnings
Bearer token

Driver earnings and commission

Endpoint guide What to send, parse and expect

Why it exists

Returns server-calculated gross, commission, net and completed trips.

Before you call

Optionally add ?period=TODAY, LAST_7_DAYS or LAST_30_DAYS.

Request fields

No JSON body. Values ending in Minor are kobo.

What to parse

Show gross, commission and net separately; this is not a payout instruction.

Expected result

200 returns summary and trip rows.

Important

Only the caller's completed trips are included.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/earnings', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/earnings',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/earnings');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/earnings' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "period": "LAST_7_DAYS",
    "summary": {
      "grossEarningsMinor": 0,
      "commissionMinor": 0,
      "netEarningsMinor": 0,
      "currency": "NGN",
      "completedTrips": 0
    },
    "trips": []
  },
  "error": null
}
GET/api/v1/driver/score
Bearer token

Driver dispatch score and audit events

Endpoint guide What to send, parse and expect

Why it exists

Shows dispatch score, rider rating and an immutable score-event history.

Before you call

Use this for transparent driver education.

Request fields

No body.

What to parse

Score is 0-1000; ranking weights reliability 55%, rating 25% and proximity 20%.

Expected result

200 returns score and events.

Important

Only trusted backend actions write score events.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/score', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/score',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/score');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/score' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "score": 500,
    "ratingAverage": 5,
    "ratingCount": 0,
    "weighting": {
      "dispatchReliability": 55,
      "riderRating": 25,
      "pickupProximity": 20
    },
    "events": []
  },
  "error": null
}
GET/api/v1/driver/fraud-signals
Bearer token

Driver-visible risk signals

Endpoint guide What to send, parse and expect

Why it exists

Lists non-sensitive fraud/operational flags affecting the signed-in driver.

Before you call

Use for transparent account-health and support screens.

Request fields

No body.

What to parse

Render status and safe detail. Do not infer internal fraud thresholds.

Expected result

200 returns caller-owned records.

Important

Drivers cannot create, clear or alter signals.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/fraud-signals', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/fraud-signals',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/fraud-signals');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/fraud-signals' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [],
  "error": null
}
GET/api/v1/driver/messages
Bearer token

Read authorised driver messages

Endpoint guide What to send, parse and expect

Why it exists

Lets the assigned driver read and send messages only within an authorised active trip.

Before you call

The rider must be assigned to the driver. Use the trip id from the driver active-trips response.

Request fields

POST accepts tripId and body; the server derives the rider recipient, so do not send recipientId.

What to parse

Render messages only in the matching trip conversation and subscribe to message:received for delivery.

Expected result

GET 200 returns the driver message inbox; POST 201 creates the trip message.

Important

The backend rejects messages for a trip assigned to another driver.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/messages', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/messages',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/messages');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/messages' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [],
  "error": null
}
POST/api/v1/driver/messages
Bearer token

Send an authorised message to active rider

Endpoint guide What to send, parse and expect

Why it exists

Lets the assigned driver read and send messages only within an authorised active trip.

Before you call

The rider must be assigned to the driver. Use the trip id from the driver active-trips response.

Request fields

POST accepts tripId and body; the server derives the rider recipient, so do not send recipientId.

What to parse

Render messages only in the matching trip conversation and subscribe to message:received for delivery.

Expected result

GET 200 returns the driver message inbox; POST 201 creates the trip message.

Important

The backend rejects messages for a trip assigned to another driver.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/messages', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"tripId":"TRIP_<uuid>","body":"I am approaching pickup."})
});
const result = await response.json();

Python

payload = json.loads(r'''{"tripId":"TRIP_<uuid>","body":"I am approaching pickup."}''')
response = requests.post(BASE_URL + '/api/v1/driver/messages',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"tripId":"TRIP_<uuid>","body":"I am approaching pickup."}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/messages');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/messages' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"tripId":"TRIP_<uuid>","body":"I am approaching pickup."}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "driver-msg-1",
    "trip_id": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "sender_id": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "recipient_id": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "body": "I am approaching pickup.",
    "type": "TRIP",
    "created_at": "2026-08-28T18:03:00.000Z"
  },
  "error": null
}
GET/api/v1/driver/support/tickets
Bearer token

List driver support tickets

Endpoint guide What to send, parse and expect

Why it exists

Creates/lists driver-owned support tickets for non-emergency issues.

Before you call

Use for payment, vehicle, account or rider issues.

Request fields

POST accepts category, subject, details, priority and optional owned tripId.

What to parse

Persist the returned ticket id/status for support UI.

Expected result

GET 200; POST 201.

Important

A driver can attach only their own trip.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/support/tickets', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/support/tickets',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/support/tickets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/support/tickets' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [
    {
      "id": "4b531f71-78d7-4bf9-895f-3c8240127eef",
      "driver_id": "a2454a62-cf67-476f-b52f-4eaea9978a83",
      "trip_id": null,
      "category": "ACCOUNT",
      "subject": "Controlled support test",
      "details": "Testing the driver support endpoint.",
      "priority": "NORMAL",
      "status": "OPEN",
      "created_at": "2026-08-28T12:33:17.613Z",
      "updated_at": "2026-08-28T12:33:17.611Z"
    }
  ],
  "error": null
}
POST/api/v1/driver/support/tickets
Bearer token

Open a driver support ticket

Endpoint guide What to send, parse and expect

Why it exists

Creates/lists driver-owned support tickets for non-emergency issues.

Before you call

Use for payment, vehicle, account or rider issues.

Request fields

POST accepts category, subject, details, priority and optional owned tripId.

What to parse

Persist the returned ticket id/status for support UI.

Expected result

GET 200; POST 201.

Important

A driver can attach only their own trip.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/support/tickets', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"category":"PAYMENT","subject":"Transfer pending","details":"Trip payment has not appeared.","priority":"HIGH"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"category":"PAYMENT","subject":"Transfer pending","details":"Trip payment has not appeared.","priority":"HIGH"}''')
response = requests.post(BASE_URL + '/api/v1/driver/support/tickets',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"category":"PAYMENT","subject":"Transfer pending","details":"Trip payment has not appeared.","priority":"HIGH"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/support/tickets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/support/tickets' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"category":"PAYMENT","subject":"Transfer pending","details":"Trip payment has not appeared.","priority":"HIGH"}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "driver-ticket-1",
    "status": "OPEN",
    "priority": "HIGH",
    "createdAt": "2026-08-28T18:03:00.000Z"
  },
  "error": null
}
GET/api/v1/driver/support/tickets/:id
Bearer token

Read an owned support ticket conversation

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/support/tickets/:id', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/support/tickets/:id',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/support/tickets/:id');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/support/tickets/:id' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "driver-ticket-1",
    "subject": "Transfer pending",
    "status": "PENDING_CUSTOMER",
    "messages": []
  },
  "error": null
}
POST/api/v1/driver/support/tickets/:id/messages
Bearer token

Reply to an owned support ticket

Endpoint guide What to send, parse and expect

Why it exists

Use this endpoint to perform the action described above.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

The JSON editor contains a runnable example. Required field rules are returned as error.details.fieldErrors when validation fails.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/support/tickets/:id/messages', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"body":"Here is the requested information."})
});
const result = await response.json();

Python

payload = json.loads(r'''{"body":"Here is the requested information."}''')
response = requests.post(BASE_URL + '/api/v1/driver/support/tickets/:id/messages',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"body":"Here is the requested information."}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/support/tickets/:id/messages');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/support/tickets/:id/messages' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"body":"Here is the requested information."}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "replayed": false,
    "status": "IN_PROGRESS",
    "message": {
      "id": "driver-reply-1",
      "body": "The trip was completed yesterday.",
      "author": "CUSTOMER",
      "createdAt": "2026-08-28T18:05:00.000Z"
    }
  },
  "error": null
}
POST/api/v1/driver/safety/incidents
Bearer token

Raise driver SOS or safety incident

Endpoint guide What to send, parse and expect

Why it exists

Raises a driver SOS or safety incident for fleet operations.

Before you call

In immediate danger call emergency services first, then send current coordinates where available.

Request fields

POST type, description and optional own trip/location. SOS/collision are CRITICAL.

What to parse

After 201 confirm, retain the emergency action and await operational follow-up.

Expected result

201 creates a durable auditable incident.

Important

Trip ownership is verified and severity is server determined.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/safety/incidents', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"type":"SOS","description":"I need urgent help","latitude":4.8156,"longitude":7.0498})
});
const result = await response.json();

Python

payload = json.loads(r'''{"type":"SOS","description":"I need urgent help","latitude":4.8156,"longitude":7.0498}''')
response = requests.post(BASE_URL + '/api/v1/driver/safety/incidents',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"type":"SOS","description":"I need urgent help","latitude":4.8156,"longitude":7.0498}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/safety/incidents');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/safety/incidents' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"type":"SOS","description":"I need urgent help","latitude":4.8156,"longitude":7.0498}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "driver-incident-1",
    "status": "OPEN",
    "severity": "CRITICAL",
    "createdAt": "2026-08-28T18:03:00.000Z"
  },
  "error": null
}
GET/api/v1/driver/remittance-balance
Bearer token

Read cash commission debt and online block state

Endpoint guide What to send, parse and expect

Why it exists

Calculates the authenticated driver cash-trip commission debt to their fleet and tells the app if ONLINE is blocked.

Before you call

Call before enabling Online and after a fleet reviews a payment.

Request fields

No body. All values ending in Minor are kobo.

What to parse

Use outstandingMinor and blocked. The server, not the app, rejects ONLINE when the policy threshold is reached.

Expected result

200 returns the debt, submitted remittances and policy.

Important

Only confirmed cash collections and APPROVED remittances affect the balance.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/remittance-balance', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/remittance-balance',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/remittance-balance');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/remittance-balance' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "currency": "NGN",
    "policy": {
      "enabled": false,
      "thresholdMinor": 500000,
      "blockOnline": true
    },
    "commissionRateBps": 0,
    "accruedCommissionMinor": 0,
    "approvedRemittanceMinor": 0,
    "submittedRemittanceMinor": 0,
    "outstandingMinor": 0,
    "blocked": false
  },
  "error": null
}
GET/api/v1/driver/remittances
Bearer token

List driver remittances

Endpoint guide What to send, parse and expect

Why it exists

Lists or submits a driver-to-fleet cash commission remittance for fleet finance review.

Before you call

The driver pays the fleet, then submits its payment reference. A fleet approval is required before debt reduces.

Request fields

POST amountMinor, paymentReference and optional note. Amount must not exceed outstanding debt.

What to parse

Render SUBMITTED as pending review and APPROVED as settled.

Expected result

GET 200; POST 201.

Important

The backend owns the debt calculation and rejects over-remittance.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/remittances', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/remittances',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/remittances');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/remittances' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [],
  "error": null
}
POST/api/v1/driver/remittances
Bearer token

Submit cash commission remittance

Endpoint guide What to send, parse and expect

Why it exists

Lists or submits a driver-to-fleet cash commission remittance for fleet finance review.

Before you call

The driver pays the fleet, then submits its payment reference. A fleet approval is required before debt reduces.

Request fields

POST amountMinor, paymentReference and optional note. Amount must not exceed outstanding debt.

What to parse

Render SUBMITTED as pending review and APPROVED as settled.

Expected result

GET 200; POST 201.

Important

The backend owns the debt calculation and rejects over-remittance.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/remittances', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"amountMinor":50000,"paymentReference":"TRF-12345"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"amountMinor":50000,"paymentReference":"TRF-12345"}''')
response = requests.post(BASE_URL + '/api/v1/driver/remittances',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"amountMinor":50000,"paymentReference":"TRF-12345"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/remittances');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/remittances' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"amountMinor":50000,"paymentReference":"TRF-12345"}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "RMT_6d87456d-32d1-439d-9d01-070e959babf9",
    "amountMinor": 50000,
    "paymentReference": "TRF-12345",
    "status": "SUBMITTED",
    "createdAt": "2026-08-28T18:04:00.000Z"
  },
  "error": null
}
GET/api/v1/driver/trips/:id/rider-locationNEW
Bearer token

Recover the rider’s latest shared pickup position

Endpoint guide What to send, parse and expect

Why it exists

Fetches a fresh rider GPS position after reconnect.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

Replace :id with an assigned trip ID. No body.

What to parse

data.location is null if the rider has not shared recently or pickup is complete. The trip pickup coordinate remains available separately.

Expected result

200 returns tripId and location.

Important

Only the currently assigned driver may read this position before pickup.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/rider-location', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/:id/rider-location',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/rider-location');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/:id/rider-location' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "location": {
      "latitude": 4.8156,
      "longitude": 7.0498,
      "accuracyM": 12,
      "recordedAt": "2026-08-28T18:04:00.000Z"
    }
  },
  "error": null
}
PATCH/api/v1/driver/profile
Bearer token

Update the signed-in driver profile

Endpoint guide What to send, parse and expect

Why it exists

Updates the driver name in both the driver and account records.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

Send at least firstName or lastName.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns the refreshed profile.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/profile', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"firstName":"Jane","lastName":"Doe"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"firstName":"Jane","lastName":"Doe"}''')
response = requests.patch(BASE_URL + '/api/v1/driver/profile',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"firstName":"Jane","lastName":"Doe"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/profile');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X PATCH '<base-url>/api/v1/driver/profile' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"firstName":"Jane","lastName":"Doe"}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
    "firstName": "Jane",
    "lastName": "Doe",
    "phone": "+2349054568692"
  },
  "error": null
}
GET/api/v1/driver/devices
Bearer token

List registered driver devices

Endpoint guide What to send, parse and expect

Why it exists

Lists only devices registered by the signed-in driver.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns device settings.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/devices', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/devices',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/devices');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/devices' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [
    {
      "id": "device-1",
      "driverId": "DRV_2e3149da-835d-4fdc-8d5e-02a5d6c7d55e",
      "deviceId": "ios-installation-id",
      "platform": "IOS",
      "notificationsEnabled": true,
      "lastSeenAt": "2026-08-28T18:05:00.000Z"
    }
  ],
  "error": null
}
GET/api/v1/driver/notifications
Bearer token

Read durable driver notifications

Endpoint guide What to send, parse and expect

Why it exists

Returns the signed-in driver notification history.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns newest-first messages.

Important

Recovery source after launch or socket reconnect.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/notifications', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/notifications',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/notifications');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/notifications' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "<resource-id>",
    "status": "OK"
  },
  "error": null
}
POST/api/v1/driver/notifications/:id/read
Bearer token

Mark a driver notification read

Endpoint guide What to send, parse and expect

Why it exists

Acknowledges an owned notification.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

Replace :id with the notification id.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns read true.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/notifications/:id/read', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.post(BASE_URL + '/api/v1/driver/notifications/:id/read',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/notifications/:id/read');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/notifications/:id/read' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "<created-id>",
    "status": "CREATED"
  },
  "error": null
}
PUT/api/v1/driver/devices
Bearer token

Register/update push-notification device

Endpoint guide What to send, parse and expect

Why it exists

Safely upserts a device registration for notifications.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

deviceId, platform and optional pushToken.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns the registered device.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/devices', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"deviceId":"ios-installation-id","platform":"IOS","notificationsEnabled":true})
});
const result = await response.json();

Python

payload = json.loads(r'''{"deviceId":"ios-installation-id","platform":"IOS","notificationsEnabled":true}''')
response = requests.put(BASE_URL + '/api/v1/driver/devices',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"deviceId":"ios-installation-id","platform":"IOS","notificationsEnabled":true}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/devices');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PUT',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X PUT '<base-url>/api/v1/driver/devices' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"deviceId":"ios-installation-id","platform":"IOS","notificationsEnabled":true}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "status": "OK"
  },
  "error": null
}
POST/api/v1/driver/trips/:id/feedback
Bearer token

Rate a rider with comment

Endpoint guide What to send, parse and expect

Why it exists

Stores one driver-to-rider rating after a completed trip.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

score is 1-5; comment is optional.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

201 creates feedback; 409 prevents duplicate ratings.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/feedback', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({"score":5,"comment":"Respectful rider"})
});
const result = await response.json();

Python

payload = json.loads(r'''{"score":5,"comment":"Respectful rider"}''')
response = requests.post(BASE_URL + '/api/v1/driver/trips/:id/feedback',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{"score":5,"comment":"Respectful rider"}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/feedback');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/driver/trips/:id/feedback' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{"score":5,"comment":"Respectful rider"}'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "id": "feedback-1",
    "score": 5,
    "comment": "Respectful rider",
    "createdAt": "2026-08-28T18:10:00.000Z"
  },
  "error": null
}
GET/api/v1/driver/trips/:id/waiting-fee
Bearer token

Preview waiting fee after 3-minute grace period

Endpoint guide What to send, parse and expect

Why it exists

Returns the server-calculated waiting-time fee and no-show eligibility.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body. Fleet/admin owns the policy; money is kobo.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns waited minutes, billable minutes and fee.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/waiting-fee', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/:id/waiting-fee',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/waiting-fee');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/:id/waiting-fee' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "eligible": true,
    "feeMinor": 1000,
    "policy": {
      "enabled": true,
      "graceMinutes": 3,
      "perMinuteMinor": 500,
      "noShowAfterMinutes": 10
    },
    "waitedMinutes": 5,
    "billableMinutes": 2
  },
  "error": null
}
GET/api/v1/driver/trips/:id/location-replay
Bearer token

Replay own authorised trip location points

Endpoint guide What to send, parse and expect

Why it exists

Restores driver route points after reconnect.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

Optional ?since=ISO timestamp.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns up to 2,000 ordered points.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/driver/trips/:id/location-replay', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/driver/trips/:id/location-replay',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/driver/trips/:id/location-replay');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/driver/trips/:id/location-replay' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": [
    {
      "latitude": 4.8156,
      "longitude": 7.0498,
      "recordedAt": "2026-08-28T18:01:00.000Z"
    },
    {
      "latitude": 4.817,
      "longitude": 7.048,
      "recordedAt": "2026-08-28T18:02:00.000Z"
    }
  ],
  "error": null
}
POST/api/v1/trips/:id/calls
Bearer token

Start an in-trip voice call

Endpoint guide What to send, parse and expect

Why it exists

Ring the assigned rider or driver for this active trip.

Before you call

Use the assigned TRIP_<uuid> and a bearer session. Send Idempotency-Key for safe retries.

Request fields

Optional `{ ringTimeoutSeconds }` integer: 10-300 seconds; omitted uses 120 seconds. The backend chooses the recipient and LiveKit room.

What to parse

Render RINGING and expiresAt. Wait for call:state_changed before requesting a join token.

Expected result

201 returns callId, tripId, status, version, participant IDs and timestamps. 409 means the trip is not eligible; 503 means LiveKit is disabled.

Important

Only the current assigned driver and rider can initiate. No LiveKit token is issued before answer.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({ "ringTimeoutSeconds": 120 })
});
const result = await response.json();

Python

payload = json.loads(r'''{ "ringTimeoutSeconds": 120 }''')
response = requests.post(BASE_URL + '/api/v1/trips/:id/calls',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{ "ringTimeoutSeconds": 120 }
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/trips/:id/calls' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{ "ringTimeoutSeconds": 120 }'
Request
Response
HTTP 201 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "RINGING",
    "version": 1,
    "callerUserId": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "recipientUserId": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "expiresAt": "2026-10-02T18:00:30.000Z",
    "acceptedAt": null,
    "activeAt": null,
    "endedAt": null,
    "createdAt": "2026-10-02T18:00:00.000Z"
  },
  "error": null
}
GET/api/v1/trips/:id/calls/active
Bearer token

Recover active call state

Endpoint guide What to send, parse and expect

Why it exists

Read the current call after app resume or socket reconnect.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns a call summary or null.

Important

Restricted to the assigned trip pair.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls/active', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.get(BASE_URL + '/api/v1/trips/:id/calls/active',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls/active');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X GET '<base-url>/api/v1/trips/:id/calls/active' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "RINGING",
    "version": 1,
    "callerUserId": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "recipientUserId": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "expiresAt": "2026-10-02T18:00:30.000Z",
    "acceptedAt": null,
    "activeAt": null,
    "endedAt": null,
    "createdAt": "2026-10-02T18:00:00.000Z"
  },
  "error": null
}
POST/api/v1/trips/:id/calls/:callId/accept
Bearer token

Accept an incoming call

Endpoint guide What to send, parse and expect

Why it exists

The recipient accepts before the call response deadline in expiresAt.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

Use CAL_<uuid> from call:incoming; no body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns CONNECTING; 409 means timed out or already decided.

Important

Caller cannot accept their own call.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls/:callId/accept', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.post(BASE_URL + '/api/v1/trips/:id/calls/:callId/accept',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls/:callId/accept');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/trips/:id/calls/:callId/accept' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "CONNECTING",
    "version": 2,
    "callerUserId": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "recipientUserId": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "expiresAt": "2026-10-02T18:00:30.000Z",
    "acceptedAt": "2026-10-02T18:00:12.000Z",
    "activeAt": null,
    "endedAt": null,
    "createdAt": "2026-10-02T18:00:00.000Z"
  },
  "error": null
}
POST/api/v1/trips/:id/calls/:callId/decline
Bearer token

Decline an incoming call

Endpoint guide What to send, parse and expect

Why it exists

The recipient declines the ringing call.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns DECLINED and emits call:ended.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls/:callId/decline', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.post(BASE_URL + '/api/v1/trips/:id/calls/:callId/decline',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls/:callId/decline');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/trips/:id/calls/:callId/decline' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "DECLINED",
    "version": 2,
    "callerUserId": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "recipientUserId": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "expiresAt": "2026-10-02T18:00:30.000Z",
    "acceptedAt": null,
    "activeAt": null,
    "endedAt": "2026-10-02T18:00:12.000Z",
    "createdAt": "2026-10-02T18:00:00.000Z"
  },
  "error": null
}
POST/api/v1/trips/:id/calls/:callId/join-token
Bearer token

Get own LiveKit microphone token

Endpoint guide What to send, parse and expect

Why it exists

After acceptance, get a short-lived credential for this device only.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body. Call separately on the rider and driver app.

What to parse

Pass serverUrl and token to the LiveKit SDK room.connect; then enable microphone. Never persist the token.

Expected result

200 returns callId, serverUrl, token, identity and expiresAt; Cache-Control: no-store.

Important

Server signs one-room, microphone-only, non-admin grants after rechecking assignment and call status.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls/:callId/join-token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.post(BASE_URL + '/api/v1/trips/:id/calls/:callId/join-token',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls/:callId/join-token');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/trips/:id/calls/:callId/join-token' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "serverUrl": "wss://your-project.livekit.cloud",
    "token": "<short-lived-livekit-token>",
    "identity": "rider:bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "expiresAt": "2026-10-02T18:02:00.000Z"
  },
  "error": null
}
POST/api/v1/trips/:id/calls/:callId/end
Bearer token

End an in-trip voice call

Endpoint guide What to send, parse and expect

Why it exists

Either participant terminates the call.

Before you call

Use the method and authentication badge shown above. Replace every placeholder with a value returned by an earlier API call.

Request fields

No body.

What to parse

Check success first. On success, read data; on failure, render error.code and error.message.

Expected result

200 returns ENDED and emits call:ended; repeated end is idempotent.

Request structure and code samples Node.js · Python · PHP · cURL

Replace angle-bracket values with returned values. Use the raw access token only in the Authorization header.

Node.js

const response = await fetch(BASE_URL + '/api/v1/trips/:id/calls/:callId/end', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer <access-token>',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({})
});
const result = await response.json();

Python

payload = json.loads(r'''{}''')
response = requests.post(BASE_URL + '/api/v1/trips/:id/calls/:callId/end',
    headers={'Idempotency-Key': str(uuid.uuid4())},
    json=payload)
result = response.json()

PHP

$payload = <<<'JSON'
{}
JSON;
$ch = curl_init($baseUrl . '/api/v1/trips/:id/calls/:callId/end');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Idempotency-Key: <uuid>'],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);

cURL

curl -X POST '<base-url>/api/v1/trips/:id/calls/:callId/end' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid>' \
  --data '{}'
Request
Response
HTTP 200 · FIXED TEST RESPONSE
{
  "success": true,
  "data": {
    "callId": "CAL_bbd4b8e1-e3b6-4dbb-bc7d-ea5df8592cbc",
    "tripId": "TRIP_a40cd66e-e88f-4729-9f03-49d66aad7a12",
    "status": "ENDED",
    "version": 2,
    "callerUserId": "USR_32f265f3-efee-4bbc-86d5-ed50c21c0267",
    "recipientUserId": "USR_0cc3dcfc-ce9c-4e79-bf09-3c77a0b6ac34",
    "expiresAt": "2026-10-02T18:00:30.000Z",
    "acceptedAt": null,
    "activeAt": null,
    "endedAt": "2026-10-02T18:00:12.000Z",
    "createdAt": "2026-10-02T18:00:00.000Z"
  },
  "error": null
}
Errors and safetyResponses use JSON with a stable error code. Mutating requests receive an automatic idempotency key in the test console. Never paste production credentials here.