diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..59dc90b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@fleetbase/postman", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@fleetbase/postman", + "version": "0.1.0", + "license": "Apache-2.0" + } + } +} diff --git a/postman/collections/Fleetbase API/.resources/definition.yaml b/postman/collections/Fleetbase API/.resources/definition.yaml index 4d7e587..4c399b3 100644 --- a/postman/collections/Fleetbase API/.resources/definition.yaml +++ b/postman/collections/Fleetbase API/.resources/definition.yaml @@ -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: | diff --git a/postman/collections/Fleetbase API/Drivers/Change Driver Password.params.yaml b/postman/collections/Fleetbase API/Drivers/Change Driver Password.params.yaml new file mode 100644 index 0000000..f365666 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Change Driver Password.params.yaml @@ -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`. diff --git a/postman/collections/Fleetbase API/Drivers/Change Driver Password.request.yaml b/postman/collections/Fleetbase API/Drivers/Change Driver Password.request.yaml new file mode 100644 index 0000000..054e432 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Change Driver Password.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Drivers/Create a Driver.request.yaml b/postman/collections/Fleetbase API/Drivers/Create a Driver.request.yaml index d4ce836..08e6c1b 100644 --- a/postman/collections/Fleetbase API/Drivers/Create a Driver.request.yaml +++ b/postman/collections/Fleetbase API/Drivers/Create a Driver.request.yaml @@ -11,7 +11,8 @@ body: { "name": "John Doe", "email": "{{$randomEmail}}", - "phone": "{{$randomPhoneNumber}}" + "phone": "{{$randomPhoneNumber}}", + "password": "{{driver_seed_password}}" } scripts: - type: afterResponse @@ -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 diff --git a/postman/collections/Fleetbase API/Drivers/List Driver Manifests.queryParams.yaml b/postman/collections/Fleetbase API/Drivers/List Driver Manifests.queryParams.yaml new file mode 100644 index 0000000..e871347 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/List Driver Manifests.queryParams.yaml @@ -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. diff --git a/postman/collections/Fleetbase API/Drivers/List Driver Manifests.request.yaml b/postman/collections/Fleetbase API/Drivers/List Driver Manifests.request.yaml new file mode 100644 index 0000000..5a88ea9 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/List Driver Manifests.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.params.yaml b/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.params.yaml new file mode 100644 index 0000000..256f89e --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.params.yaml @@ -0,0 +1,6 @@ +$kind: params +fields: + - name: identity + type: string + required: true + description: The driver's email address or phone number. diff --git a/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.request.yaml b/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.request.yaml new file mode 100644 index 0000000..803dae8 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Request Driver Password Reset.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Drivers/Reset Driver Password.params.yaml b/postman/collections/Fleetbase API/Drivers/Reset Driver Password.params.yaml new file mode 100644 index 0000000..da8fb06 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Reset Driver Password.params.yaml @@ -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. diff --git a/postman/collections/Fleetbase API/Drivers/Reset Driver Password.request.yaml b/postman/collections/Fleetbase API/Drivers/Reset Driver Password.request.yaml new file mode 100644 index 0000000..538b435 --- /dev/null +++ b/postman/collections/Fleetbase API/Drivers/Reset Driver Password.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Manifests/.resources/definition.yaml b/postman/collections/Fleetbase API/Manifests/.resources/definition.yaml new file mode 100644 index 0000000..617546e --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/.resources/definition.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Manifests/.resources/object.yaml b/postman/collections/Fleetbase API/Manifests/.resources/object.yaml new file mode 100644 index 0000000..1a7ba5d --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/.resources/object.yaml @@ -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" + } diff --git a/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.params.yaml b/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.params.yaml new file mode 100644 index 0000000..8f30b0d --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.params.yaml @@ -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. diff --git a/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.request.yaml b/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.request.yaml new file mode 100644 index 0000000..9dd1686 --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/Optimize a Manifest.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Manifests/Retrieve a Manifest.request.yaml b/postman/collections/Fleetbase API/Manifests/Retrieve a Manifest.request.yaml new file mode 100644 index 0000000..1511d53 --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/Retrieve a Manifest.request.yaml @@ -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 diff --git a/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.params.yaml b/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.params.yaml new file mode 100644 index 0000000..d5775bd --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.params.yaml @@ -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. diff --git a/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.request.yaml b/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.request.yaml new file mode 100644 index 0000000..f8e20c4 --- /dev/null +++ b/postman/collections/Fleetbase API/Manifests/Update a Manifest Stop.request.yaml @@ -0,0 +1,39 @@ +$kind: http-request +name: "Update a Manifest Stop" +description: |- + Marks a stop on a manifest as arrived, completed or skipped. + + Status changes run through the manifest's own transitions rather than writing a column, so arrival and completion timestamps are recorded and a manifest completes itself when its last stop does. + + Any other status is refused and changes nothing. +url: "{{base_url}}/{{namespace}}/manifest-stops/:id" +method: PATCH +pathVariables: + - key: id + value: "{{manifest_stop_id}}" + description: (Required) The stop to update. + +body: + type: json + content: |- + { + "status": "arrived" + } + +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_stop_id"); + const unresolved = !id || /^\{\{.*\}\}$/.test(String(id)); + + if (unresolved && typeof pm.execution !== "undefined" && pm.execution.skipRequest) { + pm.execution.skipRequest(); + } + language: text/javascript + +order: 3000