AI models — one OpenAI-compatible endpoint
Call every model we host from any OpenAI client by changing one string. Streaming, bring-your-own-key, scheduling and tool chaining.
Updated August 12, 2026
Every model we host is reachable through one OpenAI-compatible endpoint, with the ToolsXpo API key you already have. If you have code that talks to OpenAI, you change one string.
Point a client at it
```js import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.toolsxpo.com/v1/ai", apiKey: process.env.TOOLSXPO_API_KEY, });
const res = await client.chat.completions.create({ model: "cloudflare/llama-3.1-8b-instruct-fp8", messages: [{ role: "user", content: "Hello" }], }); ```
The prefix is ours and the suffix is standard, which is how every provider does this — Groq serves `/openai`, Gemini `/v1beta/openai`. It works from the OpenAI SDK in any language, and from anything built on it.
The namespace is not cosmetic: `/v1/{tool}` already serves 230 tools, so a model placed there would shadow one.
Model names
Names are vendor-qualified, so two providers offering the same open model are never ambiguous:
``` cloudflare/llama-3.1-8b-instruct-fp8 cloudflare/gpt-oss-120b ```
`GET /v1/ai/models` returns the catalogue in the shape `client.models.list()` expects, with tier, context window and capability alongside. An unqualified name resolves to the cheapest match, so leaving the vendor off never silently costs more.
Streaming
Set `stream: true` for Server-Sent Events in the standard chunk format, ending with `data: [DONE]`. The SDK's async iterator works unchanged.
A streamed call is billed for what it generated, including when you disconnect part-way — those tokens were produced and paid for. A stream that produced nothing is not billed.
What it costs
| Per call | Tokens | |
|---|---|---|
| Our key | 3 credits | charged at the model's rate |
| Your key | 3 credits | nothing |
The flat 3 credits is the price of routing — auth, logging, the credit write — not of inference. Pricing routing like inference would be indefensible.
Bring your own key and pay less. Add a provider key under Provider keys and it is used automatically, with no code change: you pay the provider directly and we charge only the routing fee. That is worth doing if you already have a provider account or run any real volume.
Our key is worth it when you want no provider account at all, one invoice, or you are already automating with us and this is one more step in a job you have. It is not the cheaper option at volume, and we would rather say so here than have you work it out later.
Several keys for one provider
Add more than one and they rotate, by a rule you choose:
- Least recently used (default) — spreads load evenly
- Round robin — predictable ordering
- Priority — a preferred key, the rest as fallback
A key that returns a rate-limit or auth error is rested, not disabled — 30 seconds first, longer if it keeps failing — and calls continue on the next key, or on ours. Most rate limits clear on their own, so switching a key off at the first failure would create work for you that the provider was about to undo.
This is for capacity and resilience. Using separate accounts to enlarge a provider's free allowance is against most providers' terms and puts those accounts at risk, including everything else you run on them.
Keys are encrypted before storage and are never shown again — not in the API, not in the dashboard, not to us in a form we display. We keep them to make calls, not to give back.
Errors
Errors come back in OpenAI's shape, so the SDK raises a real exception with a real message:
```json { "error": { "message": "…", "type": "invalid_request_error", "param": "model", "code": "model_not_found" } } ```
`type` is one of `invalid_request_error`, `authentication_error`, `permission_error`, `not_found_error`, `rate_limit_error`, `insufficient_quota` or `api_error`. A failed call is never billed.
Scheduling and chaining
The reason to route a model call through us rather than straight to the provider is what surrounds it:
- Schedule it. A prompt on a timer, with delivery by email or webhook — see Scheduled automation.
- Chain it to a tool. Fetch a page, then have a model tell you what changed. The tool step and the model step are billed independently, and a failed fetch never runs the model.
- One bill for tools, browser rendering and models together.
Routing alone is a commodity. These are not.
Request logs
Every call is logged with the model, token counts, credits, latency, whether it streamed, and whether your key or ours served it — under AI → Request logs. That is a different question from the usage page, which totals spend; this one answers what happened on a particular call.
Related
AES Encryption API
Call the AES Encryption API — GET /v1/aes-encryption. Parameters, example requests in cURL, JavaScript and Python, credits per call, and the JSON response.
AI Text Embeddings API
Call the AI Text Embeddings API — GET /v1/text-embeddings. Parameters, example requests in cURL, JavaScript and Python, credits per call, and the JSON response.
AI Text Summarizer API
Call the AI Text Summarizer API — GET /v1/text-summarizer. Parameters, example requests in cURL, JavaScript and Python, credits per call, and the JSON response.
API Mock Payload Builder API
Call the API Mock Payload Builder API — POST /v1/mock-payload-builder. Parameters, example requests in cURL, JavaScript and Python, credits per call, and the JSON response.