Migration
fremai speaks the OpenAI wire format, so migrating is mostly a configuration change. This guide covers moving from the OpenAI API (nearly drop-in) and from the Anthropic API (a small shape change).
From OpenAI
Three changes, no code rewrite:
- Base URL →
https://api.fremai.eu/v1 - API key → your
sk-fremai-…key - Model → a fremai catalog id (e.g.
glm-5.2) — see Models
Everything else stays: request/response shapes, streaming (SSE chat.completion.chunk + data: [DONE]), the usage object, and the error envelope.
from openai import OpenAI
client = OpenAI(
base_url="https://api.fremai.eu/v1", # was: default OpenAI URL
api_key="sk-fremai-…", # was: sk-…
)
resp = client.chat.completions.create(
model="glm-5.2", # was: an OpenAI model name
messages=[{"role": "user", "content": "Hello"}],
)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.fremai.eu/v1", // was: default OpenAI URL
apiKey: process.env.FREMAI_API_KEY, // was: sk-…
});
const resp = await client.chat.completions.create({
model: "glm-5.2", // was: an OpenAI model name
messages: [{ role: "user", content: "Hello" }],
});Checklist
- Point every client base URL at
https://api.fremai.eu/v1. - Swap keys to
sk-fremai-…(store server-side, never in a browser/mobile client). - Map each OpenAI model to a fremai catalog id.
- Confirm the endpoints you use are supported:
chat/completions,completions,embeddings,models. - Keep your retry logic — honour
Retry-Afteron429(see rate limits).
From Anthropic
The Anthropic Messages API differs in shape from OpenAI. Switching to fremai means adopting the OpenAI-style request, which most SDKs and frameworks already support:
| Anthropic | fremai (OpenAI-compatible) |
|---|---|
POST /v1/messages | POST /v1/chat/completions |
x-api-key header + anthropic-version | Authorization: Bearer sk-fremai-… |
Top-level system string | A messages entry with role: "system" |
content blocks (array of typed parts) | messages[].content string |
max_tokens (required) | max_tokens (optional) |
stream → Anthropic event types | stream → SSE chat.completion.chunk, ends data: [DONE] |
Response content[].text | Response choices[0].message.content |
The simplest path is to use an OpenAI SDK (or a framework like LangChain) pointed at fremai, rather than adapting the Anthropic SDK. Merge any Anthropic system prompt into a leading system message and flatten content blocks to a string.
Verifying the switch
Run one call against fremai and confirm you get a chat.completion back:
curl https://api.fremai.eu/v1/chat/completions \
-H "Authorization: Bearer $FREMAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"glm-5.2","messages":[{"role":"user","content":"ping"}]}'Then roll the base-URL/key change through the rest of your services. Because the wire format is identical to OpenAI, existing tests that assert on OpenAI response shapes keep passing.