Skip to content
Open
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
1 change: 1 addition & 0 deletions .postman/resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ localResources:
- ../postman/collections/Fleetbase Ledger API
- ../postman/collections/Fleetbase Storefront API
- ../postman/collections/Fleetbase Integrated Vendor Flow
- ../postman/collections/Fleetbase Pallet API
environments:
- ../postman/environments/local.environment.yaml
- ../postman/environments/qa.environment.yaml
Expand Down
44 changes: 44 additions & 0 deletions collections/apis/pallet-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Pallet API Collection

Reference collection for the Fleetbase Pallet consumable API — inventory and warehouse management.

## Variables

- `base_url`
- `namespace` (`v1`)
- `api_prefix` (`pallet`)
- `api_key`

## Auth

Requests inherit bearer token authentication from the collection. The middleware behind these
routes is named `AuthenticateOnceWithBasicAuth` but reads `Authorization: Bearer`, so HTTP basic
auth will not authenticate. Store real API keys locally or in Postman Vault.

## Coverage

The editable Postman Local Mode collection lives at `postman/collections/Fleetbase Pallet API`.
It uses `api_prefix=pallet` and `namespace=v1`, so URLs resolve as
`{{base_url}}/{{api_prefix}}/{{namespace}}/...`.

Thirteen resources: products, product variants, suppliers, warehouses, warehouse zones, bin
locations, inventory, stock adjustments, purchase orders, sales orders, stock transfers, batches
and audits.

## Running in order

The folders are ordered so a full run builds its own fixtures: a product, supplier and warehouse
are created first and their public ids captured into environment variables, then zones and bins,
then the orders and transfers that consume them. Requests that address a record created earlier
use those captured variables rather than hardcoded ids.

## What the API will not do

Four resources deliberately refuse writes, so there are no requests here for them:

- stock levels have no create, update or delete — stock follows from operations
- adjustments cannot be updated or deleted — correcting one means making another
- batches are read-only — a batch is produced by receiving stock
- audit entries are read-only — they are written by the system

Transfers follow the same principle: no settable status, only the transition endpoints.
17 changes: 17 additions & 0 deletions collections/apis/pallet-api/collection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type: collection
name: Pallet API
version: 1.0.0
description: Legacy single-file placeholder. The editable Postman Local Mode collection lives at postman/collections/Fleetbase Pallet API.
auth:
type: bearer
bearer:
- key: token
value: "{{api_key}}"
type: string
variables:
- key: base_url
value: "{{base_url}}"
- key: namespace
value: "{{namespace}}"
- key: api_prefix
value: pallet
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"postman:run:core": "./scripts/run-collection.sh 'postman/collections/Fleetbase Core API'",
"postman:run:storefront": "./scripts/run-collection.sh 'postman/collections/Fleetbase Storefront API'",
"postman:run:ledger": "./scripts/run-collection.sh 'postman/collections/Fleetbase Ledger API'",
"postman:run:pallet": "./scripts/run-collection.sh 'postman/collections/Fleetbase Pallet API'",
"postman:run:integrated-vendor": "./scripts/run-collection.sh 'postman/collections/Fleetbase Integrated Vendor Flow'"
},
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
$kind: collection
variables:
base_url: ""
namespace: v1
api_prefix: pallet
api_key: ""
scripts:
- type: http:afterResponse
code: |
// Baseline contract assertions for every request in this collection.
//
// Status is checked against an explicit list. `pm.expect(pm.response).to.be.ok`
// is chai's truthiness check on an object, so it passes for a 400 too and
// asserts nothing.
const expected = pm.request.method === 'POST' ? [200, 201, 202] : [200, 201, 202, 204];

pm.test(`${pm.info.requestName} responds 2xx`, function () {
pm.expect(pm.response.code, `got HTTP ${pm.response.code}`).to.be.oneOf(expected);
});

pm.test(`${pm.info.requestName} returns a JSON body`, function () {
pm.expect(pm.response.headers.get('Content-Type') || '').to.include('json');
pm.expect(() => pm.response.json(), 'body is not parseable JSON').to.not.throw();
});

// The Pallet consumable API reports failure as {"error": "..."}, so a 2xx
// carrying one is still a failure.
pm.test(`${pm.info.requestName} returns no error payload`, function () {
let body;
try { body = pm.response.json(); } catch (e) { return; }
if (body === null || typeof body !== 'object') { return; }
pm.expect(body.error === null || body.error === undefined,
`response carries an "error": ${JSON.stringify(body.error)}`).to.be.true;
});

// Public ids are the addressing scheme; a uuid in a response body means an
// internal identifier leaked into the consumable representation.
pm.test(`${pm.info.requestName} exposes no internal uuids`, function () {
let body;
try { body = pm.response.json(); } catch (e) { return; }
const keys = JSON.stringify(body).match(/"[a-z_]*uuid"/g) || [];
pm.expect(keys, `response carries uuid keys: ${keys.join(', ')}`).to.be.empty;
});
language: text/javascript
auth:
- id: 1be408ef-ea43-4cff-962a-fa7d6b7d7fbc
type: bearer
name: bearer auth
credentials:
token: "{{api_key}}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$kind: collection
description: |-
The operational audit trail, read only. Entries are written by the system as operations happen; one a consumer could author would not be a record of anything.
order: 2200
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
$kind: object
name: Audit
description: |-
An immutable record of an operation that took place.
example: |
{
"id": "audit_w4x5y6",
"object": "audit",
"event_type": "po_received",
"action": "received",
"type": "partial",
"reason": null,
"subject": "purchase_order_v4w5x6",
"subject_type": "PurchaseOrder",
"old_values": null,
"new_values": null,
"meta": { "order_number": "purchase_order_v4w5x6" },
"created_at": "2026-08-20T14:30:00Z"
}
fields:
- name: id
type: string
description: "Public identifier of the audit entry."
- name: event_type
type: string
description: "The kind of event recorded."
- name: subject
type: string
description: "Public id of the record the event happened to."
- name: subject_type
type: string
description: "Short type name of the subject, not the fully qualified class."
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$kind: params
fields:
- name: limit
type: integer
description: "Maximum records to return. Capped at 100, defaults to 30."
- name: offset
type: integer
description: "Records to skip before returning results."
- name: page
type: integer
description: "Page number, used in place of offset."
- name: sort
type: string
description: "Column to sort by, prefixed with - for descending."
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$kind: http-request
description: List audit entries
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/audits"
method: GET
headers:
- key: Accept
value: application/json
scripts:
- type: afterResponse
code: |
// Later requests address {{audit_id}}; nothing else sets it.
const body = pm.response.json();
const captured = body[0].id;
if (captured) { pm.environment.set("audit_id", captured); }
language: text/javascript
order: 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$kind: http-request
description: Retrieve an audit entry
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/audits/{{audit_id}}"
method: GET
headers:
- key: Accept
value: application/json
order: 1100
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$kind: collection
description: |-
Received lots, read only. A batch is produced by receiving stock, so one authored here would describe a lot that never arrived.
order: 2100
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
$kind: object
name: Batch
description: |-
A lot of stock received together.
example: |
{
"id": "batch_t1u2v3",
"object": "batch",
"batch_number": "B-1001",
"product": "product_a1b2c3",
"product_name": "Steel Shelving Bracket",
"received_quantity": 40,
"manufacture_date_at": "2026-07-01T00:00:00Z",
"expiry_date_at": "2027-07-01T00:00:00Z",
"created_at": "2026-08-19T11:00:00Z",
"updated_at": "2026-08-19T11:00:00Z"
}
fields:
- name: id
type: string
description: "Public identifier of the batch."
- name: batch_number
type: string
description: "Lot number."
- name: received_quantity
type: integer
description: "Quantity the batch arrived with. Not the quantity still on hand — that is on the stock record."
- name: expiry_date_at
type: timestamp
description: "Expiry date for the lot."
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$kind: params
fields:
- name: limit
type: integer
description: "Maximum records to return. Capped at 100, defaults to 30."
- name: offset
type: integer
description: "Records to skip before returning results."
- name: page
type: integer
description: "Page number, used in place of offset."
- name: sort
type: string
description: "Column to sort by, prefixed with - for descending."
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$kind: http-request
description: List batches
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/batches"
method: GET
headers:
- key: Accept
value: application/json
scripts:
- type: afterResponse
code: |
// Later requests address {{batch_id}}; nothing else sets it.
const body = pm.response.json();
const captured = body[0].id;
if (captured) { pm.environment.set("batch_id", captured); }
language: text/javascript
order: 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$kind: http-request
description: Retrieve a batch
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/batches/{{batch_id}}"
method: GET
headers:
- key: Accept
value: application/json
order: 1100
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$kind: collection
description: |-
Bins are the addressable positions stock is put away into. A bin's zone must belong to the same warehouse as the bin.
order: 1500
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
$kind: object
name: Bin Location
description: |-
An addressable position within a warehouse.
example: |
{
"id": "bin_m4n5o6",
"object": "bin_location",
"warehouse": "warehouse_x1y2z3",
"zone": "zone_j1k2l3",
"zone_name": "Receiving",
"bin_number": "A-01-01",
"is_pickable": true,
"is_replenishable": true,
"status": "active",
"created_at": "2026-08-02T10:05:00Z",
"updated_at": "2026-08-02T10:05:00Z"
}
fields:
- name: id
type: string
description: "Public identifier of the bin."
- name: warehouse
type: string
description: "Public id of the warehouse."
- name: zone
type: string
description: "Public id of the zone, when the bin sits in one."
- name: bin_number
type: string
description: "Human-readable bin address."
- name: is_pickable
type: boolean
description: "Whether stock can be picked from this bin."
- name: aisle
type: string
description: "Public id of the aisle, reported when the bin sits in the older hierarchy. Not settable here."
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
$kind: params
fields:
- name: warehouse
type: string
required: true
description: "Public id of the warehouse."
- name: zone
type: string
description: "Public id of a zone in that same warehouse. A zone from elsewhere is a 404."
- name: bin_number
type: string
required: true
description: "Human-readable bin address."
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
$kind: http-request
description: Create a bin location
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/bin-locations"
method: POST
headers:
- key: Accept
value: application/json
- key: Content-Type
value: application/json
body:
type: json
content: |-
{
"warehouse": "{{warehouse_id}}",
"zone": "{{zone_id}}",
"bin_number": "A-01-01"
}
scripts:
- type: afterResponse
code: |
// Later requests address {{bin_id}}; nothing else sets it.
const body = pm.response.json();
const captured = body.id;
if (captured) { pm.environment.set("bin_id", captured); }
language: text/javascript
order: 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$kind: params
fields:
- name: limit
type: integer
description: "Maximum records to return. Capped at 100, defaults to 30."
- name: offset
type: integer
description: "Records to skip before returning results."
- name: page
type: integer
description: "Page number, used in place of offset."
- name: sort
type: string
description: "Column to sort by, prefixed with - for descending."
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$kind: http-request
description: List bin locations
url: "{{base_url}}/{{api_prefix}}/{{namespace}}/bin-locations"
method: GET
headers:
- key: Accept
value: application/json
order: 1100
Loading
Loading