# The 3-step smoke test I use for any OpenAI-compatible API

> Source: <https://dev.to/seven7763/the-3-step-smoke-test-i-use-for-any-openai-compatible-api-311g>
> Published: 2026-07-12 05:48:06+00:00

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:

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.

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.

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:

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.

Create an empty Node.js project and install the OpenAI SDK:

```
npm init -y
npm install openai
```

Create `smoke-test.mjs`

:

``` python
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.

A successful run proves that, at that moment, the following combination completed one request:

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.

| 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.

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:

I split CI into two layers:

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.

For any OpenAI-compatible endpoint, the shortest useful validation sequence is:

If your region is supported by the service terms, you can inspect [DaoXE](https://daoxe.com/?utm_source=devto&utm_medium=organic&utm_campaign=global_launch). The public examples include [cURL, Node.js, Python, and Postman](https://github.com/seven7763/DaoXE-AI), plus [Simplified Chinese](https://github.com/seven7763/DaoXE-AI/blob/main/README.zh-CN.md) and [Traditional Chinese](https://github.com/seven7763/DaoXE-AI/blob/main/README.zh-TW.md) guides.
