
Permissions
Depending on what your agent does, you will need different permissions. Basic permissions most agents need are:thread:readandcustomer:readthread:replyto reply to threadsthread:editto update the thread’s statusthread:assignandthread:unassignfor handoffsnote:createif 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_createdandthread.email_received. CheckisStartOfThreadon 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:thread.thread_assignment_transitioned, with previousThread alongside thread. Every thread event also carries thread.assignee, so check it on message events too:
thread.thread_created only when thread.tier?.name is Premium.
Reading the thread
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:
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
ThereplyToThread 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.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:- Leave a note saying what it tried and why it stopped.
- Set agent status to
HANDED_OFF. - Unassign the thread, or assign it to a user with
assignThreadand auserId. - Mark the thread as todo so it shows up in the queue.
Other mutations
Try any of them in the API explorer.

