The Dispenser API exposes every operation needed to manage the lifecycle of water dispenser units across a fleet. Dispensers move through a well-defined status machine — fromDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/GianlucaBessone/HDB-Service/llms.txt
Use this file to discover all available pages before exploring further.
BACKUP storage through IN_SERVICE deployment and back — and the routes below enforce all transition rules, lifecycle clock logic, and data-scope restrictions enforced by the caller’s role.
All endpoints require a valid Supabase Auth session cookie. Data-scope filtering is applied automatically: non-admin users only see dispensers whose owning plant or current location plant falls within their access set.
GET /api/dispensers
Returns a paginated list of active dispensers matching the supplied filters. Results are capped at 50 per request and ordered byupdatedAt descending.
Required permission: dispensers:read
Query parameters
Filter by dispenser status. Accepted values:
IN_SERVICE, UNDER_REPAIR, OUT_OF_SERVICE, BLOCKED, BACKUP, IN_TECHNICAL_SERVICE, BLOCKED_WAITING_OC.Case-insensitive substring search across
id, marca, modelo, and numeroSerie.Response fields
Array of dispenser objects. Each object includes the current
location (with nested plant and sector), the owner plant, and a _count.tickets integer.Total number of matching dispensers (useful for pagination).
Example
Error cases
| Status | Description |
|---|---|
401 | Missing or invalid authentication session. |
403 | Caller lacks the dispensers:read permission. |
POST /api/dispensers
Creates a new dispenser. Supports idempotency via anIdempotency-Key request header — submitting the same key twice returns the cached first response.
Required permission: dispensers:write
Request body
Globally unique dispenser identifier (user-defined, e.g.
"DISP-042"). Returns 409 if already taken.Brand / manufacturer name.
Model name or number.
Expected service life in months. Defaults to
60 (5 years) if omitted.Hardware serial number.
ISO 8601 purchase date (e.g.
"2023-06-15").Free-text notes.
ID of the owning plant. Assigns permanent ownership without deploying to a location.
Optional array of factory-installed consumables to record immediately.
Response fields
The created dispenser’s ID.
Always
BACKUP on creation — the dispenser begins in reserve until explicitly assigned to a location.Confirmed lifecycle duration.
ISO 8601 creation timestamp.
Example
Error cases
| Status | Description |
|---|---|
400 | id, marca, or modelo is missing or blank. |
401 | Missing or invalid authentication session. |
403 | Caller lacks the dispensers:write permission. |
409 | A dispenser with the given id already exists. |
GET /api/dispensers/{id}
Retrieves a single dispenser with full relational detail, including location history, repair history, consumable history, spare-part history, the last 12 maintenance schedules, and the 10 most recent tickets. Also returns two computed fields:lifecycleExpiration (the projected end-of-life date, adjusted for accumulated pause time) and lifecycleRemainingDays.
Required permission: dispensers:read
Response fields
Dispenser identifier.
Brand name.
Model name.
Current operational status.
Current location object including nested
plant (with client) and sector.Owner plant (
id, nombre, clientId).Up to 20 most recent location assignments, each with
location.plant.nombre and assignedBy.nombre.Up to 20 most recent repair records with
technician.nombre.Full consumable installation history, ordered newest-first.
Up to 20 spare-part replacement records.
Up to 12 most recent maintenance schedules with their checklists.
Up to 10 most recent tickets (
id, reason, priority, status, createdAt).{ tickets: number, repairHistory: number } — total counts for the full dataset.ISO 8601 projected expiration date, accounting for all accumulated pause time.
null if the lifecycle has not started.Days remaining until lifecycle expiration, clamped to
0. null if the lifecycle has not started.Example
Error cases
| Status | Description |
|---|---|
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:read or the dispenser is outside their data scope. |
404 | No dispenser found with the given ID. |
PUT /api/dispensers/{id}
Updates editable metadata fields on an existing dispenser. Only provided fields are changed; all others are left untouched. AnADMIN user may additionally set lifecycleStartDate if it has not been set yet.
Required permission: dispensers:write
Request body
New brand name.
New model name.
Updated service-life duration in months.
New serial number. Pass
null to clear.ISO 8601 purchase date. Pass
null to clear.Free-text notes. Pass
null to clear.Transfer ownership to a different plant. Pass
null to clear ownership.Set to
false to soft-delete the dispenser record.ISO 8601 date to manually set the lifecycle start. Admin-only and only applies when the lifecycle has not yet been started (i.e.
lifecycleStartDate is currently null). Pass null to clear.Example
Error cases
| Status | Description |
|---|---|
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:write. |
404 | Dispenser not found. |
POST /api/dispensers/{id}/assign
Assigns a dispenser to a physical location. Enforces the one active dispenser per location rule. Records a newDispenserLocationHistory entry and starts the lifecycle clock on first assignment. When the dispenser is coming from BACKUP status, any accumulated pause time is recorded and the clock resumes.
Required permission: dispensers:assign
Request body
ID of the target location. Must exist and be active.
Set to
true to override the conflict when the dispenser is already assigned elsewhere. The previous assignment is closed automatically.Response fields
Dispenser ID.
The newly assigned location ID.
Always
IN_SERVICE after a successful assignment.Set on first assignment; unchanged for subsequent reassignments.
Example
Error cases
| Status | Description |
|---|---|
400 | locationId is missing. |
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:assign. |
404 | Dispenser or location not found. |
409 | The location already has an active IN_SERVICE dispenser, or the dispenser is already assigned elsewhere and force was not set. |
PATCH /api/dispensers/{id}/status
Changes the operational status of a dispenser. Validates the transition and applies side effects:- →
BACKUP: lifecycle clock is paused (lifecyclePausedAtis set) and the dispenser is removed from its current location. - →
UNDER_REPAIR: dispenser is removed from its current location. - →
BLOCKED:reasonis required; email notifications are sent toCLIENT_RESPONSIBLEandCLIENT_REQUESTERusers mapped to the affected plant. BLOCKED→IN_SERVICE: requires the additionaldispensers:release_blockpermission.
This endpoint also accepts
PUT. PATCH and PUT are equivalent.dispensers:status (plus dispensers:release_block when unblocking)
Request body
Target status. Accepted values:
IN_SERVICE, UNDER_REPAIR, OUT_OF_SERVICE, BLOCKED, BACKUP, IN_TECHNICAL_SERVICE, BLOCKED_WAITING_OC.Human-readable reason for the change. Required when
status is BLOCKED.Response fields
Dispenser ID.
New status.
Populated when status is
BLOCKED; cleared on release.ISO 8601 timestamp of the block event.
Set when status transitions to
BACKUP.Example
Error cases
| Status | Description |
|---|---|
400 | status is missing, invalid, or BLOCKED was requested without a reason. |
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:status, or attempting to release a BLOCKED dispenser without dispensers:release_block. |
404 | Dispenser not found. |
POST /api/dispensers/{id}/set-repair
A convenience endpoint that transitions a dispenser directly toUNDER_REPAIR status, removes it from its current location, and writes an audit log entry — all in a single atomic transaction. Use this when a quick repair flag is needed without going through the full status endpoint.
Required permission: dispensers:write
Request body
This endpoint does not accept a request body.Response fields
true when the update was applied.Example
Error cases
| Status | Description |
|---|---|
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:write. |
404 | Dispenser not found. |
POST /api/dispensers/{id}/consumables/init
Initializes or replaces the consumables currently installed in a dispenser. Each item is processed against the plant’s live inventory: serialized consumables are marked inactive in stock; bulk consumables decrement the aggregate stock count. New items (flaggedisNew: true) can also be registered in the catalog and inventory in the same call.
If the dispenser has no owning plant (plantId is null), inventory interactions are skipped and the history records are still written.
Required permission: dispensers:write
Request body
Non-empty array of consumable entries to install.
Response fields
true when all items were processed and history records created.Example
Error cases
| Status | Description |
|---|---|
400 | items array is missing or empty. |
401 | Missing or invalid authentication session. |
403 | Caller lacks dispensers:write. |
404 | Dispenser not found. |
500 | Insufficient stock, unknown material code, or duplicate serial number — the error message describes the specific failure. |