The short answer
Configure the client with the common API root, such as https://api.example.com/v1. Do not include /chat/completions in the Base URL because the SDK adds that operation path itself.
- 1
Start with the provider's documented API root. It commonly ends in
/v1. - 2
Request
/modelsfirst to check the route, credential, and available model IDs. - 3
Use one returned model ID for a minimal
/chat/completionsrequest. - 4
If one route works and the other fails, treat it as partial compatibility—not a network failure.
Understand the URL before changing it
An OpenAI-compatible URL has three useful parts. The origin identifies the server. The Base path identifies the API version or gateway prefix. The operation identifies the capability being called.
https://api.example.comOriginScheme, host, and optional port.
/v1Base pathThe value normally supplied to the SDK.
/chat/completionsOperationAdded by the SDK method you call.
Omitting /v1 can send requests to a nonexistent route. Including the full operation can make an SDK append it again. Always inspect the final request URL when diagnosing a 404.
Configure curl, Python, and Node.js
Keep the credential outside source code. The examples use placeholder values and the same API root so you can compare what each client sends.
curl https://api.example.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
curl https://api.example.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-id",
"messages": [{"role": "user", "content": "Reply with OK"}]
}'from openai import OpenAI
client = OpenAI(
base_url="https://api.example.com/v1",
api_key="your-api-key",
)
response = client.chat.completions.create(
model="your-model-id",
messages=[{"role": "user", "content": "Reply with OK"}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.example.com/v1",
apiKey: process.env.OPENAI_API_KEY,
});
const response = await client.chat.completions.create({
model: "your-model-id",
messages: [{ role: "user", content: "Reply with OK" }],
});
console.log(response.choices[0].message.content);Configuration names follow the official OpenAI Python SDK and OpenAI Node SDK. A compatible provider can use the same client interface while implementing a different server.
Diagnose the response you actually receive
Do not change several settings at once. The HTTP status and response shape usually identify the next useful check.
| Symptom | Likely layer | Check next |
|---|---|---|
| DNS, TLS, or connection error | Network | Host, port, scheme, service availability |
401 or 403 | Authentication | API key, header format, provider permissions |
404 | Route | Missing or duplicated /v1; wrong gateway prefix |
| HTML instead of JSON | Route or proxy | Reverse-proxy fallback, login page, wrong public origin |
| Models work; chat fails | Compatibility | Chat route implementation and request schema |
| Model not found | Configuration | Use the exact ID returned by /models |
Verify more than reachability
A successful /models request proves only that one route is reachable. LLMCompat checks model listing, basic chat, SSE streaming, tool calling, the tool-result round trip, and JSON mode, then records the failure layer and evidence for each conclusion.