Build an agentiMessage API9 min read
Build an iMessage AI agent
How to build an AI agent on iMessage with Flow: webhook in, model call, tools, reply out. Memory, typing, tapbacks and testing included.

The short answer
An iMessage agent is a loop - an inbound event, a model call with your tools, a reply. The messaging layer should stay thin. Put your product's actions in tools you can reuse on other channels, and test conversations before real people see them.
Building on the iMessage API? Build on iMessage with Flow: one agent for iMessage, WhatsApp and Telegram. New to it? Read the iMessage API guide.
The loop
Every messaging agent is the same loop:
- Event in. Someone writes to your line. The provider posts a signed webhook, or you read it from a stream.
- Model call. Your code passes the conversation, your instructions and your tools to a model.
- Tools. The model asks to look up an order or move a booking. Your code runs the call against your real system and returns the result.
- Reply out. You send the answer back into the conversation.
The messaging layer only moves events in and replies out. The model and tools should not know whether the person is on iMessage, WhatsApp or Telegram. Here is the loop on Flow, with a tapback and a reply, from Flow’s iMessage docs:
// npm install @flow-engineer/messaging
import { FlowMessaging, contentText } from "@flow-engineer/messaging";
import { askMyAgent } from "./agent"; // returns a string, or any LLM stream
const flow = new FlowMessaging();
for await (const event of flow.events.stream({ types: ["message.received"] })) {
const text = contentText(event.data.message.content);
await event.conversation.react(event.data.message.id, "👍"); // shows as the Like tapback
await event.conversation.reply(await askMyAgent(text));
}
reply() also accepts a model stream and sends complete chat bubbles as they are ready. Flow’s docs have guides for the Vercel AI SDK, the OpenAI Agents SDK, the Claude Agent SDK, LangChain and Mastra, so you do not have to change how you build the agent.
Tools before channels
Start with one thing a customer should be able to finish in the conversation, such as moving a booking, checking an order or finding a product. Then write the tools that do it, with clear inputs and a clear result.
Keep three rules:
- Read before write. Look up the record, then change it.
- Confirm before you act. Ask “Shall I move it to Tuesday at 3 pm?” and act on the yes.
- Say it is done only when the backend says so. The conversation is an interface to your system, not a second record of it.
In Flow Framework a tool is a typed definition you write once and call from MCP, a CLI or a messaging agent. This is the example from the Flow home page:
export const tools = [
tool({
name: "place_order",
description: "Order food for delivery.",
input: z.object({
store: z.string(),
items: z.array(z.string()),
notes: z.string().optional(),
}),
run: (order) => doordash.orders.create(order),
}),
];
Keep a memory per customer
An agent that forgets who you are feels broken. Keep what the customer said, what they decided and what you did, per customer, and load it at the start of each turn.
Flow keeps a customer’s chat per channel so they can pick up where they left off, and you can delete everything it keeps about a customer. An iMessage handle can be a phone number or an email address, so do not assume a number. To tie an iMessage user to the same person on WhatsApp, use a verified account mapping, not a matching name. Flow’s docs describe this under one person across messaging channels.
Make it feel like iMessage
People read iMessage as short lines. These details make an agent feel at home:
- Short bubbles. On iMessage Flow’s reply helper cuts at about 400 characters, at a sentence end.
- Typing. Turn the typing indicator on while the model works. On Flow it works for 5 minutes after your line’s last message to the person, so send a reply first; the channel clears it after a few seconds, so keep turning it on.
- Reactions. A quick 👍 tells the person you got it. On iMessage a reaction can be any one emoji, in one-to-one conversations (not in groups).
- Read receipts. On iMessage, marking read covers the whole conversation and, like typing, works only for 5 minutes after your line’s last message to the person, so mark read after your reply has gone.
- Effects. A confetti effect on an order confirmation is a nice touch. Effects are iMessage only, and a message that goes by SMS or RCS shows none, so keep the text readable on its own.
- No buttons. iMessage has none, and Flow converts nothing: a buttons message to an iMessage conversation is refused with
422 unsupported_content. Write the choices into the text instead, and read the answer as words. - Edits and unsend. You can edit a sent message within 15 minutes and unsend within two.
Test with simulated people
Conversations break in ways unit tests do not catch: a person changes their mind mid-sentence, sends a photo instead of text, or comes back a day later. Test those paths before launch.
Flow’s test keys can create a simulated contact, a person that exists only inside Flow. Your test, or an AI playing the person, writes as the contact, your agent receives the message the same way it would from a real channel, and the test reads what your agent sent back. No phone is involved. Flow’s Test Suite runs your agent against simulated people and simulated tools and uses a judge to grade the result. The home page describes hundreds of simulated users on the paths that matter, such as ordering, rescheduling and refunds.
Simulated tests cover your logic. Before you ship, also send real messages from a real phone on a real line.
One project: MCP and CLI too
The same tools can serve more than chat. Flow Framework builds an MCP server for Claude, ChatGPT and other assistants and a CLI for coding agents from the same project, so the work you put into the tools pays off in more places. See Flow on iMessage for the product page, and the MCP server guide if that is your next step.
Put it on iMessage with Flow
Flow gives you the framework and messaging API together: tools once, many channels, signed ordered webhooks, simulated-user tests and traces. Customers text the iMessage number first by default, and writing first comes with the $40 a month Outbound add-on on a dedicated line, within warm-up limits.
Start with a test key on the Telegram sandbox, then put your agent on iMessage with Flow when you are ready.
Frequently asked questions
Can an AI agent send and receive iMessages?
Yes, through a third-party iMessage API. The agent receives an event when someone writes, calls its model and tools, and sends a reply. Whether it can write first depends on the provider and the plan.
Which model should an iMessage agent use?
Any model that handles short chat turns and tool calls. Flow lets you bring your own model and provider, and Pro includes $10 of agent credit a month for model tokens.
How do I make an iMessage agent feel natural?
Reply in short bubbles, show typing while the model works, and use tapbacks for quick acknowledgements. Flow's reply helper cuts long answers into bubbles of about 400 characters at sentence ends on iMessage.
Does Flow remember a customer between conversations?
Yes. On each channel, the agent remembers the customer's chat there, so they can pick up where they left off. You can delete everything it keeps about a customer through the API.
Can I use the Vercel AI SDK, LangChain or the OpenAI Agents SDK?
Yes. Flow's docs have guides for the Vercel AI SDK, OpenAI Agents SDK, Claude Agent SDK, LangChain and Mastra.
Can the same agent work on WhatsApp and Telegram?
With Flow, yes. The same handler runs on all three, and the same tools can be served as an MCP server and CLI.
How do I test an iMessage agent without real customers?
Use simulated people. On Flow, test keys can create simulated contacts that exist only inside Flow, and a test suite plays the person's side, runs your tools against simulated data and grades the result.
Keep reading
All posts: the Flow blog. The Flow docs have the reference.
From reading to building
Your agent, on iMessage and everywhere else.
Flow gives your agent an iMessage line, and the same code answers on WhatsApp and Telegram and works as an MCP server and CLI. See how it works on iMessage.
Build on iMessage with Flow