Disclosure and availability: DaoXE is a service we operate. It is not available in mainland China. This article is for developers in regions allowed by the service terms.
Changing baseURL in an OpenAI SDK takes one line. Proving that the new endpoint is configured correctly is the harder part.
When an integration fails, it is tempting to change the API key, model, prompt, timeout, and response parser at the same time. That usually creates more uncertainty. I prefer a three-step smoke test that isolates one layer at a time:
- verify authentication and the base URL;
- discover a model ID that the current account can actually use;
- send one small generation request with retries disabled.
The result is not a benchmark or a reliability guarantee. It is a repeatable way to answer a narrower question: can this exact account, endpoint, model, and runtime complete one request right now?
This walkthrough uses DaoXE as the example endpoint, but the same sequence works with other OpenAI-compatible services.
1. Keep every variable outside the code
Start with the API key and base URL. Do not put a real key in source code, screenshots, issue reports, or shell snippets that will be committed.
export DAOXE_API_KEY="your_api_key"
export DAOXE_BASE_URL="https://daoxe.com/v1"
Do not set the model yet. Model access can vary by account and can change over time. Copying a model name from an old tutorial adds an unnecessary variable before authentication has even been checked.
If you use a .env file locally, make sure it is ignored by Git. In production, use the secret manager provided by your deployment platform.
2. Discover a model through the current account
Call the Models endpoint first:
curl --fail-with-body --show-error --silent \
"${DAOXE_BASE_URL}/models" \
-H "Authorization: Bearer ${DAOXE_API_KEY}"
This request checks two things without running a generation:
- whether the key and base URL authenticate successfully;
- which exact model IDs the account currently sees.
If jq is installed, reduce the response to model IDs:
curl --fail-with-body --show-error --silent \
"${DAOXE_BASE_URL}/models" \
-H "Authorization: Bearer ${DAOXE_API_KEY}" \
| jq -r '.data[].id'
Choose one ID from that response and copy it exactly:
export DAOXE_MODEL="copy_an_exact_id_from_the_current_response"
Avoid permanently hard-coding a model name from documentation. A successful request in somebody else's account does not prove that the same ID is available to your account today.
3. Send one deliberately small request
Create an empty Node.js project and install the OpenAI SDK:
npm init -y
npm install openai
Create smoke-test.mjs:
import OpenAI from "openai";
const required = ["DAOXE_API_KEY", "DAOXE_BASE_URL", "DAOXE_MODEL"];
const missing = required.filter((name) => !process.env[name]);
if (missing.length > 0) {
console.error(`Missing environment variables: ${missing.join(", ")}`);
process.exit(1);
}
const client = new OpenAI({
apiKey: process.env.DAOXE_API_KEY,
baseURL: process.env.DAOXE_BASE_URL,
timeout: 30_000,
maxRetries: 0,
});
const startedAt = performance.now();
try {
const response = await client.chat.completions.create({
model: process.env.DAOXE_MODEL,
messages: [{ role: "user", content: "Reply with only OK." }],
max_tokens: 8,
});
const elapsedMs = Math.round(performance.now() - startedAt);
console.log({
ok: true,
elapsedMs,
model: response.model,
content: response.choices?.[0]?.message?.content,
usage: response.usage,
});
} catch (error) {
const elapsedMs = Math.round(performance.now() - startedAt);
console.error({
ok: false,
elapsedMs,
status: error.status,
type: error.name,
});
process.exit(1);
}
Run it:
node smoke-test.mjs
This request can incur a charge. Check the live model catalog, account status, and pricing before running it.
The max_tokens: 8 limit keeps the connectivity check small; it is not a recommendation for normal application traffic. I also set maxRetries: 0 on purpose. During first-pass debugging, an automatic retry can hide the original failure or turn one uncertain request into several billable requests.
What a successful result actually proves
A successful run proves that, at that moment, the following combination completed one request:
- runtime and network path;
- API base URL;
- API key and account permissions;
- exact model ID;
- SDK request and response shape.
It does not prove long-term availability, output quality, latency distribution, or total application cost.
For a useful test record, keep the timestamp, environment, HTTP result, elapsed time, returned model field, and token usage. Do not log the API key or the complete Authorization header.
Diagnose one layer at a time
| Symptom | Check first | Next action |
|---|---|---|
401 |
Empty, expired, or whitespace-padded key | Re-inject the key securely, then repeat the Models request |
403 |
Account permissions or regional eligibility | Review the account state and service terms; do not try to bypass the restriction in code |
404 |
Versioned baseURL and combined resource path |
Print only non-sensitive URL configuration and inspect the final path |
| Model not found | Whether the ID came from the current Models response | Discover the models again and copy the ID exactly |
429 |
Current rate, quota, and account state | Read the response details before choosing a backoff policy |
| Timeout or network error | DNS, TLS, proxy, and runtime egress | Run the Models request from the same environment to separate network and generation failures |
5xx |
Temporary service or upstream failure | Save the timestamp and request identifier, then retry a limited number of times later |
The important rule is to change one layer at a time. If authentication is failing, changing the prompt cannot help. If model discovery works but generation fails, the problem is already narrower.
Add retries only after the raw path works
Retries are not automatically safe. A request may have executed on the server even when the client did not receive the response. Blindly retrying can duplicate work and cost.
Before enabling retries, decide:
- which status codes are retryable;
- how long each backoff should be;
- the maximum number of attempts;
- whether the application needs an idempotency mechanism;
- which non-sensitive request context should be recorded.
Put the smoke test behind a manual CI job
I split CI into two layers:
- normal pull requests run static checks and mocked contract tests without a real API key;
- a protected, manually triggered job runs the live smoke test with a secret and a strict execution limit.
That catches code regressions without sending a billable request on every commit. Secret masking is helpful, but the safer default is still never to print the secret.
The reusable sequence
For any OpenAI-compatible endpoint, the shortest useful validation sequence is:
- separate configuration from application code;
- call the Models endpoint with the current account;
- copy an exact model ID from the response;
- send one bounded request with retries disabled;
- record the result without recording credentials;
- add streaming, tool calls, concurrency, and retry behavior only after the minimal path works.
If your region is supported by the service terms, you can inspect DaoXE. The public examples include cURL, Node.js, Python, and Postman, plus Simplified Chinese and Traditional Chinese guides.
Top comments (0)