Products

Ships to

Build an agentiMessage API6 min read

iMessage agent with the OpenAI Agents SDK

Run an OpenAI Agents SDK agent on iMessage with Flow. Receive a message, run the agent and stream the result back as chat bubbles, with TypeScript and Python examples.

The short answer

With Flow, run the agent with stream: true and pass the result to reply() for chat-sized bubbles. The same agent code works across iMessage, WhatsApp and Telegram, so adding a channel does not mean rebuilding your agent.

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

Flow’s OpenAI Agents SDK guide passes the agent’s stream to reply(). The messaging code is the same on each connected channel.

// npm install @flow-engineer/messaging @openai/agents
import { Agent, run } from "@openai/agents";
import { FlowMessaging, contentText } from "@flow-engineer/messaging";

const flow = new FlowMessaging();
const agent = new Agent({
  name: "Bakery assistant",
  instructions: "You help customers of Asha's Bakery with orders and delivery. Keep answers short.",
  model: "gpt-4.1-mini",
});

for await (const event of flow.events.stream({ types: ["message.received"] })) {
  const result = await run(agent, contentText(event.data.message.content), { stream: true });
  await event.conversation.reply(result); // reads result.toTextStream()
}

run(agent, input, { stream: true }) returns a streamed result. reply() reads its text stream and sends bubbles while the agent runs.

Python

The Python example in Flow’s docs uses plain HTTP and a FastAPI webhook. It answers {} at once, then sends the agent’s final_output from a background task:

# pip install openai-agents fastapi requests
import os, requests
from fastapi import FastAPI, Request, BackgroundTasks
from agents import Agent, Runner

API = "https://api.flow.engineer"
HEADERS = {"Authorization": f"Bearer {os.environ['FLOW_MESSAGING_KEY']}"}
agent = Agent(name="Bakery assistant", instructions="You help customers of Asha's Bakery. Keep answers short.")
app = FastAPI()

async def answer(event: dict):
    text = event["data"]["message"]["content"].get("text", "")
    result = await Runner.run(agent, text)
    requests.post(
        f"{API}/v1/conversations/{event['conversation']['id']}/messages",
        headers={**HEADERS, "Idempotency-Key": event["id"]},
        json={"content": {"type": "text", "text": result.final_output, "format": "markdown"}, "fallback": "auto"},
        timeout=30,
    )

@app.post("/flow")
async def flow_webhook(request: Request, tasks: BackgroundTasks):
    event = await request.json()  # verify Flow-Signature first
    if event["type"] == "message.received":
        tasks.add_task(answer, event)
    return {}

Verify the Flow-Signature header before you trust the body. The check is in Send iMessage programmatically.

How it fits

  • The agent’s tools, handoffs and instructions stay in the OpenAI Agents SDK. Flow only moves messages in and out.
  • Give the agent the conversation’s history from GET /v1/conversations/{conversation_id}/messages, or keep your own session keyed by the conversation ID.
  • "fallback": "auto" sends markdown as plain text where a channel has no formatting. On iMessage that is what you want.

Limits to know

  • Text length. iMessage takes up to 9,999 characters per message and Telegram 4,096. Longer text is refused.
  • Who writes first. By default customers text the line first. A dedicated line with the outbound add-on can write first, within warm-up limits. Test on the Telegram sandbox with the same code.
  • No buttons. If your agent uses buttons content, set fallback: "auto" and Flow sends numbered text.

For the design of the agent around this code, see Build an iMessage AI agent. Other frameworks: Vercel AI SDK, Claude Agent SDK, LangChain.

Frequently asked questions

Can the OpenAI Agents SDK run on iMessage?

Yes, through a messaging API. Flow's docs have an OpenAI Agents SDK guide: receive the message, run the agent, and send its stream back as chat bubbles.

Does it work in Python as well as TypeScript?

Yes. The TypeScript SDK passes the streamed result to reply. The Python example answers the webhook with an empty object, runs the agent in a background task, and posts the final output through the HTTP API.

How do I keep conversation history?

Read it from GET /v1/conversations/{conversation_id}/messages, or keep your own session keyed by the conversation ID.

What is the text limit?

iMessage allows up to 9,999 characters in a text message, and Telegram allows 4,096. Text over the limit is refused, so split long answers at paragraph breaks and send each part with its own idempotency key.

How do I avoid duplicate replies?

Use the event ID as the Idempotency-Key. A repeat with the same key returns the first answer and does not send twice.

Can I trace and grade the agent's turns?

Flow's docs describe sending traces from agent frameworks to Flow Observe, which shows each turn's model and tool calls and grades every reply.

Start hereiMessage API: a developer’s guideThe overview of how iMessage APIs work, and what to ask a provider. Build an agentBuild an iMessage AI agentWebhook in, model call, tools, reply out: the Flow loop, memory, testing and production safeguards.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 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