n4nAI

Vercel AI SDK quickstart: call GPT-4o through n4n.ai

Hands-on Vercel AI SDK GPT-4o quickstart using n4n.ai's OpenAI-compatible endpoint, with install steps, runnable TS code, and output.

n4n Team3 min read573 words

Audio narration

Coming soon — every post will get a voice note here.

This vercel ai sdk gpt-4o quickstart n4n.ai gets you from an empty folder to a working GPT-4o inference call in about ten minutes. We point the Vercel AI SDK’s OpenAI provider at n4n.ai’s OpenAI-compatible endpoint, so your code stays identical to the OpenAI-native path while gaining access to 240+ models and automatic provider fallback.

Prerequisites

  • Node.js 18.18+ or 20+ (ESM support required)
  • A package manager: npm, pnpm, or yarn
  • An API key from n4n.ai (we’ll read it from the environment)
  • TypeScript fundamentals and a terminal

If you don’t have a key yet, create one in the dashboard and export it as N4N_API_KEY.

Project scaffolding

Create a new directory and initialize a minimal ESM project:

mkdir vercel-n4n-quickstart && cd vercel-n4n-quickstart
npm init -y
npm pkg set type="module"
touch index.ts .env tsconfig.json

Install the Vercel AI SDK core and the OpenAI provider package:

npm install ai @ai-sdk/openai dotenv
npm install -D typescript @types/node tsx

The @ai-sdk/openai package speaks the OpenAI chat completions protocol. Because n4n.ai mirrors that protocol, we only need to swap the base URL.

Configure the client

Put your key in .env. The Vercel AI SDK’s OpenAI provider expects OPENAI_API_KEY, but we will override the base URL to route through the gateway:

# .env
OPENAI_API_KEY=your-n4n-api-key
OPENAI_BASE_URL=https://api.n4n.ai/v1

n4n.ai exposes a single OpenAI-compatible endpoint that addresses 240+ models, so the same key works for GPT-4o and any other supported model.

Create a small helper module to build the provider:

// client.ts
import { createOpenAI } from '@ai-sdk/openai';
import * as dotenv from 'dotenv';

dotenv.config();

export const openai = createOpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL,
});

Add a strict tsconfig.json so imports resolve cleanly:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["*.ts"]
}

First GPT-4o call

The generateText function is the simplest entry point. It returns the full completion, usage stats, and finish reason.

// index.ts
import { generateText } from 'ai';
import { openai } from './client';

async function main() {
  const { text, usage, finishReason } = await generateText({
    model: openai('gpt-4o'),
    prompt: 'Explain the difference between TCP and UDP in one sentence.',
  });

  console.log('Response:', text);
  console.log('Finish:', finishReason);
  console.log('Usage:', usage);
}

main().catch((err) => {
  console.error('Request failed:', err);
  process.exit(1);
});

Run it with tsx:

npx tsx index.ts

Expected output resembles:

Response: TCP is connection-oriented and guarantees ordered, reliable delivery, while UDP is connectionless and prioritizes low latency over reliability.
Finish: stop
Usage: { promptTokens: 14, completionTokens: 27, totalTokens: 41 }

The usage object comes straight from the gateway’s metering. Per-token usage is reported in the standard OpenAI shape.

Streaming output

For chat-like UX, stream tokens as they arrive. The streamText API returns an async iterable over deltas.

// stream.ts
import { streamText } from 'ai';
import { openai } from './client';

async function main() {
  const result = await streamText({
    model: openai('gpt-4o'),
    prompt: 'Write a haiku about distributed systems.',
  });

  for await (const delta of result.textStream) {
    process.stdout.write(delta);
  }
  process.stdout.write('\n');
}

main().catch(console.error);

Execute:

npx tsx stream.ts

You’ll see tokens printed incrementally. Final stdout might look like:

Nodes hum in sync,
Latency breaks the chain—
Retry, heal, repeat.

Passing chat messages

Real apps send conversation history, not just a flat prompt. Use the messages array:

import { generateText } from 'ai';
import { openai } from './client';

const { text } = await generateText({
  model: openai('gpt-4o'),
  messages: [
    { role: 'system', content: 'You are a terse senior engineer.' },
    { role: 'user', content: 'Why would I use a gateway instead of calling OpenAI directly?' },
  ],
});

console.log(text);

GPT-4o will answer with the usual trade-offs: provider redundancy, unified billing, and model routing.

Honoring cache-control hints

If you pass provider-specific headers, the gateway forwards cache-control hints to the upstream provider. With the Vercel AI SDK, you can attach providerOptions:

await generateText({
  model: openai('gpt-4o'),
  prompt: 'Summarize the RFC for HTTP/3.',
  providerOptions: {
    openai: { cacheControl: { type: 'ephemeral' } },
  },
});

This is a no-op if the upstream ignores it, but it lets you opt into prompt caching where supported.

Error handling and degraded providers

Network failures and provider rate limits happen. The gateway performs automatic fallback when a provider is rate-limited or degraded, but your code should still handle thrown errors gracefully.

import { generateText } from 'ai';
import { openai } from './client';
import { APIError } from '@ai-sdk/openai';

try {
  const { text } = await generateText({
    model: openai('gpt-4o'),
    prompt: 'Status check',
  });
  console.log(text);
} catch (err) {
  if (err instanceof APIError) {
    console.error(`Upstream returned ${err.status}: ${err.message}`);
  } else {
    console.error('Unexpected error', err);
  }
}

Because the SDK uses standard fetch, timeouts can be set via maxRetries or a custom fetch implementation.

Routing directives

If you need to force a specific upstream, the gateway honors client routing directives. Pass them through headers:

await generateText({
  model: openai('gpt-4o'),
  prompt: 'Trace this latency spike.',
  headers: { 'x-n4n-route': 'openai' },
});

This bypasses fallback logic for that request. Use it only when you have a concrete reason.

Using in a Next.js route handler

The vercel ai sdk gpt-4o quickstart n4n.ai setup drops into a Next.js App Router route without changes to the client module.

// app/api/chat/route.ts
import { streamText } from 'ai';
import { openai } from '@/lib/client';

export async function POST(req: Request) {
  const { prompt } = await req.json();
  const result = await streamText({
    model: openai('gpt-4o'),
    prompt,
  });
  return result.toDataStreamResponse();
}

The same client.ts works because Next.js supports ESM and environment variables.

Type safety and model lists

The createOpenAI helper types models as string, so 'gpt-4o' is accepted. To constrain to known models, cast or wrap:

const models = ['gpt-4o', 'gpt-4o-mini'] as const;
type ModelId = typeof models[number];

function chat(model: ModelId, prompt: string) {
  return generateText({ model: openai(model), prompt });
}

Wrapping up

You now have a runnable vercel ai sdk gpt-4o quickstart n4n.ai setup: a typed client, blocking and streaming calls, usage metering, and routing hooks. From here, drop the client into a serverless function and swap gpt-4o for any of the 240+ models without changing import paths.

Keep the base URL override in one place, and you can migrate between providers by editing a single line.

Tagsvercel-ai-sdkgpt-4on4n-aiquickstart

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All vercel ai sdk getting started with n4n.ai posts →