---
title: "Building a Realtime Voice Support Agent with Vercel AI SDK v7"
description: "Voice agents used to mean marrying one provider's WebSocket event format. I used the new experimental realtime API in Vercel AI SDK v7 to build an order-status voice agent I can move between providers."
image: "https://foundrysoft.co/api/og?type=article&title=Building+a+Realtime+Voice+Support+Agent+with+Vercel+AI+SDK+v7&cat=AI+Engineering&rt=8+min+read&au=Varun+Raj+Manoharan&dt=2026-07-16"
url: "https://foundrysoft.co/blog/vercel-ai-sdk-v7-realtime-voice-agent"
---

AI Engineering 2026-07-16 8 min read

# Building a Realtime Voice Support Agent with Vercel AI SDK v7

Voice agents used to mean marrying one provider's WebSocket event format. I used the new experimental realtime API in Vercel AI SDK v7 to build an order-status voice agent I can move between providers.

![Varun Raj Manoharan](https://foundrysoft.co/images/about/founder.webp)

Varun Raj Manoharan

Vercel AI SDK v7 Voice Realtime TypeScript

Every voice agent I have shipped before this year had the same architecture problem: the moment you open a WebSocket to a realtime model, you are writing against that one provider's event format. Session events, audio chunks, tool call frames, turn detection, all of it proprietary. Switching providers meant rewriting the client.

Vercel AI SDK v7 takes a swing at this with provider-agnostic realtime support. The session runs in the browser, connects directly to the provider over WebSockets, and your React code talks to one hook: `experimental_useRealtime`. I rebuilt a use case I know well, a customer support agent that answers "where is my order?" over voice, to see how much of the old pain is actually gone.

### The token dance

The browser never sees your API key. Your server mints a short-lived token, and the client uses that to open the socket. The server side is a few lines:

TypeScript

Copy

```typescript
// app/api/realtime/setup/route.ts
import { openai } from '@ai-sdk/openai';

export async function POST() {
  const token = await openai.experimental_realtime.getToken({
    model: 'gpt-realtime',
  });
  return Response.json(token);
}
```

This endpoint is effectively a key-vending machine, so put your normal auth and rate limiting in front of it. Anyone who can hit it can open billable voice sessions.

### The client is one hook

On the client, `experimental_useRealtime` manages the WebSocket, microphone capture, and audio playback. You configure the session where you create it:

TypeScript

Copy

```typescript
'use client';
import { experimental_useRealtime } from '@ai-sdk/react';
import { openai } from '@ai-sdk/openai';

const realtime = experimental_useRealtime({
  model: openai.experimental_realtime('gpt-realtime'),
  api: { token: '/api/realtime/setup' },
  sessionConfig: {
    instructions:
      'You are a support agent for an online store. Look up orders before answering. Be brief.',
    voice: 'alloy',
    inputAudioTranscription: {},
    turnDetection: { type: 'server-vad' },
  },
  onToolCall: async ({ toolCall }) => {
    if (toolCall.toolName === 'getOrderStatus') {
      const res = await fetch('/api/orders/status', {
        method: 'POST',
        body: JSON.stringify(toolCall.args),
      });
      return res.json();
    }
  },
});
```

Calling `realtime.connect()` starts the session; `realtime.messages` gives you a normal `UIMessage[]` array, so the transcript renders with the exact same components I already had for text chat. That detail alone saved me an afternoon.

### Tool calls run in the client

This was the architectural surprise: realtime tool execution is client-driven. The provider sends the tool call over the socket, your `onToolCall` handler runs it, and the result flows back into the conversation. There is no server-side agent loop.

For my order lookup that is the right shape. The browser calls my own authenticated API route, the route talks to the database, and the model gets back a small JSON payload while the user hears "let me check that for you." For anything sensitive, the pattern is the same as regular client code: the tool handler hits your API, and your API enforces who can see what. If you need to feed a result back manually, `realtime.addToolOutput(toolCallId, result)` does it.

The transcription config matters more than it looks, too. With `inputAudioTranscription` on, you get text of what the caller actually said, which is the difference between debuggable sessions and listening to recordings.

### The provider-agnostic part is real

The reason this is a v7 story and not just an OpenAI story: swap the model line and the rest of the code stands still. Google's Gemini Live and xAI's Grok voice models plug into the same hook, and the AI Gateway normalizes all of them behind one interface:

TypeScript

Copy

```typescript
// server: mint the token through the gateway instead
const token = await gateway.experimental_realtime.getToken({
  model: 'openai/gpt-realtime-2',
});
```

Change the model string, redeploy, and you are on a different provider. My session config and tool handlers did not change. That is the thing I could not do last year without a rewrite.

### Why this matters

The demo took an evening: press a button, ask where order 4271 is, hear the agent check the database and answer. Voice quality and latency are the provider's problem now, and choosing a provider is a config change instead of an architecture decision.

It is experimental and the API will move. But if you have been putting off a voice interface because the last attempt welded you to one vendor's event soup, v7 is the first version where I would start that project again.

#### Related reading

[MCP Went Stateless: Migrating Your Server to the 2026-07-28 Spec

The 2026-07-28 MCP revision removes sessions, the initialize handshake, and server-initiated requests. Here's what actually breaks in your server, the new wire format, the requestState and MRTR patterns that replace sessions, and the SDK v2 migration path.

MCP Model Context Protocol AI Agents

](https://foundrysoft.co/blog/mcp-stateless-spec-migration)[We Open-Sourced an AI Agent for Coverage Citations: And Broke It Twice

agent-for-insurance is an open-source drafting aid that will not state a coverage conclusion without citing your policy's own text. Here's how it works, and the two parsing bugs that taught us why that rule has to be enforced in code, not prose.

Open Source AI Agents Insurance

](https://foundrysoft.co/blog/open-source-ai-agent-insurance-coverage-citations)[Grok Voice API Tutorial: How to Build a Realtime AI Voice Agent for Customer Support

A hands-on Grok Voice Agent API tutorial: connect over WebSocket, configure voice and turn detection, wire up function calling for live order lookups, and build a production customer support voice agent in Python.

Grok xAI Voice Agents

](https://foundrysoft.co/blog/grok-voice-agent-api-realtime-build)

#### Next Article

[

Lightweight AI Sandboxes with WebAssembly: Pyodide and QuickJS

](https://foundrysoft.co/blog/wasm-sandbox-ai-code-pyodide-quickjs)

Available for new projects

## Let's build something great.

Have a project in mind? We are an elite software and AI development studio ready to bring your ideas to production. Let's talk about your roadmap.

Start a Project [See our work](https://foundrysoft.co/work)

```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co",
  "logo": "https://foundrysoft.co/logo.svg",
  "description": "FoundrySoft builds production-grade software and AI systems for US companies, from an India-based team of senior engineers.",
  "sameAs": [
    "https://github.com/foundrysofthq",
    "https://www.linkedin.com/company/foundrysoft",
    "https://www.instagram.com/foundrysoft/"
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co"
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Building a Realtime Voice Support Agent with Vercel AI SDK v7",
  "description": "Voice agents used to mean marrying one provider's WebSocket event format. I used the new experimental realtime API in Vercel AI SDK v7 to build an order-status voice agent I can move between providers.",
  "url": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-realtime-voice-agent",
  "mainEntityOfPage": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-realtime-voice-agent",
  "image": [
    "https://foundrysoft.co/api/og?type=article&title=Building+a+Realtime+Voice+Support+Agent+with+Vercel+AI+SDK+v7&cat=AI+Engineering&rt=8+min+read&au=Varun+Raj+Manoharan&dt=2026-07-16"
  ],
  "datePublished": "2026-07-16",
  "dateModified": "2026-07-16",
  "keywords": "Vercel, AI, SDK v7, Voice, Realtime, TypeScript",
  "author": {
    "@type": "Person",
    "name": "Varun Raj Manoharan"
  },
  "publisher": {
    "@type": "Organization",
    "name": "FoundrySoft",
    "logo": {
      "@type": "ImageObject",
      "url": "https://foundrysoft.co/logo.svg"
    }
  }
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://foundrysoft.co/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://foundrysoft.co/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Building a Realtime Voice Support Agent with Vercel AI SDK v7",
      "item": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-realtime-voice-agent"
    }
  ]
}
```
