DEV Community

Cover image for LLM integration with OpenRouter
Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev on

LLM integration with OpenRouter

OpenRouter is a unified API gateway to hundreds of language models from providers such as OpenAI, Anthropic, Google, and Meta. You use one API key and one billing surface, and swap models by changing a provider/model slug. OpenRouter exposes a Chat Completions-compatible HTTP API.

This post shows three Node.js integration paths: the official @openrouter/sdk, the openai package with baseURL, and the Vercel AI SDK with @openrouter/ai-sdk-provider.

For deeper patterns on each stack, see the Chat Completions API, OpenAI Responses API (OpenAI direct only), and Vercel AI SDK posts.

Prerequisites

  • OpenRouter account
  • API key
  • Credits or billing enabled as needed
  • Node.js version 26
  • Install packages for the path you use:
    • @openrouter/sdk (npm i @openrouter/sdk)
    • openai (npm i openai)
    • ai and @openrouter/ai-sdk-provider (npm i ai @openrouter/ai-sdk-provider)

Configuration

Read credentials from the environment in production.

Variable Purpose
OPENROUTER_API_KEY Bearer token from OpenRouter settings
OPENROUTER_MODEL Default model slug, for example openai/gpt-5.5
OPENROUTER_SITE_URL Optional site URL sent as HTTP-Referer for rankings on openrouter.ai
OPENROUTER_SITE_TITLE Optional app name sent as X-OpenRouter-Title

Model IDs use the provider/model format, for example openai/gpt-5.5, anthropic/claude-opus-4.8, or google/gemini-3.1-flash-lite. Browse the full catalog at openrouter.ai/models.

The examples below use openai/gpt-5.5, matching the model in the other LLM posts in this series. Override it with OPENROUTER_MODEL when you want a different model.

@openrouter/sdk

OpenRouter's official TypeScript SDK is type-safe and generated from the OpenAPI spec.

Client setup

import { OpenRouter } from '@openrouter/sdk';

const client = new OpenRouter({
  apiKey: process.env.OPENROUTER_API_KEY,
  httpReferer: process.env.OPENROUTER_SITE_URL,
  appTitle: process.env.OPENROUTER_SITE_TITLE,
});
Enter fullscreen mode Exit fullscreen mode

Basic integration

const response = await client.chat.send({
  chatRequest: {
    model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
    messages: [
      { role: 'user', content: 'Write a one-sentence bedtime story about a unicorn.' },
    ],
  },
});

console.log(response.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

System prompt

Add a system message before the user turn to set tone, format, and role.

const response = await client.chat.send({
  chatRequest: {
    model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
    messages: [
      { role: 'system', content: 'Reply in one short sentence. Use plain language.' },
      { role: 'user', content: 'Explain what an LLM is.' },
    ],
  },
});

console.log(response.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

Streaming

Set stream: true and read incremental text from choices[0].delta.content.

const stream = await client.chat.send({
  chatRequest: {
    model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
    messages: [{ role: 'user', content: 'List three colors.' }],
    stream: true,
  },
});

process.stdout.write('[stream] ');
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) {
    process.stdout.write(delta);
  }
}
process.stdout.write('\n');
Enter fullscreen mode Exit fullscreen mode

Model switching

Change only the model string to route the same code to a different provider.

const models = ['openai/gpt-5.5', 'google/gemini-3.1-flash-lite'];

for (const model of models) {
  const response = await client.chat.send({
    chatRequest: {
      model,
      messages: [{ role: 'user', content: 'Reply with exactly one word: ok.' }],
    },
  });

  console.log(model, '->', response.choices[0].message.content);
}
Enter fullscreen mode Exit fullscreen mode

openai package

If you already use the OpenAI SDK, point it at OpenRouter with baseURL. The request shape matches the Chat Completions API.

Client setup

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.OPENROUTER_API_KEY,
  baseURL: 'https://openrouter.ai/api/v1',
  defaultHeaders: {
    'HTTP-Referer': process.env.OPENROUTER_SITE_URL,
    'X-OpenRouter-Title': process.env.OPENROUTER_SITE_TITLE,
  },
});
Enter fullscreen mode Exit fullscreen mode

Basic integration

const completion = await client.chat.completions.create({
  model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
  messages: [
    { role: 'user', content: 'Write a one-sentence bedtime story about a unicorn.' },
  ],
});

console.log(completion.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

System prompt

const completion = await client.chat.completions.create({
  model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
  messages: [
    { role: 'system', content: 'Reply in one short sentence. Use plain language.' },
    { role: 'user', content: 'Explain what an LLM is.' },
  ],
});

console.log(completion.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

Streaming

const stream = await client.chat.completions.create({
  model: process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5',
  messages: [{ role: 'user', content: 'List three colors.' }],
  stream: true,
});

process.stdout.write('[stream] ');
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) {
    process.stdout.write(delta);
  }
}
process.stdout.write('\n');
Enter fullscreen mode Exit fullscreen mode

For JSON schema output, Markdown-to-HTML, and few-shot prompting, reuse the patterns from the Chat Completions post with the OpenRouter client and model slug above.

Vercel AI SDK

The @openrouter/ai-sdk-provider package exposes OpenRouter models to generateText, streamText, and related helpers from the ai package. See the OpenRouter Vercel AI SDK guide for the full integration reference.

Client setup

import { createOpenRouter } from '@openrouter/ai-sdk-provider';

const openrouter = createOpenRouter({
  apiKey: process.env.OPENROUTER_API_KEY,
  appUrl: process.env.OPENROUTER_SITE_URL,
  appName: process.env.OPENROUTER_SITE_TITLE,
});
Enter fullscreen mode Exit fullscreen mode

The returned provider is callable. Pass a model slug directly: openrouter('openai/gpt-5.5').

Basic integration

import { generateText } from 'ai';

const { text } = await generateText({
  model: openrouter(process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5'),
  prompt: 'Write a one-sentence bedtime story about a unicorn.',
});

console.log(text);
Enter fullscreen mode Exit fullscreen mode

System prompt

const { text } = await generateText({
  model: openrouter(process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5'),
  system: 'Reply in one short sentence. Use plain language.',
  prompt: 'Explain what an LLM is.',
});

console.log(text);
Enter fullscreen mode Exit fullscreen mode

Streaming

import { streamText } from 'ai';

const result = streamText({
  model: openrouter(process.env.OPENROUTER_MODEL ?? 'openai/gpt-5.5'),
  prompt: 'List three colors.',
});

process.stdout.write('[stream] ');
for await (const part of result.textStream) {
  process.stdout.write(part);
}
process.stdout.write('\n');
Enter fullscreen mode Exit fullscreen mode

For structured output, embeddings, and web search, see the Vercel AI SDK post. Those patterns apply when you call OpenAI directly; OpenRouter coverage depends on the model and endpoint.

Demo

Runnable scripts for each integration path live in the openrouter-demo folder. Get access via code demos.

Top comments (0)