Skip to content

Answer your first thread

Seven steps from an empty product to a ticket a specialist has replied to.

The shortest path from a product with Support available to a thread that has been answered. It takes seven steps and configures nothing beforehand: the status dictionary seeds itself the first time you read it.

Every step here is an MCP tool call. The same operations exist over the REST API under /support, and the same work is done by hand in the Workspace app — Support is headless and has no screens of its own, so there is no Product App page to open instead.

Nothing in this guide involves an end user’s Lessly account, because there is no such thing. user_8842 below is an identifier from your own user base: Support stores it verbatim and resolves nothing about it.

1. Read the status dictionary

support_status_list

A product that has never touched its settings gets four statuses seeded on this first call:

{
  "statuses": [
    { "id": "b48d8d0d…", "name": "open", "color": "#2563eb", "order": 0, "category": "open", "archived": false },
    { "id": "87e60f77…", "name": "pending", "color": "#d97706", "order": 1, "category": "pending", "archived": false },
    { "id": "d6284a3e…", "name": "resolved", "color": "#16a34a", "order": 2, "category": "resolved", "archived": false },
    { "id": "4463741a…", "name": "closed", "color": "#6b7280", "order": 3, "category": "closed", "archived": false }
  ]
}

Keep the open and pending ids: you need them in step 5.

The name is what people see and you may change it. The category is what Support itself reads, and it is fixed once threads sit on the status. More in Statuses.

2. Create the agent who will answer

An agent is the profile an end user sees next to a reply. It is Support’s own entity, not a projection of a Lessly account.

support_agent_create

{ "displayName": "Maria", "title": "Support engineer" }
{
  "id": "13c893aa…",
  "displayName": "Maria",
  "title": "Support engineer",
  "avatarUrl": null,
  "lesslyUserId": null,
  "isActive": true
}

lesslyUserId is optional and left empty here. Bind it when a human should sign into the Workspace app and work as this profile; leave it out for a bot or for your own backend, which replies exactly the same way. More in Agents.

3. Open a thread on behalf of an end user

support_thread_create

{
  "type": "ticket",
  "title": "Cannot upload my avatar",
  "authorExternalId": "user_8842",
  "authorDisplay": "Alex Fern"
}
{
  "id": "b50f26b4…",
  "type": "ticket",
  "title": "Cannot upload my avatar",
  "status": { "name": "open", "category": "open" },
  "priority": "normal",
  "authorExternalId": "user_8842",
  "authorDisplay": "Alex Fern",
  "assignedAgentId": null,
  "labels": [],
  "lastReplyAt": null
}

type is ticket when the end user wants something fixed and feedback when the input is unsolicited. There is no status argument: the thread opens on the product’s default open status — the non-archived open-category status with the lowest display order. More in Threads and messages.

4. Put the thread on an agent

support_thread_assign

{ "id": "b50f26b4…", "agentId": "13c893aa…" }

The thread comes back with assignedAgentId set. Passing null instead returns it to the unassigned queue, which is an ordinary move rather than an error.

5. Write the conversation

The end user’s own words go in as an inbound message, through support_message_create:

{
  "threadId": "b50f26b4…",
  "direction": "inbound",
  "authorExternalId": "user_8842",
  "body": "The upload button does nothing when I pick a PNG."
}

Maria’s answer is outbound and authored by the agent:

{
  "threadId": "b50f26b4…",
  "direction": "outbound",
  "authorAgentId": "13c893aa…",
  "body": "Thanks for the report. Which browser are you on?"
}

Exactly one of the two author fields is set on each message — never both and never neither. Both messages come back with "visibility": "public", which is the default; an internal note is stored the same way and is never shown to the end user.

6. Park the thread, and watch it come back

Maria is waiting on the customer, so the thread moves to pending with support_thread_status_set:

{ "id": "b50f26b4…", "statusId": "87e60f77…" }

Any status may follow any other — there are no transition rules, and the category is never a parameter: it comes from the status the thread lands on.

Then the customer answers:

{
  "threadId": "b50f26b4…",
  "direction": "inbound",
  "authorExternalId": "user_8842",
  "body": "Firefox 141 on Windows."
}

Read the thread back with support_thread_get:

{
  "id": "b50f26b4…",
  "status": { "id": "b48d8d0d…", "name": "open", "category": "open" },
  "assignedAgentId": "13c893aa…",
  "lastReplyAt": "2026-08-19T17:11:32.344Z"
}

Nobody moved it. A public inbound message on a thread parked in the pending category pulls that thread back to open — the one automatic transition Support has. It reads the category and not the name, so renaming pending to “waiting on customer” keeps it working. An internal note does not trigger it, and neither does an outbound message.

7. Read the queue and the conversation

The thread now sits in the open queue. support_thread_list:

{ "category": "open", "limit": 2 }

Threads come back newest first, and every filter lives on this call: type, status, status category, assignee, external author, labels, creation window.

The conversation itself reads forward, oldest first. support_message_list:

{ "threadId": "b50f26b4…", "visibility": "public" }

Asking for public returns what the end user would see. Omit visibility and public messages and internal notes come back together.

What you just did

The product now has a seeded status dictionary, one agent profile, and one ticket that was opened on behalf of an external end user, assigned, answered, parked and reopened by the customer’s own reply.

What to do next

Was this page helpful?
Esc

Start typing to search the docs.

navigateselect