Statuses
A dictionary your product owns, four categories Support reads, and one automatic move.
A status is where a thread sits. Support does not fix the list: your product owns its own dictionary, and every status in it carries a category that Support reads instead of the name.
Names are yours, categories are ours
A status has a name your customers and specialists see, unique within the product, one to a hundred characters. It has a color — a six-digit hex string such as #2563eb — and an order, the position it takes in the dictionary, lowest first.
It also has a category, and there are exactly four: open, pending, resolved, closed. This is the level Support itself understands. The queue filter groups by it, the one piece of automation Support has keys off it, and nothing anywhere reads a status name.
That split is the point of the dictionary. Rename pending to “waiting on customer”, split open into “triage” and “in progress”, add “won’t fix” in the closed category — none of it changes behaviour, because behaviour was never attached to the names.
The seeded default set
A thread cannot exist without a status, and Support gets no hook to run when a product starts using it. So the dictionary seeds itself the first time it is read: support_status_list on a product that has never touched its settings creates four statuses, one per category, and returns them.
| Name | Category | Colour | Order |
|---|---|---|---|
open | open | #2563eb | 0 |
pending | pending | #d97706 | 1 |
resolved | resolved | #16a34a | 2 |
closed | closed | #6b7280 | 3 |
Seeding is idempotent and safe under concurrency: two calls racing on a fresh product still produce one set of four.
support_status_list returns the dictionary in display order — by order, ties broken by name — and hides archived statuses unless includeArchived is set.
Adding and editing
support_status_create takes all four fields; none is optional, because a status with no colour or no position has nowhere to render. A duplicate name in the same product is a conflict.
support_status_update changes name, color, order — and category, but only while no thread references the status. Once threads sit on it the category is frozen, and asking to change it is refused as a conflict naming the status. The reason is history: the category is what every metric is derived from, so re-categorising a status in use would silently rewrite what those metrics said about the past. The way forward is to create a status in the category you want and move the threads to it.
Order is a plain integer you set; Support does not renumber the others for you, and duplicate orders are legal — they simply fall back to sorting by name.
Retiring one
There is no delete. A status that threads sit on cannot be made to vanish without deciding what happens to those threads, so the only way out is support_status_archive, and it takes that decision as an argument:
{ "id": "d6284a3e…", "targetStatusId": "4463741a…" }Every thread on the archived status moves to the target in the same transaction that flips the flag, so there is no moment at which a thread points at an archived status. The target must be a different status of this product, and it must itself be live — archiving into an archived status is refused.
An archived status stays readable, so old threads and reports still render its name, and it is refused as a destination from then on.
The one automatic transition
Support moves a thread by itself exactly once.
A public inbound message posted to a thread whose status is in the pending category pulls that thread back onto the product’s default open status — the non-archived open-category status with the lowest order. The move happens in the same transaction as the message, so a thread is never left one without the other.
Each of the three conditions is doing work:
- Inbound, because the rule is “the customer came back”. An outbound message is the support side talking, which is usually what put the thread on
pendingin the first place. - Public, because an internal note is invisible to the end user and therefore no evidence that they replied.
pendingcategory, because a thread anywhere else is not this rule’s business. Anopenthread stays on whicheveropen-category status it is on, custom or not; aresolvedorclosedthread is not reopened by a reply.
It reads the category, never the name — so the rule survives renaming pending to anything you like, and it applies to every pending-category status you invent, not only the seeded one.
Everything else is a deliberate move. support_thread_status_set takes the destination and nothing more:
{ "id": "b50f26b4…", "statusId": "87e60f77…" }There are no transition rules: any status may follow any other, in any order, and a thread may go back and forth. The category is never a parameter — it is a property of the status the thread lands on, and accepting it separately would let a caller assert a category the status does not have. A status of another product is reported as not found; an archived one is refused.
Where to go next
- Threads and messages: the threads that sit on these statuses.
- Notifications: why a status change is not worth a bell.
- Tools, SDK and errors: every tool named here, and how it is called.