Build an agentiMessage API6 min read
LangChain iMessage agent
Connect a LangChain model or chain to iMessage with Flow. Stream the answer as chat bubbles in TypeScript or reply in the webhook response in Python.

The short answer
Flow connects any LangChain runnable to a real iMessage conversation. Stream message chunks through reply() for natural chat bubbles, then reuse the same agent and tools on WhatsApp, Telegram and MCP.
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.
TypeScript: stream the answer
Flow’s LangChain guide starts a run for each incoming message and delivers the streamed answer as chat bubbles:
// npm install @flow-engineer/messaging @langchain/openai
import { ChatOpenAI } from "@langchain/openai";
import { FlowMessaging, contentText } from "@flow-engineer/messaging";
const flow = new FlowMessaging();
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });
for await (const event of flow.events.stream({ types: ["message.received"] })) {
const stream = await model.stream([
["system", "You are the assistant for Asha's Bakery. Answer in short messages."],
["human", contentText(event.data.message.content)],
]);
await event.conversation.reply(stream); // reads each chunk's content
}
Python: reply in the webhook
The Python example answers inside the webhook response, which is one round trip:
# pip install langchain-openai fastapi
from fastapi import FastAPI, Request
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4.1-mini")
app = FastAPI()
@app.post("/flow")
async def flow_webhook(request: Request):
event = await request.json() # verify Flow-Signature first
if event["type"] != "message.received":
return {}
text = event["data"]["message"]["content"].get("text", "")
answer = await model.ainvoke([("system", "You are the assistant for Asha's Bakery."), ("human", text)])
return {"reply": {"type": "text", "text": answer.content, "format": "markdown"}, "fallback": "auto"}
Verify the Flow-Signature header before you use the body. Send iMessage programmatically shows how.
How it fits
- Any streaming runnable. Chat models,
prompt.pipe(model)chains and chains ending in a string output parser all work withreply(). - A 10 second budget in Python. Flow waits 10 seconds for the webhook answer. That suits fast chains. For slower ones, answer
{}at once and send the reply later withPOST /v1/conversations/{conversation_id}/messages. - Plain text where needed.
fallback: "auto"sends markdown as plain text on channels without formatting. iMessage is one of them. - One message, not bubbles. A reply in the webhook response goes out as a single message, so keep it short.
Memory and limits
Keep chat history per conversation ID, or read it from GET /v1/conversations/{conversation_id}/messages. Flow keeps message content for 30 days by default, so persist anything you need for longer.
The text limits are 9,999 characters on iMessage and 4,096 on Telegram. Use the event ID as the idempotency key when you reply, so a retried delivery cannot send twice.
Flow’s iMessage numbers are US numbers, shared or dedicated. Build and test on the Telegram sandbox with the same code, then move to iMessage. For how the whole agent should be designed, see Build an iMessage AI agent.
Other frameworks: Vercel AI SDK, OpenAI Agents SDK, Claude Agent SDK.
Frequently asked questions
How do I build a LangChain iMessage agent?
Use a messaging API that gives you inbound events and a reply call. With Flow, each incoming message starts a LangChain run and reply() delivers the streamed answer as chat bubbles.
Which LangChain objects work with reply()?
Any runnable whose stream method yields message chunks: chat models, prompt-to-model chains, and chains that end in a string output parser.
Can I answer in the webhook response?
Yes, in Python. Flow waits 10 seconds for the answer, so this suits fast chains. For slower ones, answer with an empty object and send the reply later with a POST to the conversation.
How do I keep chat history?
Keep history per conversation ID, or read it from GET /v1/conversations/{conversation_id}/messages.
Is there a text limit for the reply?
A reply in the webhook response goes out as one message, so keep it within the channel's text limit. iMessage allows up to 9,999 characters and Telegram 4,096.
Can the agent run on WhatsApp and Telegram too?
Yes. The same code serves each connected channel. You can start on the Telegram sandbox and move to iMessage on a shared or dedicated line.
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