Logotipo Hedhog

Get Hedhog updates in your inbox

New releases, fresh recipes, and breaking changes — no spam.

sac Submodule

tickets

Owns the ticket lifecycle: creation from every channel, status transitions, assignment, SLA clock, satisfaction rating, and the public tracking page.

Source path: libraries/sac/src/ticket

Module file: ticket.module.ts

Introduction

Tickets are the centre of the module. Every entry point converges here: the public website form (`POST /sac/public/tickets`), an internal submission from another library, an agent opening a ticket in the admin panel, and the inbound channels (e-mail and WhatsApp).

The public tracking number lives in `protocol`, formatted `YYYYMM-NNNNNN` and generated by a Postgres default (`sac_next_protocol()`), not by application code — so two concurrent submissions can never collide on it. The sequence is global rather than per-month, so `202608-000004` means "the fourth ticket ever, created in August 2026".

The SLA clock is stored on the ticket itself (`first_response_due_at`, `resolution_due_at`, `paused_at`, `paused_ms`) and recomputed as the ticket moves. Moving to `waiting_customer` pauses it; a customer reply resumes it and shifts the deadlines by the elapsed pause, so time spent waiting on the customer never counts against the team.

`requester_email` is optional: a WhatsApp ticket has no e-mail, and the requester is identified by `requester_phone` instead. Duplicate submissions are collapsed through `dedupe_hash` within a configurable window, which is what makes a double-clicked contact form return the original protocol instead of opening a second ticket.

HTTP Endpoints

8 endpoints

Paginated ticket list with filters used by the list and board screens.

Query
page, pageSize, search, status, priority, category_id, assignee_user_id

Aggregate counters for the KPI row (open, overdue, unassigned, resolved).

Full ticket with requester, SLA state, category, channel and attachments.

Params
id (int)

Open a ticket from the admin panel, on the `admin` channel.

Body

FieldTypeRequiredNotes
requester_namestringyes
requester_emailstring (email)noOptional: a WhatsApp ticket is identified by phone instead
requester_phonestringno
subjectstringyes
descriptionstringyes
category_idintno
prioritylow | normal | high | urgentno

Move the ticket through the status machine, pausing or resuming the SLA clock as required.

Params
id (int)

Agent reply or internal note. A public reply is delivered through the ticket channel — e-mail, or WhatsApp when the channel is of kind whatsapp.

Params
id (int)

Body

FieldTypeRequiredNotes
body_htmlstringnoSanitized on write; plain `body` is derived from it
visibilitypublic | internalnoAn internal note is never delivered to the customer and never counts as the first response

Website contact form. Honeypot, optional CAPTCHA and a kill switch guard it.

Requester tracking page. The e-mail must match the ticket, otherwise the protocol alone would let anyone enumerate other people tickets.

Params
protocol
Query
email