Use the Vercel AI SDK with UberLLM (cheaper models, same code)
Install @ai-sdk/openai-compatible, create a provider with baseURL https://api.uberllm.dev/v1 and your UberLLM key, and pass uberllm("<model id>") wherever your app passes a model today. Nothing else in the app changes.
Steps
- Make a key on your keys page and add a little credit (accounts start at $0).
- Install the provider:
npm i ai @ai-sdk/openai-compatible
- Put the key in
.env.local(Next.js) or your server's environment:
UBERLLM_API_KEY=ull_your_key
- Create the provider once, for example in
lib/uberllm.ts:
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
export const uberllm = createOpenAICompatible({
name: "uberllm",
baseURL: "https://api.uberllm.dev/v1",
apiKey: process.env.UBERLLM_API_KEY, // sent as Authorization: Bearer <key>
includeUsage: true, // token counts on streamed answers too
});
- Use it where you used a model before:
import { generateText } from "ai";
import { uberllm } from "@/lib/uberllm";
const { text } = await generateText({
model: uberllm("deepseek/deepseek-v4.1-flash"),
prompt: "Write a one-line welcome message.",
});
Moving an app that already uses @ai-sdk/openai
Swap the model argument and keep everything else:
// before
import { openai } from "@ai-sdk/openai";
const model = openai("gpt-4o");
// after
import { uberllm } from "@/lib/uberllm";
const model = uberllm("deepseek/deepseek-v4.1-flash");
Model ids are the ids on uberllm.dev/models and always have a maker in front (openai/…, anthropic/…, deepseek/…). That is how you can run GPT, Claude, Gemini and open models from one key and compare them by changing one string.
A Next.js chat route for useChat
useChat from @ai-sdk/react posts to /api/chat by default. This route answers it:
// app/api/chat/route.ts
import { streamText, convertToModelMessages, type UIMessage } from "ai";
import { uberllm } from "@/lib/uberllm";
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: uberllm("deepseek/deepseek-v4.1-flash"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
Keep the key on the server. Never put it in a NEXT_PUBLIC_ variable: anyone could read it from the page and spend your balance.
Cap what one call can cost
Chat requests accept provider.max_price (dollars per million tokens). Pass it through providerOptions under the provider name you chose:
await generateText({
model: uberllm("deepseek/deepseek-v4.1-flash"),
prompt: "Hi",
providerOptions: { uberllm: { provider: { max_price: { prompt: 0.2, completion: 0.4 } } } },
});
If nobody sells the model under that price right now the call is refused with max_price_exceeded and nothing is charged.
Troubleshooting
- 401
invalid_api_key: the key did not reach the server. Restartnext devafter editing.env.local, and checkprocess.env.UBERLLM_API_KEYis set where the code runs (server, not the browser). - 402
insufficient_credits: add credit on the credits page. - 404
model_not_found: the id is wrong or missing its maker. Copy it from the model's page. - 400
wrong_endpoint: you passed an image or video model tostreamText. Image models go throughuberllm.imageModel(…)withgenerateImage; video is a job, see Make a video or image. - Usage is empty on streams: set
includeUsage: trueon the provider, as above.
Keep reading
- The full reference with tool calls and images: Vercel AI SDK doc
- OpenAI-compatible endpoint explained
- Live LLM prices