Skip to main content

Documentation 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.

The Ticket API powers the end-to-end support workflow for water dispenser incidents. Tickets are created by any authenticated user who spots a problem, automatically assigned SLA deadlines based on the client’s configuration, and then routed through a OPEN → IN_PROGRESS → RESOLVED → CLOSED lifecycle. The system emits push notifications (via OneSignal) and emails at key transition points. Data-scope filtering is applied automatically per role: technicians see only tickets assigned to them; CLIENT_REQUESTER users see tickets from their plants plus any ticket they personally reported; higher roles see all tickets within their data scope.

GET /api/tickets

Returns a paginated list of tickets matching the supplied filters, ordered by priority (descending) then createdAt (descending). Required permission: tickets:read

Query parameters

status
TicketStatus
Filter by status. Accepted values: OPEN, IN_PROGRESS, RESOLVED, CLOSED.
priority
TicketPriority
Filter by priority. Accepted values: LOW, MEDIUM, HIGH, CRITICAL.
assignedToId
string
Filter tickets assigned to a specific user ID.
dispenserId
string
Filter tickets linked to a specific dispenser ID.
slaStatus
string
SLA health filter. Accepted values:
  • BREACHEDslaResolutionBreached is true.
  • NEAR_BREACH — resolution deadline is within the next 2 hours and the ticket is not closed.
  • ON_TIME — no SLA filter (returns all SLA-healthy tickets).
page
number
Page number (1-indexed). Defaults to 1.
limit
number
Results per page. Defaults to 50.

Response fields

tickets
Ticket[]
Array of ticket objects. Each ticket includes a nested dispenser (id, marca, modelo, status), location (with plant and client name), reportedBy (nombre, role), assignedTo (nombre), and a _count.comments integer.
total
number
Total number of matching tickets across all pages.
page
number
Current page number, echoed from the request.
limit
number
Page size, echoed from the request.

Example

curl -X GET "https://your-domain.com/api/tickets?status=OPEN&priority=HIGH&page=1&limit=20" \
  -H "Cookie: sb-access-token=<token>"
{
  "tickets": [
    {
      "id": "clx1a2b3c4d5e",
      "reason": "No dispensa agua fría",
      "priority": "HIGH",
      "status": "OPEN",
      "slaResolutionDeadline": "2024-06-01T18:00:00.000Z",
      "slaResolutionBreached": false,
      "dispenser": { "id": "DISP-042", "marca": "Acuaservice", "modelo": "Pro 600", "status": "IN_SERVICE" },
      "location": { "nombre": "Comedor", "plant": { "nombre": "Planta Norte", "client": { "nombre": "Empresa SA" } } },
      "reportedBy": { "nombre": "Ana García", "role": "CLIENT_REQUESTER" },
      "assignedTo": null,
      "_count": { "comments": 0 }
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20
}

Error cases

StatusDescription
401Missing or invalid authentication session.
403Caller lacks tickets:read.

POST /api/tickets

Creates a new support ticket. SLA response and resolution deadlines are automatically calculated from the client’s SlaConfig based on the resolved location and requested priority. Supervisors and admins receive an in-app notification and a push notification (OneSignal) immediately after creation. Supports idempotency via an Idempotency-Key request header. Required permission: tickets:write

Request body

reason
string
required
Short description of the problem (displayed as the ticket title).
dispenserId
string
ID of the affected dispenser. If locationId is not provided, the dispenser’s current location is used automatically.
locationId
string
ID of the affected location. Overrides automatic location resolution from dispenserId.
description
string
Extended description of the issue.
priority
TicketPriority
Ticket priority. Accepted values: LOW, MEDIUM, HIGH, CRITICAL. Defaults to MEDIUM.
wantsPushNotifications
boolean
If true, the reporter opts in to push notifications for status updates on this ticket.
wantsEmailNotifications
boolean
If true, the reporter opts in to email notifications for status updates on this ticket.

Response fields

id
string
Generated ticket ID (CUID).
reason
string
Ticket reason as submitted.
priority
TicketPriority
Resolved priority.
status
string
Always OPEN on creation.
slaResponseDeadline
string | null
ISO 8601 response deadline derived from the client’s SLA config.
slaResolutionDeadline
string | null
ISO 8601 resolution deadline derived from the client’s SLA config.
dispenser
object
Nested dispenser object (id, marca, modelo) if dispenserId was provided.
location
object
Nested location object with plant.nombre if a location was resolved.
createdAt
string
ISO 8601 creation timestamp.

Example

curl -X POST "https://your-domain.com/api/tickets" \
  -H "Cookie: sb-access-token=<token>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ticket-disp042-20240601-001" \
  -d '{
    "dispenserId": "DISP-042",
    "reason": "No dispensa agua fría",
    "description": "El compresor parece no encender. El agua sale a temperatura ambiente.",
    "priority": "HIGH",
    "wantsEmailNotifications": true
  }'
{
  "id": "clx1a2b3c4d5e",
  "reason": "No dispensa agua fría",
  "description": "El compresor parece no encender. El agua sale a temperatura ambiente.",
  "priority": "HIGH",
  "status": "OPEN",
  "slaResponseDeadline": "2024-06-01T12:00:00.000Z",
  "slaResolutionDeadline": "2024-06-01T18:00:00.000Z",
  "slaResponseBreached": false,
  "slaResolutionBreached": false,
  "wantsEmailNotifications": true,
  "dispenser": { "id": "DISP-042", "marca": "Acuaservice", "modelo": "Pro 600" },
  "location": { "nombre": "Comedor", "plant": { "nombre": "Planta Norte" } },
  "createdAt": "2024-06-01T10:00:00.000Z"
}

Error cases

StatusDescription
400reason is missing or blank.
401Missing or invalid authentication session.
403Caller lacks tickets:write.

GET /api/tickets/{id}

Retrieves a single ticket with full relational detail. Required permission: tickets:read
CLIENT_REQUESTER users can fetch any ticket they reported, even if the dispenser is outside their normal plant scope.

Response fields

id
string
Ticket ID.
reason
string
Ticket title/reason.
description
string | null
Extended description.
priority
TicketPriority
Current priority.
status
TicketStatus
Current status.
dispenser
object
Nested dispenser with its current location (including plant, client, and sector).
location
object
Direct ticket location with nested plant, client, and sector.
reportedBy
object
Reporter details: id, nombre, role.
assignedTo
object | null
Assigned technician: id, nombre. null if unassigned.
comments
TicketComment[]
All comments ordered oldest-first, each with user.nombre, user.apellido, and user.role.
statusHistory
TicketStatusHistory[]
Full status change history ordered oldest-first, including fromStatus, toStatus, changedBy, changedAt, and notes.
slaResponseDeadline
string | null
SLA response deadline.
slaResolutionDeadline
string | null
SLA resolution deadline.
slaResponseBreached
boolean
Whether the response SLA was breached.
slaResolutionBreached
boolean
Whether the resolution SLA was breached.
respondedAt
string | null
Timestamp when the ticket first moved to IN_PROGRESS.
resolvedAt
string | null
Timestamp when the ticket was first moved to RESOLVED or CLOSED.

Example

curl -X GET "https://your-domain.com/api/tickets/clx1a2b3c4d5e" \
  -H "Cookie: sb-access-token=<token>"

Error cases

StatusDescription
401Missing or invalid authentication session.
403Caller lacks tickets:read or the ticket is outside their data scope.
404No ticket found with the given ID.

PUT /api/tickets/{id}

Updates a ticket’s status, assignment, priority, or a combination of these. Each status change creates a TicketStatusHistory record. SLA timestamps are tracked automatically:
  • Transitioning to IN_PROGRESS records respondedAt and checks the response SLA deadline.
  • Transitioning to RESOLVED or CLOSED records resolvedAt and checks the resolution SLA deadline.
  • Closing a ticket that was never RESOLVED triggers notifications to the reporter and all supervisors.
Required permissions:
  • tickets:write for status and priority changes.
  • tickets:assign to change assignedToId.
  • tickets:close to set status to CLOSED.
Technicians can only update tickets that are assigned to them. Attempting to update an unassigned or other-assigned ticket returns 403.

Request body

status
TicketStatus
New status. Accepted values: OPEN, IN_PROGRESS, RESOLVED, CLOSED.
assignedToId
string
User ID of the technician to assign. Pass null to unassign. Triggers a push notification and email to the assigned user.
priority
TicketPriority
Updated priority. Accepted values: LOW, MEDIUM, HIGH, CRITICAL.
notes
string
Optional notes to attach to the status history record (e.g. resolution summary).

Response fields

id
string
Ticket ID.
status
TicketStatus
Updated status.
assignedToId
string | null
Updated assignee ID.
priority
TicketPriority
Updated priority.
respondedAt
string | null
Set on the first IN_PROGRESS transition.
resolvedAt
string | null
Set on the first RESOLVED or CLOSED transition.
slaResponseBreached
boolean
Updated breach flag.
slaResolutionBreached
boolean
Updated breach flag.

Example

curl -X PUT "https://your-domain.com/api/tickets/clx1a2b3c4d5e" \
  -H "Cookie: sb-access-token=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "IN_PROGRESS",
    "assignedToId": "user-tech-007",
    "notes": "On-site visit scheduled for this afternoon"
  }'
{
  "id": "clx1a2b3c4d5e",
  "status": "IN_PROGRESS",
  "assignedToId": "user-tech-007",
  "priority": "HIGH",
  "respondedAt": "2024-06-01T11:30:00.000Z",
  "resolvedAt": null,
  "slaResponseBreached": false,
  "slaResolutionBreached": false,
  "updatedAt": "2024-06-01T11:30:00.000Z"
}

Error cases

StatusDescription
400status value is not a valid TicketStatus.
401Missing or invalid authentication session.
403Caller lacks the required permission, is a technician trying to update a ticket not assigned to them, or attempting to close without tickets:close.
404Ticket not found.

POST /api/tickets/{id}/comments

Adds a comment to an existing ticket. Returns the created comment with the author’s display name and role. Required permission: tickets:write

Request body

message
string
required
Comment text. Cannot be blank.

Response fields

id
string
Comment ID (CUID).
ticketId
string
Parent ticket ID.
userId
string
Author’s user ID.
message
string
Comment content.
createdAt
string
ISO 8601 creation timestamp.
user
object
Author details: nombre, apellido, role.

Example

curl -X POST "https://your-domain.com/api/tickets/clx1a2b3c4d5e/comments" \
  -H "Cookie: sb-access-token=<token>" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Visited on-site. Compressor capacitor replaced. Testing underway." }'
{
  "id": "clxcomment001",
  "ticketId": "clx1a2b3c4d5e",
  "userId": "user-tech-007",
  "message": "Visited on-site. Compressor capacitor replaced. Testing underway.",
  "createdAt": "2024-06-01T15:45:00.000Z",
  "user": {
    "nombre": "Carlos",
    "apellido": "López",
    "role": "TECHNICIAN"
  }
}

Error cases

StatusDescription
400message is missing or blank.
401Missing or invalid authentication session.
403Caller lacks tickets:write.

POST /api/tickets/{id}/repair

Records a completed repair against the ticket’s dispenser. The operation is performed in a single database transaction that:
  1. Optionally processes consumables/spare parts used during the repair, decrementing live inventory and writing DispenserConsumableHistory entries.
  2. Creates a DispenserRepairHistory entry linked to the dispenser.
  3. Posts an automatic comment summarising the repair.
  4. Advances the ticket status to RESOLVED and records resolvedAt.
Required permission: tickets:write
The ticket must have a dispenserId. Calling this endpoint on a ticket without an associated dispenser returns 400.

Request body

descripcion
string
required
Description of the problem that was repaired.
diagnostico
string
Technical diagnosis or root cause.
consumablesUsed
array
Consumables and spare parts consumed during the repair. Stock is deducted from the dispenser’s plant inventory.

Response fields

success
boolean
true when the repair was fully recorded and the ticket resolved.

Example

curl -X POST "https://your-domain.com/api/tickets/clx1a2b3c4d5e/repair" \
  -H "Cookie: sb-access-token=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "descripcion": "Compressor capacitor failure",
    "diagnostico": "Electrolytic capacitor degraded due to heat cycling. Replaced unit.",
    "consumablesUsed": [
      {
        "materialCode": "CAP-440V",
        "nombre": "Capacitor 440V 30µF",
        "cantidad": 1,
        "type": "BULK"
      }
    ]
  }'
{ "success": true }
If the dispenser’s plant has insufficient stock for any listed item, the entire transaction is rolled back. No repair history, no stock deduction, no ticket update. The response body will contain a descriptive error string.

Error cases

StatusDescription
400descripcion is missing, or the ticket has no associated dispenser.
401Missing or invalid authentication session.
403Caller lacks tickets:write.
404Ticket not found.
500Insufficient stock or unknown material code — the error message describes the specific item.

Build docs developers (and LLMs) love