Products

Ships to

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:

  1. Event in. Someone writes to your line. The provider posts a signed webhook, or you read it from a stream.
  2. Model call. Your code passes the conversation, your instructions and your tools to a model.
  3. 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.
  4. 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 within five minutes of the person’s last message and the channel clears it after a few seconds, so keep turning it on.
  • Tapbacks. A quick 👍 tells the person you got it. iMessage has a fixed set, so Flow uses the closest tapback or skips it and says so.
  • Read receipts. Mark messages read when you start work. On iMessage this marks the whole conversation.
  • Effects. A confetti effect on an order confirmation is a nice touch. Keep a plain-text fallback on, because which effects a line can send may vary.
  • No buttons. iMessage has none. Send buttons content with fallback: "auto" and Flow sends numbered text. When the person answers “2”, you still get a button_reply with the second button’s id, so your code is the same on every channel.
  • 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 a dedicated line can support writing first subject to availability and 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.

Start hereiMessage API: a developer’s guideThe overview of how iMessage APIs work, and what to ask a provider. Build an agentiMessage agent with the Vercel AI SDKTake a Vercel AI SDK agent and answer on iMessage with streamed, chat-sized bubbles.Build an agentiMessage agent with the OpenAI Agents SDKReceive an iMessage, run an OpenAI Agents SDK agent and send the result back as bubbles.Build an agentiMessage agent with the Claude Agent SDKRun a Claude agent for each iMessage and deliver its streamed answer.Build an agentLangChain iMessage agentConnect a LangChain model or chain to an iMessage conversation.Build an agentiMessage API for coding agentsLet Claude Code, Cursor or Codex set up and test a messaging integration for you.Build an agentOne agent on iMessage, WhatsApp and TelegramWhat changes per channel and what stays the same when one codebase answers everywhere.

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