Skip to main content
Triage agent An agent working on threads subscribes to the events it cares about, decides whether to act, and uses the thread APIs to reply, update the thread, or hand it to a user. The customer sees the agent’s public name and avatar.

Permissions

Depending on what your agent does, you will need different permissions. Basic permissions most agents need are:
  • thread:read and customer:read
  • thread:reply to reply to threads
  • thread:edit to update the thread’s status
  • thread:assign and thread:unassign for handoffs
  • note:create if it leaves notes

Choose your events

Subscribe your webhook target to the events that should wake the agent: Two things to handle in every listener:
  • Your own actions come back as events. Skip messages whose author is your machine user.
  • The first email on a thread fires both thread.thread_created and thread.email_received. Check isStartOfThread on the email if you want to handle it once.

Assignment

Most agents act only on threads assigned to them. That keeps the decision of which threads the agent handles in Plain, where the team can see and change it. Assign in the UI, or with a workflow based on the thread’s channel, labels, tier, or support hours. You can also assign threads programmatically:
Assignment arrives as thread.thread_assignment_transitioned, with previousThread alongside thread. Every thread event also carries thread.assignee, so check it on message events too:
To hand off a thread, unassign the machine user or assign a different user. For an agent that never replies, such as a classifier or a note-writer, you can skip assignment and filter in the handler instead. For example, act on thread.thread_created only when thread.tier?.name is Premium.

Reading the thread

As with all of our GraphQL queries, you can selectively expand your query to include details you need such as customer, assignee, and labels. See the GraphQL SDK. Every timeline entry has llmText, Plain’s rendering of that entry for a language model. Concatenate them for a prompt-ready thread:
The llmText field is null for entries with no user or customer messages and can be skipped. You can also read thread.customer, thread fields, and the message directly from the webhook payload.

Replying

The replyToThread mutation automatically replies on the right channel (Chat, Email, Slack, MS Teams, etc.) based on the messages in the thread.
markdownContent is rendered in Plain, chat, and modern email. See reply to thread. textContent is the fallback for channels that don’t support markdown and multi-part emails. If you’d rather suggest a message for a user, you can use the suggest a reply mutation instead.

Updating the agent status

A thread’s agent status tells the team what the agent is doing with a thread, and tells Plain which threads to count in response time metrics.
If a user replies on a thread marked HANDLED or IN_PROGRESS, Plain sets HANDED_OFF itself. First Response, Next Response, and Investigating metrics only count HANDED_OFF threads.

Hand off

When the agent can’t help, hand the thread to a person in this order:
  1. Leave a note saying what it tried and why it stopped.
  2. Set agent status to HANDED_OFF.
  3. Unassign the thread, or assign it to a user with assignThread and a userId.
  4. Mark the thread as todo so it shows up in the queue.

Other mutations

Try any of them in the API explorer.