Building API Routes
Backend integration patterns for any framework. Send and reconnect streams, load history, resolve approvals, interrupt runs, and manage sessions.
This guide covers backend patterns for integrating agents into your application. The examples stay in module scope so you can wire them into any framework.
Simpler alternative:
handleRequestcreates a single HTTP handler from your agent that routes requests automatically. Use this guide when you need full control over each endpoint.
Core Chat Flow
The core flow is: send input to a session, then return the stream. Reconnection reuses session.stream() on the same session.
import { createUIMessageStreamResponse } from "ai";
import { myAgent } from "@/agent";
export async function sendMessage({
chatId,
message,
}: {
chatId: string;
message: string;
}) {
const session = myAgent.session(chatId);
await session.send(message);
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });
}
export async function reconnectStream({ chatId }: { chatId: string }) {
const session = myAgent.session(chatId);
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });
}session.stream() returns a ReadableStream<UIMessageChunk> from the AI SDK. Use createUIMessageStreamResponse({ stream }) when returning it from your server.
See Streaming for reconnection details.
With Workflow
When using Vercel Workflow for durability, start the workflow and stream from its result:
import { createUIMessageStreamResponse } from "ai";
import { start } from "workflow/api";
import { myAgent } from "@/agent";
import { agentWorkflow } from "./workflow";
export async function sendMessage({
chatId,
message,
opts,
}: {
chatId: string;
message: string;
opts?: Record<string, unknown>;
}) {
const session = myAgent.session(chatId);
const result = await start(agentWorkflow, [chatId, message, opts]);
const stream = await session.stream(result);
return createUIMessageStreamResponse({ stream });
}Loading Session History
Use session.history() to load conversation history for initial render or when no active stream exists:
import { myAgent } from "@/agent";
export async function loadHistory({ chatId }: { chatId: string }) {
const session = myAgent.session(chatId);
return await session.history();
}Resolving Tool Approvals
When a tool requires approval, the agent suspends. Resolve it by sending an approval:
import { myAgent } from "@/agent";
export async function resolveApproval({
chatId,
approvalId,
approved,
reason,
}: {
chatId: string;
approvalId: string;
approved: boolean;
reason?: string;
}) {
const session = myAgent.session(chatId);
await session.send({
type: "approval",
approval: { approvalId, approved, reason },
});
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });
}See Approvals for frontend integration.
Interrupting a Run
Stop the current assistant response (e.g. when the user clicks "Stop"):
import { myAgent } from "@/agent";
export async function interruptSession({ chatId }: { chatId: string }) {
const session = myAgent.session(chatId);
await session.interrupt();
return { success: true };
}Pending approvals are auto-rejected when interrupted.
Passing Context (Auth Tokens)
Pass per-request data like auth tokens via the context option when sending. Tools receive it via ToolContext.context:
const session = myAgent.session(chatId);
await session.send(message, {
context: {
authToken,
tenantId,
},
});Define contextSchema on your agent to type and validate context. See Sessions and Tools for details.
Interrupt-If-Streaming Pattern
When the user sends a new message while the assistant is still streaming, automatically interrupt the current response:
await session.send(message, { interruptIfStreaming: true });This stops the current stream and starts fresh with the new message. Pending approvals are auto-rejected.
Next Steps
- handleRequest — Convention-based HTTP handler with less boilerplate
- Sessions — Context, update, and interrupt
- Approvals — Frontend integration and tool part states
- Streaming — Reconnection and status handling