API docs · Conversation context

Conversation context

Chat completions are stateless by default, so a multi-turn conversation normally means resending the entire history on every call. Send context_id and we keep the thread for you, so each call carries only the new message.

Quickstart

Two calls. The first opens a thread, the second continues it.

1. Start a thread
curl https://dreamprompting.com/api/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "context_id": "new",
    "messages": [{"role": "user", "content": "My project is called Kuza."}]
  }'
Response (trimmed)
{
  "object": "chat.completion",
  "model": "openai/gpt-oss-120b",
  "provider": "groq",
  "context_id": "ctx-Ngz5JE-UdyE_YB6WfVz7hQ",
  "choices": [{"index": 0, "message": {"role": "assistant", "content": "Noted."}}],
  "usage": {"total_tokens": 27}
}
2. Continue it, sending only the new message
curl https://dreamprompting.com/api/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "context_id": "ctx-Ngz5JE-UdyE_YB6WfVz7hQ",
    "messages": [{"role": "user", "content": "What is my project called?"}]
  }'

# -> "Kuza"   the earlier turns were replayed for you

What happens on each call

  1. You send context_id plus the new message or messages.
  2. We load the earlier turns of that thread, oldest first, and put them in front of your messages.
  3. The combined conversation is trimmed to fit the token budget.
  4. The result is sent to a provider, with the usual automatic failover.
  5. Your message and the reply are stored against the thread, so the next call can replay them.

Only successful turns are stored for replay. If a call fails, it leaves nothing behind, so retrying does not make it look like you asked twice.

Reference

Value of context_idEffect
"new"Starts a thread. A fresh id comes back on the response.
trueSame as "new", for clients that prefer a boolean.
"ctx-..."Continues that thread. Earlier turns are replayed.
omittedStateless, exactly as before. Nothing is stored as a thread.
anything else400, so a typo fails loudly instead of silently losing the conversation.
Where the id appearsHow to read it
Response bodycontext_id
Response headerX-Context-Id

Ids look like ctx- followed by a random string. Treat one as a secret: it names a conversation. Store it wherever you keep the rest of your session state.

Inspect a thread

GET /api/v1/contexts/{context_id}

Shows exactly what we would replay, and how big it is. Useful when a thread stops behaving the way you expect.

curl https://dreamprompting.com/api/v1/contexts/ctx-Ngz5JE-UdyE_YB6WfVz7hQ \
  -H "Authorization: Bearer YOUR_API_KEY"

{
  "context_id": "ctx-Ngz5JE-UdyE_YB6WfVz7hQ",
  "messages": [
    {"role": "user", "content": "My project is called Kuza."},
    {"role": "assistant", "content": "Noted."}
  ],
  "turns": 2,
  "estimated_tokens": 12,
  "token_budget": 12000,
  "trimmed_turns": 0
}

trimmed_turns counts older turns the budget is currently leaving out. An unknown id returns an empty thread rather than an error, because a thread only exists once its first turn has been answered.

Streaming

Context works with "stream": true. The body carries standard OpenAI chunks with no room for extra fields, so read the id from the X-Context-Id response header.

Python
import requests

r = requests.post(
    "https://dreamprompting.com/api/v1/chat/completions",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"model": "auto", "context_id": "new", "stream": True,
          "messages": [{"role": "user", "content": "Hello"}]},
    stream=True,
)
context_id = r.headers["X-Context-Id"]   # keep this for the next turn

for line in r.iter_lines():
    if line:
        print(line.decode())

Trimming, and why threads do not grow forever

A conversation that keeps growing eventually exceeds what any provider will accept, at which point every call fails. To avoid that, a replayed thread is trimmed to about 12,000 tokens:

  • System messages always survive. They carry the instructions that define behaviour, so losing them changes the assistant mid-conversation.
  • Newest turns win. Older turns are dropped first, because recent context usually matters more.
  • Nothing is deleted. Trimming decides what gets replayed; the full thread stays in your usage history.

If your thread needs to remember something permanently, put it in a system message rather than relying on an early user turn, since a system message is never trimmed away.

This does not reduce your token usage

Worth being clear about, because it surprises people. Language models are stateless: they have no memory between calls. "Remembering" a conversation always means sending the history again. When you use context_id, we are the ones resending it, so the provider still receives the full thread and it still counts against your token budget.

What it does save:

  • You stop maintaining conversation state, so the client gets simpler.
  • You stop uploading the same history repeatedly, which matters on slow or metered connections.
  • Trimming keeps the thread inside provider limits, so a long conversation does not start failing.

If your goal is lower token spend, the levers are a shorter budget, a compact system message, and starting a fresh thread when the subject changes. Long conversations are expensive by nature: input tokens accumulate every turn, and in practice they tend to dwarf the replies.

Privacy and scoping

  • A thread belongs to the account that created it. Another account cannot read it, even with the id.
  • Any active key on your own account can use your threads, so rotating a key does not lose them.
  • Threads are stored on our side, in the same request log that powers your usage page. Do not put secrets in a conversation you would not want stored.
  • Ids are unguessable, but treat one as a credential for that conversation and keep it server side.

When to use it, and when not to

Good fit

  • Chat interfaces and assistants that hold a conversation
  • Roleplay or tutoring sessions that must stay in character
  • Multi-step work where later steps depend on earlier answers
  • Clients where storing history yourself is awkward, like a shell script or an automation node

Skip it

  • One-off calls such as classification, extraction or translation, where history only adds cost
  • Cases where you already keep the transcript and want exact control over what is sent
  • Fan-out work in parallel: give each line of work its own thread, or none
  • Anything needing an audit trail of the precise payload, since we prepend on your behalf

One thread is one conversation. If your app serves several people, create a thread per person and store the id next to that person's session. Do not share one thread across users, or their conversations will run together.

Errors

StatusMeaningFix
400Malformed context_idUse "new" or an id from a previous response.
401Missing or invalid keySend Authorization: Bearer. Get a key.
413This turn alone is too largeShorten the message. Trimming applies to replayed history, not to what you send.
429Rate limit or daily budgetBack off, or ask us to raise the limit.
502Every provider declinedIf the message mentions size, shorten the thread or lower the budget.