curl. You build a maintenance-request workflow with four states, attach a resolution-notes form to the closing step, and then run a real ticket from new to resolved.
Every step also has a short Console alternative. See Ticketing in the Console for the full UI guide.
Before you start
Creating, assigning, and transitioning tickets needs only project membership.
1
Set environment variables
Successful responses use the envelope
{"ok": 1, "data": {...}}. Errors return {"ok": 0, "message": "…", "detail": "…"} with an HTTP 4xx or 5xx status.Console: you don’t need tokens. Sign in, open your project, and go to Operations → Ticketing.
2
Create the resolution-notes form
A catalog form is a JSON Schema plus bindings that copy submitted fields into the ticket. This one requires a The workflow refers to this form by
resolution string and writes it to metadata.resolution.name. Posting the same name again, or patching the form, creates version 2. A require_form with no version always uses the latest version. See Forms for pinning.Console: go to Ticketing → Forms, click New form, paste the YAML below, check Schema preview, then click Create form.
3
Validate the workflow
POST /ticket-workflows/validate checks a spec without saving it. Send the same {"workflow": {...}} body you will use to create it.A valid spec returns:
200, with valid: false and one entry per problem. For example, a typo "to": "resolvd" in the third transition returns:initial, every non-terminal label has an outgoing transition, and at least one path reaches a terminal label. See Workflows for the full rule list. A body that is not a parseable workflow (for example, a missing name or initial) returns HTTP 400 instead.Console: go to Ticketing → Workflows, click New workflow, open the YAML tab, paste the spec (the object inside
"workflow", written as YAML), and click Validate. A valid spec shows YAML OK. The Graph tab draws the states and transitions.4
Create the workflow
Post the same body to A new version starts inactive. Posting another spec with the same
/ticket-workflows. Capture two IDs from the response:name adds version 2 under the same workflow_def_id.Console: click Save in the workflow editor. Saving creates a draft version; the status line shows Not active yet.
5
Activate the version
Tickets can only be created on a workflow that has an active version. Activate by version ID:The response is the same version item with Each item has
"is_active": true. Activating a later version moves new tickets to it; tickets already open stay on the version they started on.Optionally, list the states the version created:id, label, system_class, color, is_initial, and is_terminal. new has "is_initial": true; resolved and cancelled have "is_terminal": true.Console: click Activate and confirm the dialog. The workflow now appears on Board.
6
Create a ticket
Use
workflow_def_id, not the version ID. Include a severity tag, because the workflow requires one on create.Ticket create and transition accept an
Idempotency-Key header. Send one when you retry so a timed-out request does not create a second ticket.Console: on Board, click New ticket, fill Title and Description, choose a value under Severity, and click Create. The Console’s Due date is stored as
metadata.due_at, not the API due_at field, so it does not start due-policy timers.7
Assign the ticket
The The ticket’s
in_progress → resolved transition permits ticket.assignee, so assign the ticket to yourself. Send exactly one of assigned_user_id or assigned_group_id.assigned_to is now your user ID. The user must be a member of the project. Assigning a user clears any group assignment, and the reverse. To undo, POST …/unassign with {"target": "user"}. You can also assign at create time with assigned_user_id or assigned_group_id. See Assignment & notifications.Console: there is no assign control. Pick people under Assign users when you create the ticket instead. That adds
user tags, and a ticket.assignee permit also accepts users tagged on the ticket, so the walkthrough still works.8
Start work: new → in_progress
Transition by the target label key:The call returns after the state change is saved, so a
GET right afterwards shows "system_class": "in_progress". Any on_enter / on_exit actions on the transition run afterwards in the background (see Automation). This workflow has none.Console: open the ticket and click Go next to
in_progress under Transitions, or drag the card to the in_progress column on Board.9
Resolve with the form: in_progress → resolved
This move requires the The payload is checked against the form schema, then the binding writes
resolution-notes form. Send its fields in form_payload:resolution into the ticket metadata. Nothing changes if any check fails:Console: click Go next to
resolved (or drag the card). The Transition form dialog (or Form required to move on the board) asks for resolution; fill it in and click Apply transition (or Move).10
Check the history and final state
List the transition history. Rows are newest first:Page with
limit (default 10, max 200) and page. Each row stores the submitted form_payload as payload.Then fetch the ticket:Console: the ticket moves to the resolved column, and Ticket detail shows Status
terminal_success. The Console has no transition-history view; use the API for the audit trail.Next steps
- Workflows: guards, permits, trigger intake, and due policy
- Forms: pinned versions, inline forms, and tag bindings
- Assignment & notifications: group assignment and ticket notification events
- Automation: HTTP and device RPC actions on transitions
- API reference: every ticketing endpoint
- Troubleshooting: common errors and fixes