Skip to content

Answer your first thread

Create a support ticket, reply, and verify that a customer response reopens it.

Create an agent profile, open a ticket for a customer, and exchange three messages. This tutorial uses seven steps to show assignment and the automatic move from pending back to open.

Before you start

  • A Lepsto product with Support available. The tools take the product from your credentials; they have no product argument.
  • A platform identity with product-scoped read access for the reads and write access for the create, assignment, and status calls. An MCP agent needs a token granting these operations.
  • Access to the support_* MCP tools. The same operations are available through authenticated REST under /support and the generated support namespace in @lepsto/sdk-app. Your team can also work in the separate workspace Support App; Support has no Product App navigation entry.

A product public key cannot complete this tutorial: its API does not support assignment or status changes. See Public HTTP API for the backend integration path.

The example follows Alex Fern reporting an avatar-upload problem in your shop, with Maria answering. Replace user_8842, Alex Fern, and Maria with your own values. Replace every abbreviated id such as b50f26b4… with the full id returned by the relevant call. Response examples show the fields used in this tutorial.

Support stores authorExternalId verbatim. It does not resolve, normalize, or enrich the value, or link it to a Lepsto workspace identity or Lepsto Users account.

1. Read the status dictionary

support_status_list

On a new product, this call creates and returns four default statuses:

{
  "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 }
  ]
}

Save the pending id for step 6 and the open id for the final check.

Names are editable display text. Categories drive behavior and cannot change while threads reference the status. See Statuses.

2. Create the agent who will answer

Create the profile your customer will see beside the reply:

support_agent_create

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

Save the agent id. This example leaves lesslyUserId unset, as a backend or bot profile would. Bind it to a Lepsto identity when a person will answer through the Workspace app. Both profile types can reply. See 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; it cannot be changed afterwards. title runs 1–500 characters. 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…" }

Check that the response sets assignedAgentId to Maria’s agent id. Assignment requires an active agent; a deactivated profile is rejected. Set agentId to null to clear an assignment.

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?"
}

Set exactly one author field per message. A supplied body must contain 1–50,000 characters. For an attachment-only message, omit body; an empty string is rejected. These text examples have no attachments.

Both messages default to visibility: "public". Use internal for a note your product must not show to the customer.

6. Park the thread, and watch it come back

Maria is waiting on the customer, so move the thread to pending with support_thread_status_set, using the pending id from step 1:

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

The destination must be a live status; an archived one is rejected. Any live status can follow any other. The tool reads the category from the status you select.

Post the customer’s answer with support_message_create:

{
  "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"
}

The public inbound reply automatically moved the thread to the default open status. This works for every pending-category status, even if you rename it to “Waiting on customer”. Internal notes and outbound messages do not trigger the move.

7. Read the queue and the conversation

The thread now sits in the open queue. support_thread_list:

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

Threads return newest first, with a default page size of 25 and a maximum of 100. You can also filter by type, status, category, assignee, external author, labels, rating bounds, and creation window.

Read the conversation oldest first with support_message_list:

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

Keep the public filter when preparing a customer-facing conversation. Omitting visibility includes internal notes.

Check what you built

Verify the result with these reads:

  1. support_thread_get on your thread id returns status.category of "open", assignedAgentId equal to the agent id from step 2, and a lastReplyAt that is no longer null.
  2. support_message_list with that threadId and visibility: "public" returns the three messages you posted, oldest first: the customer’s report, Maria’s answer, the customer’s reply. Match them by body — a thread you opened in this run holds only these three, whatever else the product contains.
  3. support_agent_get on the agent id from step 2 returns displayName: "Maria" and isActive: true. Read it by id to identify the profile you created among any existing agents.

If status.category still reads "pending" after step 6, the message that should have reopened the thread was not both inbound and public — check direction and visibility on it.

What to do next

Was this page helpful?
Esc

Start typing to search the docs.

↑↓navigate↵select