How to run the OpenAI Agents API on Vercel without keeping a VM running
Vercel plugged OpenAI's Agents API into Sandbox and Queues: an agent with session state, isolated execution, and scale-to-zero. I mapped out the end-to-end path.

On September 10, 2026, Vercel announced an integration between the OpenAI Agents API and its serverless infrastructure. The core idea is simple to explain and tedious to implement on your own: OpenAI hosts the agent loop and keeps the session state, while Vercel delivers what's missing to turn that into a real product, an isolated environment to run code (Sandbox), durable event processing (Queues), and an architecture that scales to zero, without a live VM sitting 24/7 waiting for requests.
For anyone building an agent that runs tools, reads and writes files, and continues a task based on a previous instruction, this is exactly the thorny part. I'll break down what changes in your code and map out the path I'd take to get this up and running.
What OpenAI does and what Vercel does
The division of responsibilities is the heart of the matter. It's worth breaking it down before writing a single line:
| Layer | Who handles it | What it solves | |---|---|---| | Agent loop and session state | OpenAI (Agents API) | Orchestrates reasoning, decides which tools to call, keeps the session history | | Sandbox lifecycle events | Vercel Queues | Processes signed OpenAI webhooks durably, without losing events | | Code execution and file access | Vercel Sandbox | Isolated, per-agent-session persistent environment | | Frontend / agent experience | Your app on Vercel | Where the user chats with the agent |
The point that changes the game for serverless devs: Vercel describes this as scale-to-zero architecture without long-lived virtual machines. In other words, you don't pay for a machine running the whole time to hold the agent's state, because OpenAI holds the state, and the sandbox spins up per session.
Why a signed webhook + queue, and not just a function
This is the most important architecture decision, and the one that usually breaks when we improvise. The agent loop runs on OpenAI's side and is asynchronous and potentially long-running. OpenAI communicates events ("the sandbox needs to spin up," "run this," "the session ended") via signed webhooks.
The temptation is to process the webhook directly in a route handler and call the sandbox right there. The problem:
- The webhook needs to respond quickly, otherwise OpenAI retries and you duplicate work.
- Sandbox operations (spinning up an environment, running code) can take longer than a webhook's acceptable timeout.
- If the function fails midway, you lose the event.
This is where Vercel Queues comes in: the webhook only validates the signature and enqueues; a consumer processes the event durably, with retry. Vercel calls this durable processing of sandbox lifecycle events, and it's the part you don't want to reimplement by hand.
The path I'd take
Vercel published a step-by-step guide and a sample application in the changelog. Below is the skeleton of how I'd put the flow together, with the pieces the integration requires. Treat the package/handler names as a conceptual outline, not the final API, always check against the official guide and the sample.
1. Prerequisites
- A Vercel account with Fluid Compute enabled (the foundation of the platform's long-running serverless model).
- Access to the OpenAI Agents API and an API key.
- Vercel Sandbox and Vercel Queues available in the project.
- A current LTS version of Node and the Vercel CLI.
npm i -g vercel@latest
vercel login
npx create-next-app@latest meu-agente
cd meu-agente2. Set up the environment variables
# .env.local
OPENAI_API_KEY=sk-...
OPENAI_WEBHOOK_SECRET=whsec_... # to validate the webhook signatureOPENAI_WEBHOOK_SECRET is what guarantees the event actually came from OpenAI. Never process the payload without validating the signature, it's your security boundary.
3. Receive the webhook and enqueue it (don't process directly)
// app/api/openai-webhook/route.ts
import { NextResponse } from 'next/server'
import { enqueue } from '@/lib/queue' // Vercel Queues consumer
export async function POST(req: Request) {
const signature = req.headers.get('openai-signature') ?? ''
const body = await req.text()
// 1) validate signature before anything else
if (!verifySignature(body, signature, process.env.OPENAI_WEBHOOK_SECRET!)) {
return new NextResponse('invalid signature', { status: 401 })
}
// 2) enqueue and respond quickly
await enqueue('sandbox-lifecycle', JSON.parse(body))
return NextResponse.json({ received: true })
}The handler does the minimum: it validates and enqueues. Responding 200 quickly prevents OpenAI from retrying.
4. Consume the event and operate the Sandbox
// queue consumer
import { Sandbox } from '@vercel/sandbox'
export async function handleLifecycle(event: SandboxEvent) {
// sandbox persistent per agent session
const sandbox = await Sandbox.get(event.sessionId)
?? await Sandbox.create({ sessionId: event.sessionId })
if (event.type === 'tool.run_code') {
const result = await sandbox.exec(event.command)
await reportBack(event.sessionId, result) // sends back to OpenAI to continue the loop
}
}The detail Vercel highlights: the workspace is persistent across follow-up instructions. If the user sends "now adjust that file you created," the files are still there, because the sandbox is tied to the sessionId, not to a request.
How to verify it worked
After deploying (vercel deploy), the smoke test I'd run:
- Trace the webhook. In the Vercel dashboard, check whether the endpoint received the POST and responded 200. If you see a 401, your signature validation is wrong, likely the body was parsed before verification (the signature needs the raw body).
- Check the queue. In Observability/Queues, the event needs to move from pending to processed. If it keeps retrying, your consumer is failing silently.
- Persistence. Run two instructions in sequence in the same session, creating and then reading a file. If the second one can't see the file, the
sessionIdisn't matching between calls.
Where this usually breaks
The most likely stumbling blocks in this kind of integration, and how I'd tackle each one:
- Invalid signature (401): it's almost always the body. Frameworks that automatically call
req.json()consume/normalize the payload; use the raw body to verify the signature. - Duplicate event: an idempotent webhook is mandatory. Store the event ID and ignore repeats, otherwise the same command runs twice in the sandbox.
- Sandbox "disappeared": if you create a sandbox per request instead of per session, you lose the state. The key is always resolving by
sessionId. - Webhook timeout: if you process the sandbox inside the webhook handler instead of enqueuing, it will time out. That's exactly what the queue is for.
What this means for developers in Brazil
The real gain isn't "now you can build an agent," that was already possible. It's that the expensive part to operate, a live VM holding state, isolated-execution orchestration, and event durability, comes off your backlog. For small teams, which are the majority here in Brazil, this means putting an agent that executes code into production without keeping infrastructure running 24 hours a day, paying per session instead of for an idle machine.
The cost, which the changelog doesn't detail, lives in two places: the OpenAI Agents API (loop and state on their side) and Sandbox/Queues/Fluid Compute on the Vercel side. Before shipping to production, measure the cost per session under a real-world scenario, because scale-to-zero solves idleness, but not the bill for a long session running lots of tools.
The official starting point is Vercel's changelog, with the step-by-step guide and sample app linked. It's worth cloning the sample before writing your own, it's faster to understand the division of responsibilities by seeing the code run than by building from scratch.
Translated from the Brazilian Portuguese original · Read the original
Jev turns design system into a decision engine for AI agents
TypeSafe AI's model doesn't generate interface: it chooses among options you define. This changes what it means to maintain a design system.

