Developer guide
Build an AI texting agent with human handoff
Give your agent a messaging API for sends and a webhook-driven backend for replies. Keep conversation ownership outside the model, so automated replies pause when a human takes over.
Separate transport, state and decisions
A phone-number API handles message transport. Your webhook receiver verifies events and writes them to durable state. A worker loads the conversation, decides whether automation is allowed, and creates a draft. The send action runs only after that policy check.
MCP lets an assistant call hosted tools, but an idle coding assistant does not wake automatically when a customer texts. Use an event-driven backend for a production responder.
Customer reply
> signed webhook > durable inbox > tenant/thread lookup
> ownership + opt-out check > agent draft > approval/send
Human takeover > owner=human > automated sends pauseMake human ownership a real state transition
Store owner=ai or owner=human alongside the thread. A handoff changes ownership before another automated send is permitted. Recheck ownership immediately before sending, not only when the draft was produced. Release the thread explicitly after the person finishes.
The runnable example demonstrates durable ownership and opt-out state through signed local events. Its admin endpoint is token-protected. It provides the backend boundary; choosing an LLM, helpdesk and user interface is left to your application.
Keep inbound text out of privileged control
Treat a customer reply as untrusted conversation content. It must not become a system instruction, a shell command, a new tenant identity or permission to message a different customer. Scope tools, restrict recipients and separate draft creation from send authorization.
A STOP reply in the sample prevents future automated responses for that conversation. A production implementation needs the appropriate opt-out and consent handling for its channels and destinations, including your human sending tools. The sample does not establish legal compliance.
Prove the conversation before scaling
Test an outbound message, inbound reply, automated draft, human takeover and a duplicate webhook. Confirm that takeover pauses sends and that retries cannot produce duplicates. Log message IDs and ownership transitions without storing API keys in logs.
API line claiming requires workspace approval and available inventory. A denied claim returns line_claim_not_allowed; unavailable inventory returns no_available_line.
Acceptance is not delivery. Delivery and read events depend on the channel, line, recipient, and available receipts. SMS does not provide read receipts.