API documentation
A free, OpenAI-compatible LLM API. Create a free account, grab an API key, change one line (base_url) and your existing OpenAI code works.
Base URL & authentication
Base URL:
https://dreamprompting.com/api/v1
Every request needs an API key, sent as a Bearer token (the standard OpenAI way):
Authorization: Bearer YOUR_API_KEY
Keys are free. Sign in and create one in a few seconds — no credit card. Your account has a generous daily quota, shared across all of its keys; usage is shown on your account page.
Chat completions
POST /api/v1/chat/completions — OpenAI-compatible.
Request body
| Field | Type | Notes |
|---|---|---|
| messages | array | Required. [{role, content}] with roles system/user/assistant. |
| model | string | Optional. "auto" (default, failover) or "provider/model". See model selection. |
| stream | boolean | Optional. true for Server-Sent Events. See streaming. |
| temperature | number | Optional. Passed through to the provider. |
| max_tokens | integer | Optional. Passed through. |
| context_id | string | "new" to start a server-side thread, or an id from a previous response to continue one. See conversation context. |
| reasoning_effort | string | none|low|medium|high. Controls Gemini thinking. See below. |
| thinking | boolean | Convenience flag to enable Gemini thinking. See below. |
Examples
curl https://dreamprompting.com/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"messages": [{"role":"user","content":"Hello!"}]
}'
from openai import OpenAI
client = OpenAI(
base_url="https://dreamprompting.com/api/v1",
api_key="YOUR_API_KEY",
)
r = client.chat.completions.create(
model="auto",
messages=[{"role":"user","content":"Hi"}],
)
print(r.choices[0].message.content)
const r = await fetch(
"https://dreamprompting.com/api/v1/chat/completions",
{ method:"POST",
headers:{"Content-Type":"application/json",
"Authorization":"Bearer YOUR_API_KEY"},
body: JSON.stringify({
model:"auto",
messages:[{role:"user",content:"Hi"}]
})});
const d = await r.json();
console.log(d.choices[0].message.content);
{
"object": "chat.completion",
"model": "openai/gpt-oss-120b",
"provider": "groq",
"choices": [{
"index": 0,
"message": {"role":"assistant","content":"Hi!"},
"finish_reason": "stop"
}],
"usage": {"total_tokens": 12}
}
The response includes a non-standard provider field and an X-Served-By header telling you which upstream answered.
Conversation context
By default every call is independent, so a multi-turn chat means resending the whole history each time.
Send "context_id": "new" and we keep the thread for you. The response
returns a context_id; pass it on later calls and we prepend the earlier
turns, so you only send the new message.
1. Start a thread
{
"model": "auto",
"context_id": "new",
"messages": [
{"role": "user", "content": "My name is Elena."}
]
}
// response includes:
// "context_id": "ctx-A1b2C3..."
2. Continue it
{
"model": "auto",
"context_id": "ctx-A1b2C3...",
"messages": [
{"role": "user", "content": "What is my name?"}
]
}
// the model already knows
- The id is also returned as an
X-Context-Idheader, which is how you read it when streaming. - A thread is tied to the account that created it. Another account cannot read it, even with the id.
- Long threads are trimmed to about 12,000 tokens. Your system message is always kept, and the newest turns win over the oldest.
- This does not reduce token usage. Models are stateless, so the history still goes upstream on every turn and still counts toward your token budget. What it saves is the bookkeeping on your side, and it stops a thread growing until no provider will accept it.
- Omit
context_idfor one-off calls. Nothing is stored as a thread and behaviour is unchanged. - Inspect a thread with
GET /api/v1/contexts/{context_id}.
Model selection & failover
"auto"(default): the gateway picks a live provider and automatically fails over to the next if one errors or is rate-limited."provider/model": pin a specific model, e.g."groq/openai/gpt-oss-120b"or"google/gemini-3.1-flash-lite". If it fails, the gateway still falls back to other providers.- List everything live at /api/v1/models, or browse and test them on the models page.
Streaming (SSE)
Pass "stream": true to receive Server-Sent Events with OpenAI-compatible chat.completion.chunk deltas, terminated by data: [DONE]. The OpenAI SDK's stream=True works unchanged.
curl -N https://dreamprompting.com/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"auto","messages":[{"role":"user","content":"Hi"}],"stream":true}'
Gemini "thinking" control
Google's Gemini models can spend extra tokens "thinking" before answering. This is powerful for hard
problems but slower and heavier for everyday calls. On DreamPrompting, Gemini defaults to the
lightweight gemini-3.1-flash-lite model with thinking turned OFF,
so you get fast, cheap, predictable answers by default.
To enable thinking, opt in per request in either of two ways:
1. Standard reasoning_effort
{
"model": "google/gemini-2.5-flash",
"messages": [...],
"reasoning_effort": "medium"
}
2. Convenience flag
{
"model": "google/gemini-2.5-flash",
"messages": [...],
"thinking": true
}
Values for reasoning_effort: none (off, default), low, medium, high. This applies only to Gemini; other providers ignore it.
Other endpoints
- GET
/api/v1/models— list live models. - GET
/api/v1/quota— your remaining rate-limit quota. - BODY
allow_fallback: false— pin the request to themodelyou named. If it is unavailable you get503 model_unavailableinstead of a different model answering in its place. Needs an explicitmodel; it means nothing withauto. Useful for a bot that tells its users which model it is. - BODY
identify: false— drop the one-line note we add to the system prompt telling the model which model and provider it actually is. It is there because a model's weights do not record which endpoint is serving them, so without it a Llama answering through Groq will often claim to be ChatGPT. Skipped automatically when you ask for JSON output. - POST
/api/v1/classify— one question, a fixed set of answers. Body:{input, choices}, plus optionalmodel. Returns the chosen label and its index. In practiceconfidencecomes backnulltoday: a probability needs token logprobs, only NVIDIA of our providers reports them, and the models it will actually serve this account are reasoning models whose first token is a thought rather than an answer. The field is there and fills in the moment a provider supports it, andmethodtells you which way the answer was read. It writes the "reply with one letter" prompt for you, which is where almost all of the speed comes from: measured over 60 questions, an unconstrained prompt took 1,401ms against 142ms for a constrained one. The probability is reported raw andcalibratedis alwaysfalse: on a small model it was 0.896 when right and 0.839 when wrong, so do not threshold on it without checking it against your own labels. See the measurements. - POST
/api/v1/unwatermark— strip watermarks and invisible Unicode from source code and report every removal by codepoint and line. Body:{code}, plus optionaltrailing,punctuation,homoglyphsandinspect. Costs no tokens. See the invisible character remover. - POST
/api/v1/tokenize— count tokens before you spend them. No API key needed. Body:{text}or{messages}, plus optionalencodingandsplit. See the token calculator. - POST
/api/chat— stateful chat with server-side history (used by the chat page). Body:{seed, message, model?, thinking?}. - GET
/api/chat/history?seed=...— retrieve a chat thread.
Rate limits & budgets
Tokens are the real budget, since that is what the upstream free tiers meter. Requests are a secondary backstop.
| Limit | Value | Scope |
|---|---|---|
| Burst | 100 / minute | per IP |
| Tokens | 500,000 / 24h | per account, rolling |
| Requests | 5,000 / 24h | per account, rolling |
| Response length | 8,192 tokens | per request, max_tokens capped to this |
| Input size | 32,000 tokens | per request, larger returns 413 |
Every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Check your remaining budgets any time at GET /api/v1/quota, which reports both requests and tokens, or on your account page. Both 24 hour budgets free up on a rolling window rather than resetting at midnight. Need a higher limit? Just ask and we will raise it, or lift it entirely by adding your own provider key: requests served on a key you supply are routed through your account with that provider and are not counted against this quota.
Errors
Errors use the OpenAI shape and appropriate HTTP status codes:
{"error": {"message": "Rate limit reached (100 requests/minute)...", "type": "rate_limit_error"}}
Common: 400 invalid request, 401 missing/invalid API key, 429 rate limited or daily quota reached, 502 all providers failed, 503 no providers configured.
Getting a 403 with error code: 1010?
That block comes from our CDN, not the API — it rejects generic default User-Agents (e.g. Python's urllib). The fix is one header: send any descriptive User-Agent that identifies your app, e.g. User-Agent: my-app/1.0. The OpenAI SDKs, curl and Python requests already send one and are unaffected.
Building an agent or MCP tool?