Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions postman/collections/Fleetbase API/.resources/definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ variables:
customer_phone: ""
verification_code: ""
push_token: ""
driver_identity: ""
driver_email: ""
driver_phone: ""
# Seeded on Create a Driver so the password endpoints have a known starting
# point; `driver_password` then tracks whatever is currently in force.
driver_seed_password: "contract-seed-password"
driver_password: ""
driver_new_password: "contract-changed-password"
# A reserved address (RFC 2606) that can never be delivered to. Requesting a
# reset answers the same way for an unknown identity as for a real one, so the
# endpoint is still exercised and no stranger receives a reset code.
driver_reset_identity: "driver-password-reset@example.com"
manifest_id: ""
manifest_stop_id: ""
scripts:
- type: http:afterResponse
code: |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$kind: params
fields:
- name: current_password
type: string
required: true
description: The driver's existing password. The change is refused without it.
- name: password
type: string
required: true
description: The new password. Must be at least 8 characters.
- name: password_confirmation
type: string
required: false
description: When present, must match `password`.
- name: device_name
type: string
required: false
description: Name for the replacement token issued to the caller. Defaults to `navigator`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
$kind: http-request
name: "Change Driver Password"
description: |-
Changes the password of a driver who is signed in, proving the current one.

A password change is an authorisation decision rather than an attribute update, which is why it is not part of `PUT /drivers/:id` — that endpoint does not accept a password at all. Supplying the wrong `current_password` is refused and changes nothing.

Every other session is revoked when the password changes, and a fresh token is returned in the same response, so the caller keeps working while other devices are signed out.
url: "{{base_url}}/{{namespace}}/drivers/:id/change-password"
method: POST
pathVariables:
- key: id
value: "{{driver_id}}"
description: (Required) The driver whose password is being changed.

body:
type: json
content: |-
{
"current_password": "{{driver_password}}",
"password": "{{driver_new_password}}",
"password_confirmation": "{{driver_new_password}}",
"device_name": "navigator"
}

scripts:
- type: afterResponse
code: |-
// The password in force has changed, so anything authenticating later
// must use the new one.
if (pm.response.code === 200) {
pm.environment.set("driver_password", pm.variables.get("driver_new_password"));
}
language: text/javascript

order: 4200
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ body:
{
"name": "John Doe",
"email": "{{$randomEmail}}",
"phone": "{{$randomPhoneNumber}}"
"phone": "{{$randomPhoneNumber}}",
"password": "{{driver_seed_password}}"
}
scripts:
- type: afterResponse
Expand All @@ -21,6 +22,19 @@ scripts:

cv.set("driver_id", json_response.id);
cv.set("driver_name", json_response.name);

// The email and phone are generated inline, so the response is the only
// place they can be read back. Without them the password and login
// requests below have no identity to use.
cv.set("driver_email", json_response.email);
cv.set("driver_phone", json_response.phone);
cv.set("driver_identity", json_response.email);

// Tracks the password currently in force, so Change Driver Password can
// prove the old one and later requests still know what it is.
// pm.variables resolves across scopes; the seed is a collection variable,
// which pm.environment cannot see.
cv.set("driver_password", pm.variables.get("driver_seed_password"));
language: text/javascript
examples: ./.resources/Create a Driver.resources/examples
order: 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$kind: queryParams
fields:
- name: status
type: string
required: false
description: Comma separated statuses to include, such as `pending,in_progress`.
- name: on
type: string
required: false
description: Only manifests scheduled on this date, as `YYYY-MM-DD`.
- name: limit
type: integer
required: false
description: Maximum manifests to return. Defaults to 30.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
$kind: http-request
name: "List Driver Manifests"
description: |-
Lists the manifests assigned to a driver, newest first.

A manifest is a driver's route: an order-agnostic sequence of stops which may span several orders, or none the driver has seen as an order.

Defaults to a recent window rather than the driver's whole history. Use `status` and `on` to narrow it further.
url: "{{base_url}}/{{namespace}}/drivers/:id/manifests"
method: GET
pathVariables:
- key: id
value: "{{driver_id}}"
description: (Required) The driver whose manifests to list.

scripts:
- type: afterResponse
code: |-
// Captures a manifest for the Manifests folder to address. On an instance
// with no routes assigned this simply finds nothing, and those requests
// skip themselves.
if (pm.response.code === 200) {
const body = pm.response.json();
const rows = Array.isArray(body) ? body : (body.data || []);

if (rows.length) {
pm.environment.set("manifest_id", rows[0].id);
}
}
language: text/javascript

order: 4500
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$kind: params
fields:
- name: identity
type: string
required: true
description: The driver's email address or phone number.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
$kind: http-request
name: "Request Driver Password Reset"
description: |-
Sends a password reset code to a driver who cannot sign in.

The code goes by email or SMS depending on whether `identity` looks like an email address or a phone number.

The response is the same whether or not the identity belongs to a driver. That is deliberate: an endpoint that answered differently for an unknown number would be a way to enumerate an organization's drivers.

`driver_reset_identity` defaults to a reserved address that belongs to nobody, so running the collection documents the endpoint without sending mail to a stranger. Point it at a real driver to exercise delivery.
url: "{{base_url}}/{{namespace}}/drivers/forgot-password"
method: POST

body:
type: json
content: |-
{
"identity": "{{driver_reset_identity}}"
}

order: 4300
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$kind: params
fields:
- name: identity
type: string
required: true
description: The driver's email address or phone number — the same one the code was sent to.
- name: code
type: string
required: true
description: The verification code sent by `POST /drivers/forgot-password`.
- name: password
type: string
required: true
description: The new password. Must be at least 8 characters.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
$kind: http-request
name: "Reset Driver Password"
description: |-
Sets a new password using the code sent by `POST /drivers/forgot-password`.

A wrong code, an expired code and an unknown identity all return the same error, so the endpoint cannot be used to test which of the three happened.

Every session is revoked on success. A reset is a recovery from losing control of an account, so nothing that was signed in stays signed in.
url: "{{base_url}}/{{namespace}}/drivers/reset-password"
method: POST

body:
type: json
content: |-
{
"identity": "{{driver_email}}",
"code": "{{driver_password_reset_code}}",
"password": "{{driver_new_password}}"
}

scripts:
- type: beforeRequest
code: |-
// The reset code is delivered by email or SMS, so an automated run has no
// way to read it. Skipped rather than failed: the request is here to be
// documented and to work for anyone who sets `verification_code`, and a
// request that cannot succeed should not be reported as a broken endpoint.
const code = pm.environment.get("verification_code");
const unresolved = !code || /^\{\{.*\}\}$/.test(String(code));

if (unresolved && typeof pm.execution !== "undefined" && pm.execution.skipRequest) {
pm.execution.skipRequest();
}
language: text/javascript

order: 4400
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$kind: collection
description: |-
A manifest is a driver's route: an order-agnostic sequence of stops which may span several orders, or none the driver has seen as an order.

These endpoints are for the driver running the route. Creating, cancelling and deleting a manifest is dispatch work and is not part of the consumable API.
order: 8500
22 changes: 22 additions & 0 deletions postman/collections/Fleetbase API/Manifests/.resources/object.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
$kind: object
name: Manifest
description: |-
A route assigned to a driver for a day, made of ordered stops.
example: |
{
"id": "manifest_7KpQ2Rx9Vz",
"status": "in_progress",
"scheduled_date": "2026-08-23",
"started_at": "2026-08-23T07:12:04.000000Z",
"completed_at": null,
"total_distance_m": 41200,
"total_duration_s": 5400,
"stop_count": 8,
"completed_stops": 3,
"pending_stops": 5,
"driver_name": "Ron",
"vehicle_name": "EAS-01",
"notes": null,
"updated_at": "2026-08-23T09:02:00.000000Z",
"created_at": "2026-08-23T06:40:00.000000Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
$kind: params
fields:
- name: latitude
type: number
required: false
description: The driver's current latitude. The walk starts here when both coordinates are given.
- name: longitude
type: number
required: false
description: The driver's current longitude.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
$kind: http-request
name: "Optimize a Manifest"
description: |-
Re-sequences the stops a driver has not done yet, nearest first.

This is the driver's optimise, not the orchestrator's. The orchestrator allocates orders across a fleet and produces manifests; this reorders the stops of one manifest that is already assigned.

It is a nearest-neighbour walk over road distances: from the driver's position to the closest remaining stop, then the closest from there. That is usually a large improvement on an arbitrary order and is not guaranteed optimal.

Completed and skipped stops keep their place — a route already driven is not re-planned. A manifest with fewer than three stops still to do is returned unchanged, since there is no ordering to find.

Send `latitude` and `longitude` to start the walk from where the driver actually is. Without them it starts from the first stop still to do.
url: "{{base_url}}/{{namespace}}/manifests/:id/optimize"
method: POST
pathVariables:
- key: id
value: "{{manifest_id}}"
description: (Required) The manifest to re-sequence.

body:
type: json
content: |-
{
"latitude": 1.3521,
"longitude": 103.8198
}

scripts:
- type: beforeRequest
code: |-
// Manifests are produced by dispatch — the consumable API deliberately
// cannot create one — so a fresh instance has none to address. Skipped
// rather than failed: the request documents the endpoint and runs for
// anyone whose instance has a manifest, and a missing fixture is not an
// endpoint fault.
const id = pm.environment.get("manifest_id");
const unresolved = !id || /^\{\{.*\}\}$/.test(String(id));

if (unresolved && typeof pm.execution !== "undefined" && pm.execution.skipRequest) {
pm.execution.skipRequest();
}
language: text/javascript

order: 2000
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
$kind: http-request
name: "Retrieve a Manifest"
description: |-
Retrieves a manifest with its stops, in the sequence they are to be driven.

Each stop carries its place inline — a route of twenty stops is one request, not twenty-one — along with its status, estimated and actual arrival, and the distance and duration from the previous stop.
url: "{{base_url}}/{{namespace}}/manifests/:id"
method: GET
pathVariables:
- key: id
value: "{{manifest_id}}"
description: (Required) The manifest to retrieve.

scripts:
- type: beforeRequest
code: |-
// Manifests are produced by dispatch — the consumable API deliberately
// cannot create one — so a fresh instance has none to address. Skipped
// rather than failed: the request documents the endpoint and runs for
// anyone whose instance has a manifest, and a missing fixture is not an
// endpoint fault.
const id = pm.environment.get("manifest_id");
const unresolved = !id || /^\{\{.*\}\}$/.test(String(id));

if (unresolved && typeof pm.execution !== "undefined" && pm.execution.skipRequest) {
pm.execution.skipRequest();
}
language: text/javascript

order: 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
$kind: params
fields:
- name: status
type: string
required: false
description: One of `arrived`, `completed` or `skipped`. Anything else is refused.
- name: meta
type: object
required: false
description: Arbitrary metadata to store against the stop, such as a note left on arrival.
Loading
Loading