Vercel AI SDK OpenAI-Compatible API: Custom Provider Setup

Set up a Vercel AI SDK OpenAI-compatible API provider with custom baseURL, API key, model aliases, streaming, fallback routing, and OurToken model examples.

O
OurToken Team//13 min
Vercel AI SDK OpenAI-Compatible API: Custom Provider Setup

A vercel ai sdk openai compatible setup is useful when your application already uses Vercel AI SDK primitives such as generateText or streamText, but you want model access through a unified OpenAI-compatible endpoint instead of wiring every provider separately. The important pieces are simple: a baseURL, an API key, a model ID, and a provider object the AI SDK can call.

This guide shows a practical setup for using OurToken with the Vercel AI SDK. You will configure an OpenAI-compatible provider, call generateText, stream output, add model aliases, and build a small fallback policy that can move from a cheaper route to a stronger route when a request fails. The examples use the official AI SDK pages for OpenAI-compatible custom providers, provider management, and text generation as the API behavior references.

For the OurToken side, keep OurToken API Keys, OurToken Docs, and the model pages for GPT-5.6 Terra, DeepSeek V4 Pro, and GLM 5.2 open while you test. Those pages are the current source of truth for route availability, model IDs, and pricing.

Verification status: This article is documentation-verified against AI SDK and OurToken public pages on 2026-08-04. It was not executed with a private OurToken API key in this draft. Run the smoke tests in your own environment before production rollout.

Vercel AI SDK OpenAI-Compatible Setup

The fastest path is to treat OurToken as an OpenAI-compatible provider in your app configuration. The AI SDK handles the application-facing API, while OurToken provides the model gateway behind one base URL.

Application code
  -> Vercel AI SDK generateText / streamText
  -> OpenAI-compatible provider config
  -> https://api.ourtoken.ai/v1
  -> selected model route
  -> usage and response logging

Install the packages you need:

npm install ai @ai-sdk/openai-compatible

The AI SDK documentation describes @ai-sdk/openai-compatible as the package for OpenAI-compatible provider implementations. If your installed version exposes a helper such as createOpenAICompatible, use that direct provider helper. If you are building a published provider package, follow the official custom provider structure. The implementation below is intentionally framed as an application-level setup file so you can keep your app simple.

Environment variables

Use environment variables for the API key and base URL. Do not expose the key to the browser.

OURTOKEN_API_KEY="paste-your-key-here"
OURTOKEN_BASE_URL="https://api.ourtoken.ai/v1"

The base URL should stop at /v1. Do not use https://api.ourtoken.ai/v1/chat/completions as baseURL in an SDK provider config unless the provider specifically asks for a full operation path. A common failure mode is accidentally creating a doubled request path.

Minimal provider file

Create a small provider module that keeps model IDs in one place. Depending on the exact AI SDK version installed in your app, the OpenAI-compatible package export name may vary. The current AI SDK documentation confirms the @ai-sdk/openai-compatible package and the custom provider pattern, so verify the helper export in your lockfile or installed package before shipping.

// lib/ai-provider.ts
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';

export const ourtoken = createOpenAICompatible({
  name: 'ourtoken',
  apiKey: process.env.OURTOKEN_API_KEY,
  baseURL: process.env.OURTOKEN_BASE_URL ?? 'https://api.ourtoken.ai/v1',
});

export const models = {
  balanced: ourtoken('gpt-5.6-terra'),
  fast: ourtoken('deepseek-v4-flash'),
  strong: ourtoken('deepseek-v4-pro'),
  longContext: ourtoken('glm-5.2'),
} as const;

If your installed package does not expose createOpenAICompatible, use the official custom provider guide rather than guessing. The key idea remains the same: the provider must send Authorization: Bearer YOUR_API_KEY, use https://api.ourtoken.ai/v1 as the base URL, and pass the exact model ID for the route you want to call.

Generate and Stream Text

Once the provider is configured, generateText should look like any other Vercel AI SDK call. The model object changes; your app code can remain stable.

// app/api/summarize/route.ts
import { generateText } from 'ai';
import { models } from '@/lib/ai-provider';

export async function POST(request: Request) {
  const { text } = await request.json();

  const result = await generateText({
    model: models.balanced,
    system: 'You are a concise product documentation assistant.',
    prompt: `Summarize this text in three bullets:\n\n${text}`,
  });

  return Response.json({
    summary: result.text,
    finishReason: result.finishReason,
    usage: result.usage,
  });
}

The official AI SDK text generation documentation notes that generateText returns result information such as generated text, finish reason, usage, warnings, steps, and final step details. Log usage and finish reasons from the start. It is much harder to debug model cost after you have shipped without telemetry.

Streaming route example

For chat UX, streaming is usually a better user experience. The AI SDK docs describe streamText as the function for streaming text from a model.

// app/api/chat/route.ts
import { streamText } from 'ai';
import { models } from '@/lib/ai-provider';

export async function POST(request: Request) {
  const { messages } = await request.json();

  const result = streamText({
    model: models.fast,
    messages,
    onError({ error }) {
      console.error('streamText failed', error);
    },
  });

  return result.toTextStreamResponse();
}

A streaming endpoint should log errors through onError, because streaming failures often happen after headers are sent. Do not assume a clean exception path will catch everything. Also keep messages server-side validated; a browser client should not be able to choose arbitrary model IDs or inject hidden system prompts.

For production chat, also capture finishReason, usage, and latency in onEnd when your AI SDK version exposes those callbacks. Streaming can make an app feel faster, but it can also hide expensive long generations if you only log request count. Store the route alias, model ID, prompt version, and customer or workspace ID with each completed stream. That gives you a path from a monthly bill back to the product feature that created it.

A useful streaming log event looks like this:

type AiUsageLog = {
  feature: string;
  route: 'fast' | 'balanced' | 'strong' | 'longContext';
  modelId: string;
  finishReason?: string;
  inputTokens?: number;
  outputTokens?: number;
  latencyMs: number;
};

Base URL smoke test

Before debugging AI SDK abstractions, test the same key and model with raw HTTP:

curl https://api.ourtoken.ai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OURTOKEN_API_KEY" \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [
      {"role": "user", "content": "Reply with one short sentence."}
    ],
    "max_tokens": 80
  }'

If cURL fails, fix the key, endpoint, or model ID first. If cURL works but the AI SDK call fails, inspect the provider package version, base URL, generated path, and request body. That sequence keeps you from blaming the wrong layer.

Custom Providers, Multiple Providers, and Fallback Routing

A Vercel AI SDK custom provider is useful when you want model aliases, default settings, or a controlled list of models. The official provider management docs explain that custom providers can pre-configure model settings, provide model name aliases, and limit available models. That fits a production OurToken setup well: expose product-level names such as fast, balanced, and strong, while keeping provider-specific model IDs in one file.

// lib/model-policy.ts
import { customProvider } from 'ai';
import { models } from './ai-provider';

export const appModels = customProvider({
  languageModels: {
    fast: models.fast,
    balanced: models.balanced,
    strong: models.strong,
    longContext: models.longContext,
  },
});

Then your feature code can use stable aliases:

import { generateText } from 'ai';
import { appModels } from '@/lib/model-policy';

export async function classifyTicket(ticket: string) {
  const result = await generateText({
    model: appModels.languageModel('fast'),
    system: 'Classify support tickets into billing, account, bug, or other.',
    prompt: ticket,
  });

  return result.text;
}

If your AI SDK version uses a slightly different custom provider API, keep the architecture and adjust the syntax to the installed version. The important production pattern is not the function name; it is centralizing provider config, model aliases, and route policy.

Model alias strategy

Use aliases that describe workload intent, not vendor names. This reduces churn when your team changes a route.

AliasStarting modelUse case
fastdeepseek-v4-flashlow-cost chat, classification, summarization
balancedgpt-5.6-terradefault assistant and coding workflows
strongdeepseek-v4-proharder coding, reasoning, escalation
longContextglm-5.2long prompt or document-heavy tasks

Model aliases also make A/B tests safer. Instead of letting every feature import raw model strings, put route changes behind a configuration file. That makes it obvious which products use which model family and helps finance tie usage back to product decisions.

A good alias file also documents why each route exists. If fast is only for low-risk tasks, say so in code comments or a short README. If strong is allowed for coding agents but not for free-tier support chat, make that policy explicit in the route selector. The goal is not to hide models from engineers; it is to stop accidental route drift where a quick experiment quietly becomes the default for every request.

You can also split aliases by environment. In development, every alias can point to a cheaper route so local testing stays inexpensive. In staging, run a representative subset against the production route map. In production, route by feature and risk level. This keeps costs predictable without forcing developers to edit application code every time you change a model choice.

Multiple provider registry

The AI SDK provider management docs also describe provider registries for mixing multiple providers and accessing models through string IDs. You may not need a registry on day one. Start with a single custom provider if your app only uses OurToken. Move to a registry when you also need a direct provider, a local model, or a separate vendor-specific route.

A simple rule works well: use a custom provider for one gateway with aliases; use a provider registry when your application genuinely needs multiple provider namespaces.

Fallback model routing

A vercel ai sdk fallback model strategy should not be a blind retry loop. Fallback is a routing decision: when a cheaper or faster route fails validation, times out, or returns an unsupported result, escalate to a stronger route and record why.

import { generateText } from 'ai';
import { appModels } from '@/lib/model-policy';

const fallbackOrder = ['fast', 'balanced', 'strong'] as const;

type RouteName = (typeof fallbackOrder)[number];

function isUsableAnswer(text: string) {
  return text.trim().length > 20 && !text.includes('I cannot');
}

export async function generateWithFallback(prompt: string) {
  const attempts: Array<{ route: RouteName; error?: string }> = [];

  for (const route of fallbackOrder) {
    try {
      const result = await generateText({
        model: appModels.languageModel(route),
        system: 'Answer clearly and avoid unnecessary length.',
        prompt,
      });

      if (isUsableAnswer(result.text)) {
        return {
          route,
          text: result.text,
          usage: result.usage,
          attempts,
        };
      }

      attempts.push({ route, error: 'validation_failed' });
    } catch (error) {
      attempts.push({ route, error: String(error) });
    }
  }

  throw new Error(`All model routes failed: ${JSON.stringify(attempts)}`);
}

The fallback policy should be boring and auditable. Log the route, prompt version, validation result, finish reason, usage, and latency. If fast fails often, you need either a better prompt or a different default route. If strong is rarely used, you may be paying for reliability only when it matters, which is exactly the point.

The healthiest fallback dashboard shows four numbers per feature: first-route success rate, escalation rate, final failure rate, and average cost per successful task. If first-route success is high, the policy is working. If escalation is high, the default route is probably too weak or the validation rule is too strict. If final failure remains high, switching models is not the root fix; the prompt, tool schema, input quality, or product workflow needs attention.

For cost control, avoid fallback on user-visible subjective preference alone. A user asking for a more detailed answer should usually trigger a different prompt or larger max_tokens, not an automatic jump to the strongest model. Reserve model fallback for reliability, structured-output validity, rate limits, and measurable task quality signals.

When to escalate

Use fallback for operational and quality failures, not for every answer you dislike.

TriggerGood fallback actionBad fallback action
Timeoutretry once or move to another routeretry forever
429 or transient 5xxexponential backoff, then alternate routeimmediate tight loop
JSON validation failurerepair prompt or escalateaccept malformed output
Low confidence classifiermove from fast to balancedsend all traffic to strong
High-value coding taskstart at balanced or strongforce cheap route first every time

A fallback model policy only saves money if it avoids unnecessary expensive calls. If every request ends at strong, the policy is just a slow way to use the expensive model.

Production Checklist and Cost Control

An OpenAI-compatible AI SDK integration is small enough to ship quickly, but production quality depends on configuration hygiene. Treat the provider setup like infrastructure, not a random helper file.

.env secrets
  -> provider config
  -> model aliases
  -> feature route policy
  -> generateText / streamText calls
  -> usage + latency + finish reason logs
  -> fallback dashboard

Use this checklist before launch:

CheckWhy it matters
OURTOKEN_API_KEY is server-onlyprevents key leaks
baseURL ends at /v1avoids doubled endpoint paths
model IDs are copied from live pagesavoids model_not_found errors
aliases hide raw model stringssimplifies route changes
cURL smoke test passesisolates key and endpoint problems
usage is logged per featureenables cost debugging
fallback attempts are loggedprevents hidden expensive retries
streaming has onError loggingcatches post-header failures

For cost control, start with a default route such as DeepSeek V4 Flash for simple tasks, use GPT-5.6 Terra or GLM 5.2 where their capabilities fit the workload, and reserve stronger routes for prompts that actually need them. The OurToken model pages expose current pricing and model details; your application should log enough usage to compare real cost per successful task, not just unit price.

Do not let frontend users pick raw model IDs. Expose product modes such as fast, balanced, or best, then map those to server-side aliases. This protects your budget and reduces support incidents caused by invalid model strings.

A minimal cost-control loop can be implemented without a separate observability vendor. Start with a database table or log sink that records feature, route, modelId, inputTokens, outputTokens, finishReason, latencyMs, and fallbackAttempt. Review that table weekly. The first useful report is not fancy: list the top five features by token spend, the top five features by escalation rate, and the top five prompts by average output length.

That report usually reveals one of three things. First, a single product feature is sending far more context than expected. Second, a fallback rule is escalating too often. Third, output length is growing because prompts ask for "comprehensive" answers when the UI only needs a short summary. Each issue has a different fix, and you cannot see the difference from aggregate API spend alone.

For teams using OurToken, route-level model pages help keep the configuration honest. Check current pricing and model IDs before changing aliases, then record the change in a small changelog next to your model policy file. This makes later cost changes explainable: you know whether spend changed because traffic grew, prompts changed, or the route map changed.

Conclusion and FAQ

A Vercel AI SDK OpenAI-compatible setup is a good fit when you want AI SDK ergonomics with flexible model routing behind one endpoint. Configure a provider with baseURL, store the API key server-side, centralize model aliases, test with cURL before debugging SDK code, and add fallback only where quality or reliability justifies it.

For OurToken, start by creating a credential in OurToken API Keys, checking setup notes in OurToken Docs, and choosing model routes from live pages such as GPT-5.6 Terra, DeepSeek V4 Pro, and GLM 5.2. Then keep the application code stable while you adjust model policy over time.

FAQ

Can Vercel AI SDK use an OpenAI-compatible API?

Yes. The AI SDK has OpenAI-compatible provider support and custom provider patterns. Configure the provider with the compatible base URL, API key, and model IDs supported by your gateway.

What should the Vercel AI SDK base URL be for OurToken?

Use https://api.ourtoken.ai/v1 as the base URL. Do not include /chat/completions in the base URL unless a specific provider implementation asks for a full endpoint.

How do I use multiple providers in Vercel AI SDK?

Use a custom provider for a single gateway with aliases, or use the AI SDK provider registry when you genuinely need multiple provider namespaces. Keep model choices centralized.

How should fallback models work?

Fallback should escalate only after a timeout, transient error, validation failure, or workload-specific quality signal. Log every attempt, route, usage object, and failure reason.

Which OurToken model should I start with?

For simple high-volume tasks, start with a lower-cost route such as DeepSeek V4 Flash. For balanced production tasks, test GPT-5.6 Terra. For long-context tasks, evaluate GLM 5.2. Always verify with your own prompts.

Is this the same as building a full provider package?

No. This article focuses on an application-level provider setup. If you are publishing a reusable provider package, follow the AI SDK custom provider documentation and test against the package version you plan to ship.