Bring your own agent is currently in beta and free to use.
1
Give the agent an identity
Create a machine user under Settings → Machine users & API Keys.This example reads a thread, replies, reports status, and can hand off. Click Add API key and grant:
thread:readthread:replyforreplyToThreadthread:editfor agent status, done, and todothread:assignandthread:unassigncustomer:read
/settings/machine-users/mu_…).2
Receive and verify events
Add an HTTPS
POST endpoint. Create a target under Settings → Webhooks (Add webhook target). Subscribe to thread.thread_assignment_transitioned and customer-message events such as thread.email_received. Copy the signing secret from Settings → Request signing (Workspace HMAC Secret). The webhook target has no secret.parsePlainWebhook skips the signature and checks shape only. See webhooks, request signing, and mTLS.3
Decide which threads it acts on
In the handler, run only when the thread is assigned to your machine user:Assign in the UI, or with a workflow under Settings → Workflows (channel, labels, customer tier, support hours). Workflows are UI-only. Assignment still arrives as
thread.thread_assignment_transitioned. The payload includes previousThread.Ignore events your agent caused. For message events, skip when the author is your machine user. After a handoff, the assignee is no longer you, so the filter drops it.4
Read the thread
thread:read. customer, assignee, and labels are lazy-loaded. See the GraphQL SDK.Concatenate llmText on timeline entries for a prompt-ready thread.llmText is null for entry types with nothing meaningful to render. Skip those entries.thread.customer, thread fields, or the message already on payloads such as thread.email_received. To search Help Center articles and indexed documents, see searching knowledge.5
Act on the thread
Reply with Always send both fields.
replyToThread (thread:reply). Works on API, CHAT, EMAIL, SLACK, and MS_TEAMS. Plain delivers on that channel as the machine user.textContent is the fallback; markdownContent is rendered in Plain, chat, and modern email. See reply to thread.6
Report agent status
HANDED_OFF threads.Caveats
If a user replies on a thread your agent markedHANDLED or IN_PROGRESS, Plain sets HANDED_OFF itself.
On failure: createNote, updateThreadAgentStatus(HANDED_OFF), unassignThread, then markThreadAsTodo.
Also useful
Suggest a reply withaddGeneratedReply (generatedReply:create). The customer sees nothing until a user sends it. Once you’ve suggested a reply on a thread, Ari stops drafting its own suggestions there. markdown max 5,000 characters. timelineEntryId must be a message from the customer or from a machine user (for example payload.email.timelineEntryId). See suggested replies.
removeLabels takes label IDs, not label type IDs. See labels.
thread.thread_created, thread.chat_received, thread.slack_message_received, thread.thread_status_transitioned. thread.thread_created plus thread.email_received fires twice for the first email; use isStartOfThread if you want one of them.
API explorer

