SDK
Migrating from another gateway
Conifer speaks the OpenAI wire, so the base URL and the key are most of the work. This page is about the rest.
Coming from Vercel AI Gateway, OpenRouter, or Helicone, the mechanical change is two lines. The part that usually goes wrong quietly is the handful of fields that have no Conifer equivalent — so those are named here rather than dropped.
Vercel AI Gateway
- baseURL: "https://ai-gateway.vercel.sh/v1"
- apiKey: process.env.AI_GATEWAY_API_KEY
+ baseURL: "https://api.conifer.build/v1"
+ apiKey: process.env.CONIFER_API_KEYBoth gateways serve POST /chat/completions, GET /models, and GET /models/{model} on the OpenAI spec. If you use the AI SDK, the supported path is the @ai-sdk/openai-compatible provider:
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";
export function conifer() {
const apiKey = process.env.CONIFER_API_KEY;
if (!apiKey) {
throw new Error("CONIFER_API_KEY is missing. Set it before calling the gateway.");
}
return createOpenAICompatible({
name: "conifer",
baseURL: "https://api.conifer.build/v1",
apiKey,
});
}
export async function POST(req: Request) {
const { text } = await generateText({
model: conifer()("claude-haiku-4-5"),
prompt: "three names for a build cache",
});
return Response.json({ text });
}OpenRouter
- baseURL: "https://openrouter.ai/api/v1"
- apiKey: process.env.OPENROUTER_API_KEY
+ baseURL: "https://api.conifer.build/v1"
+ apiKey: process.env.CONIFER_API_KEYModel ids need no rewriting. An id like anthropic/claude-opus-5 is tried in full first, then by its last segment, so it lands on the catalog’s claude-opus-5 without you editing every call site.
OpenRouter returns cost as credits on the response body and offers /api/v1/generation for stats after the fact. Conifer settles onto the same response’s headers, so the numbers are already in hand when the call returns.
Helicone
- baseURL: "https://gateway.helicone.ai/v1"
- defaultHeaders: {
- "Helicone-Auth": `Bearer ${process.env.HELICONE_API_KEY}`,
- "Helicone-Target-URL": "https://api.openai.com",
- }
+ baseURL: "https://api.conifer.build/v1"
+ apiKey: process.env.CONIFER_API_KEYHelicone proxies in front of your provider key. Conifer is the biller and router itself, so there is no second credential and no target URL. If you want your own provider key used, that is BYOK custody — save it once and keep calling with CONIFER_API_KEY. See Add Azure OpenAI for that shape.
Helicone-RateLimit-Policy in u=cents maps onto the per-request cost ceiling below, which is a stronger control: money rather than request count. A u=requests policy has no equivalent.
What carries over unchanged
| Field | On Conifer |
|---|---|
| model | Identical. OpenRouter-style vendor/model ids resolve to the catalog id, so nothing is rewritten by hand. |
| messages, tools, tool_choice | Identical OpenAI shapes, forwarded verbatim. |
| stream | Identical SSE. Ask for stream_options.include_usage and the final usage chunk arrives. |
| response_format | Forwarded to the upstream; honored where the upstream honors it. |
| usage.prompt_tokens_details.cached_tokens | Same field name, same meaning. |
What does not, and why it errors instead
These are refused at the call site rather than dropped. A migration that silently loses a provider pin or a moderation flag looks successful while changing what runs and what it costs.
| Feature | Where it comes from | Why Conifer refuses it |
|---|---|---|
| Provider pinning | OpenRouter provider, Vercel gateway.order | Conifer picks the host for the model you named, by price and health. A client cannot pin it. The model itself is never substituted. |
| Server-side fallbacks | OpenRouter models, Helicone-Fallbacks | The gateway admits exactly one model per request. A fallback list becomes a client-side chain of separate billed calls, which you opt into. |
| Prompt rewriting | OpenRouter transforms, Helicone token-limit handlers | Nothing here truncates or middle-outs your prompt. An over-window request gets a typed 400 naming the window, so you choose what to cut. |
| Moderation, injection scanning, prompt registries | Helicone feature flags | Conifer runs none of these. A security control that silently does nothing is worse than one that errors. |
| Embeddings and image generation | Vercel /embeddings | No such door here. Keep those calls on your current provider. |
Fallback lists, specifically
Conifer admits exactly the model you name — that is what makes the price you were quoted the price you are charged. A fallback list is therefore a client-side chain: one full request per member, each billed on its own, and only a retryable failure advances it. A 402 or a bad request is the same answer on every member, so the chain stops.
What you gain: the cost of the call, on the call
A buffered (non-streamed) response carries the settled cost of that exact request in integer nanodollars ($1 = 1e9), itemized across the four billed token classes. There is no second stats request to make and no float dollars to reconcile.
import OpenAI from "openai";
export async function POST(req: Request) {
const res = await conifer().chat.completions
.create({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "three names for a build cache" }],
})
.withResponse();
// Integer nanodollars ($1 = 1e9) for THIS call. No second stats request.
const cost = res.response.headers.get("x-conifer-cost-nanousd");
// fresh=<n>,cache_write=<n>,cache_read=<n>,output=<n> — the four sum to cost.
const itemized = res.response.headers.get("x-conifer-cost-components-nanousd");
return Response.json({ cost, itemized });
}x-conifer-cost-components-nanousd always sums to x-conifer-cost-nanousd. When that identity cannot be guaranteed the header is omitted rather than approximated, so absence means “not known”, never zero.
And a spend ceiling the gateway enforces
x-conifer-max-cost-nanousd is a hard bound on the caller-total worst case, checked before any upstream call. Over it, the request is refused with cost_ceiling_exceeded and nothing is spent.
curl https://api.conifer.build/v1/chat/completions \
-H "Authorization: Bearer $CONIFER_API_KEY" \
-H "Content-Type: application/json" \
-H "x-conifer-max-cost-nanousd: 5000000" \
-d '{
"model": "claude-haiku-4-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "three names for a build cache"}]
}'