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/supportand the generatedsupportnamespace 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
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:
{ "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
{
"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
{ "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:
support_thread_geton your thread id returnsstatus.categoryof"open",assignedAgentIdequal to the agent id from step 2, and alastReplyAtthat is no longernull.support_message_listwith thatthreadIdandvisibility: "public"returns the three messages you posted, oldest first: the customer’s report, Maria’s answer, the customer’s reply. Match them bybody— a thread you opened in this run holds only these three, whatever else the product contains.support_agent_geton the agent id from step 2 returnsdisplayName: "Maria"andisActive: 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
- Threads and messages: filtering the queue, feedback threads and the product-wide catch-up read.
- Correct or remove a message: fixing a reply that went out wrong.
- Labels and attachments: tags, and sending a file with a message.
- Receive Support events: hearing about a reply without polling for it.