Availability
Read-only availability queries for the rental availability engine.
Availability API
Read-only availability queries for the rental availability engine. Availability
is the quantity of a catalogue item that is free to book at a warehouse over time:
available = total_stock - total_demanded, and may be negative when demand
exceeds stock (a shortage).
The endpoint serves a two-tier read strategy:
- A point query (single
date) is computed on-the-fly from active demands — always live, no snapshot dependency. - A range query (
from+to) is read from pre-calculated availability snapshots, with acalculated_atfreshness marker so consumers know how current the data is.
Endpoints
| Method | URL | Description |
|---|---|---|
| GET | /api/v1/availability |
Availability for a catalogue item at a warehouse |
| GET | /api/v1/availability/calendar |
Multi-catalogue-item daily availability grid for a warehouse |
| GET | /api/v1/availability/{catalogue_item}/gantt |
Demand-bar Gantt for a single catalogue item at a warehouse |
| GET | /api/v1/availability/shortages |
Warehouse-wide shortage sweep over a date range |
| GET | /api/v1/catalogue_items/{catalogue_item}/availability |
Availability for a specific catalogue item |
| GET | /api/v1/catalogue_items/{catalogue_item}/available-assets |
Barcoded assets of a catalogue item free across a window |
Authentication
Requires a Sanctum bearer token with the availability:read ability, and the
availability.view permission.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
catalogue_item_id |
Yes (flat endpoint only) | The catalogue item to query. Supplied by the route on the nested endpoint. |
warehouse_id |
Yes | The warehouse to query. |
date |
One of date or from+to |
ISO date/time for a point query. |
from |
With to |
Range start (ISO) for a range query. |
to |
With from |
Range end (ISO) for a range query. |
date cannot be combined with from/to. Dates are aligned to the configured
availability resolution slot (daily, half-daily, or hourly) in the warehouse's local
timezone.
Point Query
GET /api/v1/availability?catalogue_item_id=5&warehouse_id=1&date=2026-07-02
Response
{
"availability": {
"catalogue_item_id": 5,
"warehouse_id": 1,
"date": "2026-07-02T00:00:00.000Z",
"total_stock": 10,
"total_demanded": 4,
"available": 6,
"demand_breakdown": {
"rental_item": 4
}
}
}
demand_breakdown reports the demanded quantity per source type (e.g.
rental_item, repair).
Range Query
GET /api/v1/availability?catalogue_item_id=5&warehouse_id=1&from=2026-07-01&to=2026-07-04
Response
{
"availability": {
"catalogue_item_id": 5,
"warehouse_id": 1,
"from": "2026-07-01T00:00:00.000Z",
"to": "2026-07-04T00:00:00.000Z",
"min_available": 6,
"max_available": 10,
"calculated_at": "2026-06-18T09:30:00.000Z",
"slots": [
{
"slot_start": "2026-07-01T00:00:00.000Z",
"total_stock": 10,
"total_demanded": 4,
"available": 6,
"demand_breakdown": { "rental_item": 4 }
}
]
}
}
slots contains one entry per resolution-aligned time slot in the range.
min_available / max_available summarise the range; calculated_at is the
oldest snapshot recalculation time in the range (null when no snapshots exist
yet for the range).
Available Assets (barcoded catalogue items)
For catalogue items tracked as barcoded (one physical unit per asset), list
the specific assets that are free for an entire window — i.e. no active demand
claims that asset over a period overlapping [from, to). A loose catalogue item has no
discrete assets and returns an empty collection; use the point/range endpoints
above for quantity-based reads.
GET /api/v1/catalogue_items/5/available-assets?warehouse_id=1&from=2026-07-02&to=2026-07-04
Query Parameters
| Parameter | Required | Description |
|---|---|---|
warehouse_id |
Yes | The warehouse to query. |
from |
Yes | Window start (ISO). |
to |
Yes | Window end (ISO), on or after from. |
Response
{
"available_assets": [
{
"id": 42,
"item_name": "Shure SM58",
"asset_number": "A-0042",
"serial_number": "SN-000042",
"barcode": null,
"location": "Bay 3"
}
],
"meta": { "total": 1, "per_page": 1, "page": 1 }
}
The overlap is evaluated against the demand period: on PostgreSQL via the native
tstzrange && operator (backed by the idx_demands_asset_period GiST index and
the excl_demands_asset_period exclusion constraint), and via a scalar
comparison on the SQLite test connection.
Calendar Grid
GET /api/v1/availability/calendar?warehouse_id=1&from=2026-07-01&to=2026-07-14
Returns the pre-calculated daily availability summary for all (or a filtered subset of) catalogue items at a warehouse over a date range. Each catalogue item row contains one entry per day with the available quantity, a shortage flag, and the pending check-in count. This drives the Equipment Availability calendar view.
Note: Kit and composed catalogue items whose availability is derived at read time (rather than from a demand snapshot) do not appear in the calendar grid. Use the point/range endpoints for those.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
warehouse_id |
Yes | The warehouse to query. |
from |
Yes | Start date (ISO). |
to |
Yes | End date (ISO, on or after from). |
catalogue_item_ids[] |
No | Array of catalogue item ids to narrow the result (omit for all catalogue items). |
Response
{
"calendar": {
"warehouse_id": 1,
"from": "2026-07-01T00:00:00+00:00",
"to": "2026-07-14T00:00:00+00:00",
"catalogue_items": [
{
"catalogue_item_id": 5,
"catalogue_item_name": "MegaPointe Moving Head",
"days": [
{
"date": "2026-07-01",
"available": 6,
"has_shortage": false,
"pending_checkin": 0
},
{
"date": "2026-07-02",
"available": -2,
"has_shortage": true,
"pending_checkin": 3
}
]
}
]
}
}
Gantt (demand bars for one catalogue item)
GET /api/v1/availability/{catalogue_item}/gantt?warehouse_id=1&from=2026-07-01&to=2026-07-14
Returns the individual demand bars for a single catalogue item at a warehouse, decomposed into their prep / on-hire / turnaround zones. Shortage windows are surfaced as a separate shortages array. This drives the per-catalogue-item Gantt timeline view.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
warehouse_id |
Yes | The warehouse to query. |
from |
Yes | Start date (ISO). |
to |
Yes | End date (ISO, on or after from). |
asset_ids[] |
No | Array of barcoded asset ids to narrow the result (omit for all assets). |
Response
{
"gantt": {
"catalogue_item_id": 5,
"warehouse_id": 1,
"from": "2026-07-01T00:00:00+00:00",
"to": "2026-07-14T00:00:00+00:00",
"total_stock": 10,
"demands": [
{
"demand_id": 42,
"asset_id": 7,
"asset_serial": "SN-0007",
"quantity": 1,
"source_type": "rental_item",
"source_id": 1001,
"source_name": "Corporate Conference 2026",
"colour": null,
"phase": "reserved",
"period_start": "2026-07-01T08:00:00Z",
"buffer_before_end": "2026-07-01T09:00:00Z",
"buffer_after_start": "2026-07-05T18:00:00Z",
"period_end": "2026-07-06T09:00:00Z",
"starts_at": "2026-07-01T09:00:00Z",
"ends_at": "2026-07-05T18:00:00Z"
}
],
"shortages": [
{
"from": "2026-07-02T00:00:00Z",
"to": "2026-07-04T00:00:00Z",
"severity": 2,
"in_buffer_zone": false
}
]
}
}
Each demand has:
| Field | Type | Description |
|---|---|---|
demand_id |
integer | Demand record id |
asset_id |
integer|null | Barcoded asset id (null for bulk-quantity demands) |
asset_serial |
string|null | Serial number of the asset |
quantity |
integer | Quantity demanded |
source_type |
string | Demand source type (e.g. rental_item) |
source_id |
integer | Source record id |
source_name |
string|null | Display name of the source (rental title) |
colour |
string|null | Optional display colour hint |
phase |
string | Current demand phase (e.g. reserved, on_hire) |
period_start |
string | Earliest boundary including prep buffer |
buffer_before_end |
string | End of the prep/turnaround-before zone |
buffer_after_start |
string | Start of the post-return turnaround zone |
period_end |
string | Latest boundary including post-return buffer |
starts_at |
string | Hire start (the on-hire window start) |
ends_at |
string | Hire end (the on-hire window end) |
Warehouse-Wide Shortages
GET /api/v1/availability/shortages?warehouse_id=1&from=2026-07-01&to=2026-07-14
Returns the pre-calculated shortage windows from the daily-summary read model — any day/catalogue-item/warehouse combination where available < 0. This drives the calendar shortage panel and dashboard shortage widget. Omit warehouse_id to sweep all warehouses.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
from |
Yes | Start date (ISO). |
to |
Yes | End date (ISO, on or after from). |
warehouse_id |
No | Narrow to a single warehouse. Omit to sweep all warehouses. |
Response
{
"shortages": [
{
"catalogue_item_id": 5,
"catalogue_item_name": "MegaPointe Moving Head",
"warehouse_id": 1,
"date": "2026-07-02",
"available": -2,
"severity": 2,
"calculated_at": "2026-06-18T09:30:00Z"
}
],
"meta": { "total": 1, "per_page": 50, "page": 1 }
}
severity is the absolute shortfall at its worst point on that day. calculated_at is the snapshot recalculation timestamp for that slot.
Error Cases
| Status | Condition |
|---|---|
| 401 | No valid Sanctum token |
| 403 | Token lacks availability:read, or user lacks availability.view |
| 422 | Missing warehouse_id/catalogue_item_id, no date or from+to, or date combined with from/to |
| 422 | Available-assets: missing warehouse_id, from, or to |
| 422 | Calendar/Gantt/Shortages: missing warehouse_id (where required), from, or to |