Skip to content
Relaykit
DocsMigrating

Optimize

Migrating

Move existing code from the OpenAI API, the Anthropic API, OpenRouter or another gateway. Change the base URL, key and model ids, then check the few features that differ.

Updated View .md
On this page

Most code moves over with three changes: the base URL, the API key, and the model id. Request and response shapes stay the same, because Relaykit speaks the OpenAI and Anthropic formats directly. This page lists those changes and the features that behave differently.

The short version

  1. Create a key under API keys.
  2. Point your SDK or tool at the base URL for the format it uses.
  3. Replace model ids with ids from the models table.
  4. Run your tests, then read the section below for where you came from.

If your code reads the standard environment variables, you may not need to touch it at all:

.env
# OpenAI SDKs (Python, Node, and most tools built on them)
OPENAI_BASE_URL=https://api.oneaiapikey.com/v1
OPENAI_API_KEY=<your Relaykit key>

# Anthropic SDKs (no /v1 at the end)
ANTHROPIC_BASE_URL=https://api.oneaiapikey.com
ANTHROPIC_API_KEY=<your Relaykit key>

From the OpenAI API

import os
from openai import OpenAI

# Before: client = OpenAI()
client = OpenAI(
    base_url="https://api.oneaiapikey.com/v1",
    api_key=os.environ["RELAYKIT_API_KEY"],
)

reply = client.chat.completions.create(
    model="gpt-5.6-terra",   # an id from the models table
    messages=[{"role": "user", "content": "Hello"}],
)
import OpenAI from "openai";

// Before: const client = new OpenAI();
const client = new OpenAI({
  baseURL: "https://api.oneaiapikey.com/v1",
  apiKey: process.env.RELAYKIT_API_KEY,
});

const reply = await client.chat.completions.create({
  model: "gpt-5.6-terra", // an id from the models table
  messages: [{ role: "user", content: "Hello" }],
});
  • Works the same: chat completions, streaming with stream_options, tools and parallel tool calls, response_format on GPT models, images in messages, reasoning_effort, and the Responses API on GPT models.
  • Stateless only: the Responses API does not store responses for you to fetch later. Send the full history each time instead of relying on stored state.
  • Not available: Assistants, Threads, Files, Batch, fine-tuning and image variations. Requests to them fail with 404 or 501.
  • Other models, same code: you can now send the same request to Claude, Grok, DeepSeek and other families. Read Claude models in this format before you switch a request that uses response_format.

From the Anthropic API

import anthropic, os

# Before: client = anthropic.Anthropic()
client = anthropic.Anthropic(
    base_url="https://api.oneaiapikey.com",   # no /v1: the SDK adds /v1/messages
    api_key=os.environ["RELAYKIT_API_KEY"],
)

message = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
import Anthropic from "@anthropic-ai/sdk";

// Before: const client = new Anthropic();
const client = new Anthropic({
  baseURL: "https://api.oneaiapikey.com", // no /v1: the SDK adds /v1/messages
  apiKey: process.env.RELAYKIT_API_KEY,
});

const message = await client.messages.create({
  model: "claude-sonnet-5-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Hello" }],
});
  • Works the same: Messages with streaming, system prompts, tools, images and PDFs, cache_control prompt caching, extended thinking, and anthropic-beta headers, which are passed through.
  • Base URL: no /v1 at the end. The SDKs and Claude Code add /v1/messages themselves.
  • Not available: token counting (/v1/messages/count_tokens), Message Batches and the Files API. Estimate tokens on your side, or read usage from the reply.
  • Claude Code and agents: see the Claude Code guide for the two environment variables it needs.

From OpenRouter or another gateway

  • Model ids have no provider prefix here. Look up each model in the models table; spellings and version numbers can differ from other gateways, so copy the id rather than editing the old one.
  • The OpenAI-style request is the same, including the reasoning object ({"effort": "high"}). Extra attribution headers such as HTTP-Referer or X-Title are not needed and can stay.
  • Routing options such as provider preferences or a models fallback list are not used here. Each model id goes to one route. If you relied on automatic fallback, put the fallback in your own code (see Rate limits and retries).
  • Billing is a prepaid balance in US dollars. Each request is billed at the rates on the models page; there is no per-request platform fee on top.

Features that differ by model

Check that it worked

Send one cheap request, then open the usage page. The request should be listed with its model, key, tokens and cost. If it fails, the Errors page explains each status code.

↑ ↓ moveEnter openEsc close