An OpenAI-compatible API is a service that speaks the same request and response format as OpenAI’s API — the same chat completions endpoint, the same Authorization: Bearer header, and the same choices[0].message.content response — so client code built on the OpenAI SDK can call it after changing the base URL and the API key. Novita AI’s LLM API exposes this interface at https://api.novita.ai/openai, which means the SDK call keeps its shape and only the connection details move.
Here is the change in full. Two connection lines differ, and the model value has to name something the new endpoint actually serves:
from openai import OpenAI
client = OpenAI(
base_url="https://api.novita.ai/openai", # was https://api.openai.com/v1
api_key="YOUR_NOVITA_API_KEY", # was your OpenAI API key
)
response = client.chat.completions.create(
model="deepseek/deepseek-v4.1-flash",
messages=[{"role": "user", "content": "Summarize an OpenAI-compatible API in one sentence."}],
max_tokens=128,
)
print(response.choices[0].message.content)
The rest of this guide explains what “compatible” actually guarantees, where a compatible endpoint diverges from OpenAI’s own API, and which details break first when you move real traffic.
What makes an API “OpenAI-compatible”?
Compatibility is a contract about shape, not a single flag. An endpoint is OpenAI-compatible when a client written for OpenAI’s API can connect to it without structural changes: the same paths, the same authentication, and the same JSON field names for requests and responses.
The contract has four parts that matter in practice.
Endpoint paths. Chat traffic goes to /v1/chat/completions, plain text completion to /v1/completions. Compatible providers usually add embeddings, model listing, and batch routes under the same v1 prefix so SDK methods that call them keep working.
Authentication. Requests carry Content-Type: application/json and Authorization: Bearer <api-key>. The header name and scheme match OpenAI; only the key itself comes from the new provider.
Request schema. A chat request has a required model string and a messages array of objects with role (system, user, or assistant) and content. Sampling and control parameters — temperature, top_p, max_tokens, stop, stream, tools, response_format — reuse OpenAI’s names so existing request bodies parse. Some providers also accept parameters OpenAI does not, such as top_k, min_p, repetition_penalty, and reasoning controls like enable_thinking.
Response schema. The response returns choices[], where each choice has a message with content and a finish_reason, plus an object field set to chat.completion, a usage object with prompt_tokens, completion_tokens, and total_tokens, and a unique id. Code that reads response.choices[0].message.content works against either service because the path to the text is identical.
Novita AI’s create chat completion endpoint documents this exact set: bearer authentication, the model and messages fields, the streaming flag, tool definitions, and structured-output formats. The LLM API guide states the intent directly — if you already use OpenAI’s ChatCompletion or Completion API, set the base URL to api.novita.ai/openai, set your key, and update the model name.
What compatibility does not guarantee is behavioral equivalence. Two endpoints can accept the same request and still differ on which parameters they honor, which models exist, how errors are shaped, and how streaming reports usage. The next section maps those differences.
OpenAI-compatible API vs. the official OpenAI API
The table compares OpenAI’s own API with what a typical third-party compatible endpoint delivers. It is a pattern view, not a claim about any one provider; check the provider’s own reference before you depend on a specific field.
| Dimension | Official OpenAI API | A typical OpenAI-compatible API |
|---|---|---|
| Base URL | https://api.openai.com/v1 | Provider-defined, for example https://api.novita.ai/openai |
| Authentication | Authorization: Bearer <OPENAI_API_KEY> | Same header and scheme, different key |
model values | OpenAI’s own model names | The provider’s catalog IDs, usually namespaced with an organization prefix (vendor/model-name) |
| Streaming | Server-sent events, data: chunks ending with data: [DONE] | Same SSE envelope; chunk payloads and usage reporting can differ |
| Function calling | tools plus tool_calls, with finish_reason: "tool_calls" | Supported, but only on models that advertise the feature; finish_reason values in provider docs may list only stop and length |
| Unsupported parameters | Rejected with a 400 invalid-request error | Behavior varies: some reject, some ignore, some accept provider-specific extensions |
| Extra response fields | Not present | Providers may add fields such as reasoning_content for reasoning models |
Interface details for Novita AI from its API reference, and the OpenAI column reflects OpenAI’s documented chat completions format; both checked October 14, 2026.
The practical reading: the SDK connection and the response-reading path transfer cleanly, while model names, parameter coverage, tool behavior, and error semantics are provider-specific and need testing. Treat the compatible surface as the part you can rely on and the rest as the part you verify.
How to migrate existing OpenAI SDK code to a compatible endpoint
The migration is deliberately small. The steps below use Novita AI as the target, but the shape applies to any OpenAI-compatible endpoint.
1. Keep the SDK
You do not need a new client library. The official openai package works against any compatible base URL:
pip install openai
2. Change the base URL and the API key
In most codebases those are two lines. Before:
client = OpenAI(
base_url="https://api.openai.com/v1",
api_key=os.environ["OPENAI_API_KEY"],
)
After:
client = OpenAI(
base_url="https://api.novita.ai/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
The SDK appends the route it needs — /chat/completions for chat — so you set the base URL, not the full endpoint. Read your key from the environment rather than hard-coding it, and keep it server-side.
3. Point model at a model the endpoint serves
This is the third change, and it is the one that surprises people. OpenAI’s model names do not exist on another provider. Replace them with an entry from the provider’s own catalog, and put the exact ID that catalog lists in the model field. For Novita AI, a current example is DeepSeek V4.1 Flash; the model catalog is the list to check, because availability and IDs change. A display name is not a valid substitute for the API ID.
4. Verify the response shape, then the edge cases
Run one small request and confirm response.choices[0].message.content returns text. Then test the features your application actually depends on: streaming, tool calls, structured output, and long prompts. A short text completion proves connectivity, not production readiness.
If you call the API without the SDK, the raw route differs from the base URL. A cURL request posts to the versioned path:
curl --request POST "https://api.novita.ai/openai/v1/chat/completions" \
--header "Authorization: Bearer $NOVITA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "deepseek/deepseek-v4.1-flash",
"messages": [{"role": "user", "content": "Summarize an OpenAI-compatible API in one sentence."}],
"max_tokens": 128
}'
Match the provider’s own example rather than assuming the path: the SDK base URL and the raw HTTP route are not always the same string. Full parameter coverage lives in the API reference, and a first-call walkthrough is in the LLM API guide.
Common pitfalls when switching providers
These are the failures that show up after the first successful call, not before it.
Model IDs do not carry over. Every compatible provider names models in its own namespace. A request that sends an OpenAI model name returns a not-found or invalid-model error. Keep the model ID in configuration, not scattered through code, so switching is one edit.
Parameter support differs. A field being accepted does not mean it is applied. Some providers require max_tokens on the chat completion call; OpenAI treats it as optional. Others add parameters OpenAI has no equivalent for — top_k, min_p, repetition_penalty, and reasoning switches — which OpenAI clients will not send. Audit the parameters your app sets and confirm each one against the provider’s reference.
Function calling depends on the model. Tool use is not universal across a catalog. Only models that advertise function calling support the tools field, and strict-schema support varies. Confirm both the model’s capability and the provider’s finish_reason values before wiring tools into a workflow.
Streaming and usage reporting differ. Streaming uses the same server-sent-events envelope, but where usage numbers appear can change. Some providers only include token usage in the final chunk. Parse defensively and do not assume a usage object on every chunk.
Errors and rate limits are provider-specific. HTTP status codes and error body shapes are not guaranteed to match OpenAI’s, so retry and backoff logic keyed on OpenAI error codes may misfire. Rate limits are usually tied to your account tier, so measure against your own limits instead of assuming a fixed throughput.
Context and reasoning behave differently at the edges. Some providers lower max_tokens to fit the context window instead of returning an error when a prompt is too long, which hides overflow until output is short. Reasoning models bill thinking tokens as output and count them toward max_tokens; set the limit too low and you can get empty content with a length finish reason. Fields such as reasoning_content are extensions, so code that reads them will not port to a provider that does not return them.
Conclusion
An OpenAI-compatible API is a compatibility layer over OpenAI’s request and response format, not a clone of OpenAI’s service. The connection is portable — the same SDK, the same bearer header, the same path to the text — so migration is genuinely a small edit to base_url and the API key. Everything past the connection is provider-specific: model IDs, parameter coverage, tool support, streaming details, and error handling. Change the two lines, then verify model names, parameters, tools, and errors before you move production traffic. Novita AI’s compatible endpoint is at https://api.novita.ai/openai, and its models, limits, and pricing are listed on the model catalog.
FAQ
Is every model behind an OpenAI-compatible API actually callable with the OpenAI SDK?
Usually yes for basic chat, because the SDK only needs the endpoint shape, the bearer header, and the response fields to match. Feature-level compatibility varies by model, so a model may answer chat requests while returning nothing useful for tools or structured output. Test the features you depend on rather than the endpoint alone.
Can I switch providers without changing any code?
No. You can keep the SDK and most of the code, but at least three values change: the base URL, the API key, and the model ID. Anything that inspects provider-specific response fields or error codes may need adjustment too.
Does an OpenAI-compatible API support function calling and structured outputs?
It can, but support is opt-in per model. The endpoint exposes the tools and response_format fields, and models that advertise function calling or structured output honor them. Confirm the specific model’s capabilities on the provider’s model page before relying on either.
Why does my OpenAI model name fail on a compatible endpoint?
Because each provider serves its own catalog. OpenAI model names resolve only on OpenAI’s API; a compatible endpoint expects its own model IDs, usually namespaced with an organization prefix. Replace the model value with the exact ID listed on the provider’s model page.
Is an OpenAI-compatible API the same as the OpenAI API?
No. It replicates the interface — paths, authentication, and request and response schemas — so compatible clients connect, but it runs the provider’s own models on the provider’s infrastructure. Same shape, different models and operating behavior.
What should I verify first when migrating production traffic?
Verify the response shape on a real prompt, then the features your app uses: streaming, tool calls, structured output, and long-context handling. Check error responses and rate limits last, because they determine how your retry and fallback logic behaves under load.
Sources
- Novita AI LLM API guide — OpenAI-compatible base URL and Python example; checked October 14, 2026.
- Novita AI create chat completion reference — request headers, parameters, and response fields; checked October 14, 2026.
- OpenAI API reference overview — official request and response format; checked October 14, 2026.