Skip to content

Vercel AI SDK

The Vercel AI SDK’s createOpenAICompatible adapter connects to any OpenAI-compatible endpoint, including MirAPI, and streamText consumes the SSE stream. You only change the base URL, the key, and the model.

Element Value
Base URL https://api.mirapi.ai/v1
API key MIRAPI_API_KEY
Model deepseek-chat

Install the core SDK and the OpenAI-compatible adapter:

Terminal window
npm install ai @ai-sdk/openai-compatible

Then create the provider pointing at MirAPI:

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText } from "ai";
const mirapi = createOpenAICompatible({
name: "mirapi",
baseURL: "https://api.mirapi.ai/v1",
apiKey: process.env.MIRAPI_API_KEY!,
});

The adapter options are:

Option Purpose
name Provider label used to build model handles such as mirapi("deepseek-chat")
baseURL https://api.mirapi.ai/v1 — the adapter appends /chat/completions itself
apiKey Your MirAPI key, typically from process.env.MIRAPI_API_KEY
const result = streamText({
model: mirapi("deepseek-chat"),
prompt: "Reply with exactly: connected to MirAPI",
});
for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}

The streamed output should end with connected to MirAPI.

Pass tools in the streamText options using the OpenAI tools/tool_choice format. The upstream model must support tool calling — check the capability flags in the catalogue.

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText } from "ai";
import { z } from "zod";
const mirapi = createOpenAICompatible({
name: "mirapi",
baseURL: "https://api.mirapi.ai/v1",
apiKey: process.env.MIRAPI_API_KEY!,
});
const result = streamText({
model: mirapi("deepseek-chat"),
prompt: "What is the weather in Paris?",
tools: {
getWeather: {
description: "Get the current weather for a city",
parameters: z.object({
city: z.string().describe("City name"),
}),
execute: async ({ city }) => `Sunny, 18°C in ${city}`,
},
},
});
for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}

Streaming is standard SSE — data: lines terminated by data: [DONE] — and streamText maps it to text parts without special flags. With reasoning models, the reasoning content arrives before the answer. Non-streaming usage reports token counts only, never a dollar amount.

MirAPI speaks three protocols natively, and one key covers all of them:

Protocol Base URL Authentication
OpenAI-compatible https://api.mirapi.ai/v1 Authorization: Bearer
Anthropic https://api.mirapi.ai x-api-key or Authorization: Bearer
Gemini https://api.mirapi.ai or https://api.mirapi.ai/v1beta x-goog-api-key or ?key=

createOpenAICompatible uses the OpenAI protocol. The Anthropic protocol has its own SDK, covered in Anthropic SDK; the Gemini protocol is documented in Configuration.

Status Meaning What to do
401 Key missing, invalid, or unknown Fix your credentials
403 Key valid but rejected (balance, whitelist, quota, IP) Resolve the cause, then retry
413 Payload too large Reduce the request size
429 Rate limited Back off; no Retry-After header is sent
500 Server error Safe to retry idempotent requests

A 403 with a valid key means the model is not whitelisted or the balance is exhausted — top up and retry. Every error message ends with a request ID; include it in support tickets. See Errors.

Chat is billed per token, in three tiers per 1M tokens (input, output, cache read). Reasoning tokens are billed as output, and cache reads cost less than fresh input. The balance is prepaid and never expires; when it runs out, requests return 403 and recover immediately after you top up. Reconcile cost in the console billing log or GET /api/log/token — see Billing.

  • 401? The key is missing, invalid, or unknown — verify it and retry.
  • 403 on a request that used to work? Check the balance and the key constraints (whitelist, quota, IP). Topping up restores the key immediately.
  • 429? Back off with jittered exponential delay (1s → 2s → 4s, capped around 30s); no Retry-After header is sent.
  • Model not found? Use the exact id from GET /v1/models and drop any vendor/ prefix.