How to Use OpenRouter SDK with Puter
On this page
In this tutorial, you'll learn how to use the OpenRouter TypeScript SDK with Puter. Puter exposes an OpenAI-compatible endpoint, and the OpenRouter SDK can be configured to use it as a custom server URL. This gives you a type-safe client for accessing GPT, Claude, Gemini, Grok, and more, all through a single endpoint.
Note: The OpenRouter SDK is currently in beta and may have breaking changes between versions. This tutorial uses version 0.9.11. We recommend pinning your dependency to this version until the SDK reaches a stable release.
Prerequisites
- A Puter account
- Your Puter auth token, go to puter.com/dashboard and click Copy to get your auth token
- Node.js installed on your machine
Setup
Install the OpenRouter SDK:
npm install @openrouter/sdk@0.9.11
Then configure the client with Puter's server URL and your auth token:
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
Replace YOUR_PUTER_AUTH_TOKEN with the auth token you copied from your Puter dashboard. The serverURL option points the SDK at Puter's OpenAI-compatible endpoint instead of the default OpenRouter API.
Example 1: Basic Chat Completion
Let's start with the simplest possible example, a single chat completion:
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
const response = await client.chat.send({
chatGenerationParams: {
model: "gpt-5-nano",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},
});
console.log(response.choices[0].message.content);
This sends a single message to gpt-5-nano and prints the response. The chatGenerationParams object is similar to the OpenAI chat completion format, but the OpenRouter SDK uses camelCase for field names (e.g. toolCalls instead of tool_calls, toolCallId instead of tool_call_id).
Example 2: Streaming
For longer responses, streaming gives you results in real-time as they're generated:
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
const stream = await client.chat.send({
chatGenerationParams: {
model: "gpt-5-nano",
messages: [
{ role: "user", content: "Write a short story about a robot learning to paint." },
],
stream: true,
},
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
process.stdout.write(content);
}
}
Set stream: true inside chatGenerationParams and iterate over the chunks as they arrive. Each chunk contains a piece of the response that you can display immediately.
Example 3: Use a Different Model
This is where it gets interesting. Same code, same endpoint. Just swap the model parameter to use Claude, Gemini, Grok, or any other supported model:
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Use Claude
const claude = await client.chat.send({
chatGenerationParams: {
model: "claude-sonnet-4-5",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Use Claude
const claude = await client.chat.send({
chatGenerationParams: {
model: "claude-sonnet-4-5",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Use Claude
const claude = await client.chat.send({
chatGenerationParams: {
model: "claude-sonnet-4-5",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},
});
console.log("Claude:", claude.choices[0].message.content);
// Use Gemini
const gemini = await client.chat.send({
chatGenerationParams: {
model: "gemini-2.5-flash-lite",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},
});
console.log("Gemini:", gemini.choices[0].message.content);
// Use Grok
const grok = await client.chat.send({
chatGenerationParams: {
model: "grok-4-1-fast",
messages: [
{ role: "user", content: "What is the capital of France?" },
],
},
});
console.log("Grok:", grok.choices[0].message.content);
One endpoint, any model. You don't need separate SDKs, separate API keys, or separate billing accounts. Switch between providers by changing a single string.
Example 4: Tool/Function Calling
Function calling lets the model request structured data from your code. Here's an example with a simple get_weather tool:
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Define the tool
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a given location",
parameters: {
import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Define the tool
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a given location",
parameters: {import { OpenRouter } from "@openrouter/sdk";
const client = new OpenRouter({
apiKey: "YOUR_PUTER_AUTH_TOKEN",
serverURL: "https://api.puter.com/puterai/openai/v1/",
});
// Define the tool
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "Get the current weather for a given location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "City name, e.g. San Francisco",
},
},
required: ["location"],
},
},
},
];
// Send the request with tools
const response = await client.chat.send({
chatGenerationParams: {
model: "gpt-5-nano",
messages: [
{ role: "user", content: "What's the weather like in Tokyo?" },
],
tools: tools,
},
});
// Handle the tool call
const toolCall = response.choices[0].message.toolCalls?.[0];
if (toolCall) {
const args = JSON.parse(toolCall.function.arguments);
console.log(`Model wants to call: ${toolCall.function.name}`);
console.log(`With arguments:`, args);
// Simulate a tool response
const toolResult = JSON.stringify({ temperature: "22°C", condition: "Partly cloudy" });
// Send the tool result back to the model
const finalResponse = await client.chat.send({
chatGenerationParams: {
model: "gpt-5-nano",
messages: [
{ role: "user", content: "What's the weather like in Tokyo?" },
response.choices[0].message,
{
role: "tool",
toolCallId: toolCall.id,
content: toolResult,
},
],
tools: tools,
},
});
console.log(finalResponse.choices[0].message.content);
}
The model analyzes the user's question, decides it needs weather data, and returns a structured tool call. Your code executes the function, sends the result back, and the model generates a final response using that data.
Conclusion
That's it. You now have the OpenRouter TypeScript SDK configured to use Puter as a backend, giving you access to GPT, Claude, Gemini, Grok, and more through a type-safe client. No need to juggle multiple API keys or rewrite your code when you want to try a different model.
To go further, check out the full Puter.js documentation or browse the complete list of supported AI models. You can also learn more about the Puter.js AI API for additional features like vision, text-to-speech, and image generation.
Related
Free, Serverless AI and Cloud
Start creating powerful web applications with Puter.js in seconds!
Get Started Now