Skip to content

Quickstart

Inferray speaks three text formats — OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages — and every text model answers on all three. Image models have their own endpoint. Keep your SDK, keep your prompts, and change two things: the base URL and the key.

  • Base URLhttps://api.inferray.com/v1
  • AuthAuthorization: Bearer inferray_..., or x-api-key if your SDK sends that

Create a key

Sign up and create a key in the console. Keys are scoped to a project, so you can keep staging and production spend apart from the first request.

export INFERRAY_API_KEY="inferray_..."

The full secret is shown once, when the key is created. Store it then.

Chat Completions

The OpenAI-compatible endpoint, at /v1/chat/completions. Your Inferray key goes where your provider key used to; everything else in the call stays the same.

import OpenAI from "openai";

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

const resp = await client.chat.completions.create({
  model: "gpt-5.5",
  messages: [{ role: "user", content: "ship it" }],
});

console.log(resp.choices[0].message.content);
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://api.inferray.com/v1",
    api_key=os.environ["INFERRAY_API_KEY"],
)

resp = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "ship it"}],
)

print(resp.choices[0].message.content)
curl https://api.inferray.com/v1/chat/completions \
  -H "Authorization: Bearer $INFERRAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [{"role": "user", "content": "ship it"}]
  }'

Messages

The Anthropic-compatible endpoint, at /v1/messages. Every model in the catalogue answers on it — the OpenAI and Google ones too, not only Claude. The Anthropic SDK's x-api-key header works exactly like the bearer token.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://api.inferray.com",
  apiKey: process.env.INFERRAY_API_KEY,
});

const msg = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  messages: [{ role: "user", content: "ship it" }],
});

Responses

The other OpenAI-compatible endpoint, at /v1/responses. It is what Codex and the newer OpenAI SDK methods speak, and every model in the catalogue answers on it — Claude and Gemini included.

import OpenAI from "openai";

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

const response = await client.responses.create({
  model: "gpt-5.5",
  input: "ship it",
});

console.log(response.output_text);
curl https://api.inferray.com/v1/responses \
  -H "Authorization: Bearer $INFERRAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "input": "ship it"
  }'

store is passed through as you send it. Set store: false and the response is not retained upstream; leave it unset and the provider's default applies. Note that Inferray serves POST /v1/responses only — the retrieval, cancel, and delete routes for stored responses are not exposed, so treat a stored response as something the provider holds rather than something you can fetch back through Inferray.

List the models

GET /v1/models returns the catalogue in the shape OpenAI clients expect, so a tool that populates its model picker from the API finds one.

curl https://api.inferray.com/v1/models \
  -H "Authorization: Bearer $INFERRAY_API_KEY"
{
  "object": "list",
  "data": [
    { "id": "claude-opus-4-8", "object": "model", "created": 1700000000, "owned_by": "anthropic" }
  ]
}

The list is the catalogue itself, so every id it returns is one you can call on any of the three endpoints. It costs nothing and is never billed, but it does require a valid key — which makes it a quick way to check that a key works.

Streaming

Set stream: true and tokens arrive as they are generated. Usage is still counted, so streamed requests show up in your logs like any other.

const stream = await client.chat.completions.create({
  model: "gpt-5.5",
  messages: [{ role: "user", content: "ship it" }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Coding agents

Most agents need a base URL and a key and nothing else. Claude Code takes two environment variables; the others want a provider block or a settings form. Each one has its own page under coding agents.

Errors

Errors come back in the shape your SDK already expects, with a message that says what to do about it.

StatusWhat it means
401The key is missing, malformed, or no longer active.
402Your balance is too low to cover the request. Top up, or turn on auto top-up.
404That model isn't on this endpoint. The response lists the ones that are.
503We couldn't confirm your balance, so nothing was sent or charged. Retry.

Next