Migrate from OpenAI

Move an OpenAI client to Cruxy: change the base URL and the key, pass a tier as the model, and know what carries over and what differs.

Cruxy serves OpenAI-compatible chat completions at POST /v1/chat/completions and an OpenAI-compatible model list at GET /v1/models. Both take OpenAI's request and return OpenAI's response, so code written for the official openai npm package moves over with three changes: the base URL, the API key, and model.

Change three settings

SettingSet it to
Base URLhttps://api.cruxy.ai/v1
API keyYour Cruxy API key, read from CRUXY_API_KEY. It travels as Authorization: Bearer <key>, as on OpenAI.
modelA Cruxy tier, kavi, vaani, or mira, or auto to let the router pick one.

The key needs the chat endpoint family, the same as for POST /api/v1/chat; a key without it is 403. On a server, use a developer API key from the Cruxy Console: Get your API key covers the kinds of key and how to create one. Authentication, rate limits, and billing work as they do on POST /api/v1/chat.

Before and after

The same request, first to OpenAI, then to Cruxy. Only the base URL, the key, and model change; the request body and the response you read stay the same.

# OPENAI_MODEL is the OpenAI model id you call today.
curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "'"$OPENAI_MODEL"'",
    "messages": [
      { "role": "user", "content": "Hello" }
    ]
  }'

Pass a tier as model

model takes a tier or auto. Any other value, an OpenAI model id included, is 400 invalid_request. These docs map no OpenAI model to a tier: the model behind a tier is never exposed, and it can change while the tier stays the same. Choose a tier by its profile, then test it on your own prompts.

modelProfileDefault reasoning_effortmax_tokens cap
kaviDeephigh8192
vaaniBalancedlow4096
miraFastnone2048
autoThe router picks a tier for each request.Chosen per requestThe cap of the tier that serves

The response's model is the tier that served the request. With auto, it is the tier the router chose, which a budget can also have downgraded, so read it rather than assume it. Choosing a tier compares the tiers, and Auto routing covers what the router does.

GET /v1/models returns OpenAI's list shape, {"object": "list", "data": [...]}, and its ids are the tiers. For each tier's context window, output cap, tool support, and reasoning defaults, read GET /api/v1/models; see Models.

What carries over unchanged

  • The request. messages with the system, user, assistant, and tool roles, plus temperature, top_p, max_tokens, stream, stream_options, tools, tool_choice, response_format, and reasoning_effort.
  • The response. A chat.completion object with id, object, created, model, choices[].message, choices[].finish_reason (stop, tool_calls, length, or content_filter), and usage with prompt_tokens, completion_tokens, and total_tokens.
  • Streaming. chat.completion.chunk frames that end with data: [DONE], and a usage frame only when you set stream_options.include_usage.
  • Tool calling. tools and tool_choice on the request, tool_calls on the assistant message, and a tool message with tool_call_id for each result.
  • Errors. OpenAI's envelope, {"error": {"message", "type", "param", "code"}}, which the SDK raises as an APIError.

What differs

  • model is a tier, and the response's model names the tier that served.
  • Fields Cruxy does not implement are ignored, not rejected: n, stop, seed, presence_penalty, frequency_penalty, logit_bias, logprobs, user, and the rest. A request that sends them still runs, and they have no effect.
  • max_tokens is clamped to the tier's cap, and thinking spends it. kavi thinks by default, so a small max_tokens on kavi can end with finish_reason: "length" and empty content.
  • reasoning_effort takes none, low, medium, or high. Any other value, OpenAI's minimal included, is 400 invalid_request.
  • A non-streaming call has a deadline: 90 seconds on kavi and vaani, 45 on mira. Past it, the call is 504 upstream_timeout.
  • An error's code is a Cruxy code, and param is always null.
  • The route carries none of the Cruxy-native chat features: no memory, no standing rules, no vaults, no file_ids, and no cruxy block. For those, call POST /api/v1/chat; see Chat.
  • The request ID is only in a header, X-Request-Id, and the response's usage carries no cost.
  • A tool call's id may not start with call_. Treat it as opaque.

OpenAI SDK compatibility covers each of these parameter by parameter, with streaming, errors, and how the SDK retries.

Next steps

Was this page helpful?