API reference

The full request surface: authentication, the two run modes, per-request headers, endpoints, and error shapes.

Introduction

condense.chat sits between your app and your LLM provider. Point your SDK at a provider route, add your condense key, keep your provider key: condense compacts the repeated context in each request before forwarding it upstream, with the same request and response shapes.

Choose the surface for your app:

Base URL: https://api.condense.chat. The dialect is selected by the path prefix; the X-Condense-Function header picks proxy (forward upstream) or rewrite (return the rewritten body). New here? Start with the Quickstart, choose a model on Models, and review Rate limits before production.

Authentication

Two keys travel on every request: your condense key (gates access to condense.chat) and your upstream provider key (charged for the model call). We never store the upstream key, only a sha256 fingerprint in the usage ledger.

The condense API key (ak_…) always travels in the X-Condense-Auth-Token header, for both providers. The upstream key goes in whatever header the provider expects: x-api-key for Anthropic, Authorization: Bearer for OpenAI. Using a custom header for the condense key means Authorization is always available for the upstream, with no precedence conflicts in any SDK.

Anthropic

httpPOST /anthropic/v1/messages
X-Condense-Auth-Token: ak_<your-condense-key>
x-api-key: sk-ant-<your-anthropic-key>
anthropic-version: 2023-06-01
Content-Type: application/json

OpenAI

httpPOST /openai/v1/chat/completions
X-Condense-Auth-Token: ak_<your-condense-key>
Authorization: Bearer sk-<your-openai-key>
Content-Type: application/json

proxy vs. rewrite

The same pipeline runs for both; only the last step differs.

proxy  (default) Forward the rewritten body to the upstream provider and stream the response back to you. You pay for the upstream call.
rewrite Return the rewritten body as JSON. No upstream call, no upstream cost. Useful for debugging which messages got packed, or for piping the result into a different runtime.
bashcurl https://api.condense.chat/anthropic/v1/messages \
  -H "X-Condense-Auth-Token: ak_..." \
  -H "x-api-key: sk-ant-..." \
  -H "anthropic-version: 2023-06-01" \
  -H "X-Condense-Function: rewrite" \
  -d '{"model":"claude-haiku-4-5","max_tokens":256,"messages":[...]}'

rewrite must be enabled on your account. Calls without the entitlement return 403.

In rewrite mode, a model that names a condense compressor (e.g. helene-1) selects it for that request. Any other model keeps its provider meaning and your account's default compressor runs. To compress a transcript without a provider request shape at all, use POST /v1/compress.

Per-request headers

Header Effect
X-Condense-Auth-Token Required. Your condense API key (ak_…). Used for both Anthropic and OpenAI paths.
X-Condense-Function proxy (default) or rewrite. Unknown values fall back to proxy.
X-Condense-Session-Id Optional UUID. Groups requests into a session so the dashboard can show per-session savings. The dense CLI sets this for you.
Authorization / x-api-key Your upstream provider key (Anthropic uses x-api-key, OpenAI uses Authorization: Bearer). Forwarded verbatim; never stored.

condense adds no custom response headers. Upstream response headers come back as-is, minus hop-by-hop headers and content-encoding (bodies are re-encoded in flight).

Worked examples

Six short guides, one per provider × function. Each is self-contained: a paragraph of what the mode does, the smallest possible curl that exercises it, then the same call in Python (no SDK, just urllib) wired into a three-turn tool loop that computes (17 + 25) * 3. Pick a tab; copy the snippet; replace the keys; run.

The two condense-managed functions:

direct tabs are baselines. They don't touch condense at all, included so you can compare and see exactly which headers change.

Provider
Mode

Baseline: talk to OpenAI directly. Sends one OpenAI key in Authorization; no condense involvement. Use this as the control variant when comparing against the proxy tab.

bash# single-turn smoke
curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}'
python# three-turn tool loop; pip-free
import json, os
from urllib.request import Request, urlopen

URL = "https://api.openai.com/v1/chat/completions"
KEY = os.environ["OPENAI_API_KEY"]

TOOLS = [
  {"type":"function","function":{"name":"add","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"mul","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"final_answer","parameters":{"type":"object","properties":{"text":{"type":"string"}}}}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def post(messages):
  body = json.dumps({"model":"gpt-4o-mini","messages":messages,"tools":TOOLS,"tool_choice":"auto"}).encode()
  req = Request(URL, method="POST", data=body, headers={
    "Authorization": f"Bearer {KEY}",
    "Content-Type": "application/json",
  })
  return json.loads(urlopen(req).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  msg = post(messages)["choices"][0]["message"]
  if not msg.get("tool_calls"): print(msg.get("content") or ""); break
  messages.append(msg)
  for tc in msg["tool_calls"]:
    args = json.loads(tc["function"]["arguments"] or "{}")
    result = tool(tc["function"]["name"], args)
    print(f"{tc['function']['name']}({args}) -> {result}")
    messages.append({"role":"tool","tool_call_id":tc["id"],"content":result})
    if tc["function"]["name"] == "final_answer": raise SystemExit

Same shape as direct, but the URL is condense's /openai/v1/chat/completions, the condense key rides in X-Condense-Auth-Token, and your OpenAI key stays in Authorization. Condense compresses, forwards, streams back the upstream response. Your code doesn't change.

bashcurl https://api.condense.chat/openai/v1/chat/completions \
  -H "X-Condense-Auth-Token: $CONDENSE_KEY" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}'
python# identical to the direct example, only URL + headers change
import json, os
from urllib.request import Request, urlopen

URL = "https://api.condense.chat/openai/v1/chat/completions"
OAI = os.environ["OPENAI_API_KEY"]
CON = os.environ["CONDENSE_KEY"]

TOOLS = [
  {"type":"function","function":{"name":"add","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"mul","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"final_answer","parameters":{"type":"object","properties":{"text":{"type":"string"}}}}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def post(messages):
  body = json.dumps({"model":"gpt-4o-mini","messages":messages,"tools":TOOLS,"tool_choice":"auto"}).encode()
  req = Request(URL, method="POST", data=body, headers={
    "X-Condense-Auth-Token": CON,
    "Authorization": f"Bearer {OAI}",
    "Content-Type": "application/json",
  })
  return json.loads(urlopen(req).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  msg = post(messages)["choices"][0]["message"]
  if not msg.get("tool_calls"): print(msg.get("content") or ""); break
  messages.append(msg)
  for tc in msg["tool_calls"]:
    args = json.loads(tc["function"]["arguments"] or "{}")
    result = tool(tc["function"]["name"], args)
    print(f"{tc['function']['name']}({args}) -> {result}")
    messages.append({"role":"tool","tool_call_id":tc["id"],"content":result})
    if tc["function"]["name"] == "final_answer": raise SystemExit

Two-step: condense rewrites your body and hands it back without calling upstream, then you forward it yourself. Header switch is X-Condense-Function: rewrite. No upstream key needed for the first call. Useful when you want to inspect, log, or batch the compressed payload before spending tokens.

bash# step 1: get the compressed body
curl https://api.condense.chat/openai/v1/chat/completions \
  -H "X-Condense-Auth-Token: $CONDENSE_KEY" \
  -H "X-Condense-Function: rewrite" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}' \
  > rewritten.json

# step 2: forward it to OpenAI yourself
curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @rewritten.json
python# tool loop where every turn is rewrite-then-forward
import json, os
from urllib.request import Request, urlopen

REWRITE  = "https://api.condense.chat/openai/v1/chat/completions"
UPSTREAM = "https://api.openai.com/v1/chat/completions"
OAI = os.environ["OPENAI_API_KEY"]
CON = os.environ["CONDENSE_KEY"]

TOOLS = [
  {"type":"function","function":{"name":"add","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"mul","parameters":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}}}}},
  {"type":"function","function":{"name":"final_answer","parameters":{"type":"object","properties":{"text":{"type":"string"}}}}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def turn(messages):
  body = json.dumps({"model":"gpt-4o-mini","messages":messages,"tools":TOOLS,"tool_choice":"auto"}).encode()
  rewritten = urlopen(Request(REWRITE, method="POST", data=body, headers={
    "X-Condense-Auth-Token": CON,
    "X-Condense-Function": "rewrite",
    "Content-Type": "application/json",
  })).read()
  return json.loads(urlopen(Request(UPSTREAM, method="POST", data=rewritten, headers={
    "Authorization": f"Bearer {OAI}",
    "Content-Type": "application/json",
  })).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  msg = turn(messages)["choices"][0]["message"]
  if not msg.get("tool_calls"): print(msg.get("content") or ""); break
  messages.append(msg)
  for tc in msg["tool_calls"]:
    args = json.loads(tc["function"]["arguments"] or "{}")
    result = tool(tc["function"]["name"], args)
    print(f"{tc['function']['name']}({args}) -> {result}")
    messages.append({"role":"tool","tool_call_id":tc["id"],"content":result})
    if tc["function"]["name"] == "final_answer": raise SystemExit

Baseline: talk to Anthropic directly. The Anthropic dialect puts the upstream key in x-api-key (not Authorization) and requires the anthropic-version header. Tools are typed; the model's tool calls come back as tool_use blocks; tool results go back as tool_result blocks.

bashcurl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-haiku-4-5-20251001","max_tokens":256,"messages":[{"role":"user","content":"hi"}]}'
pythonimport json, os
from urllib.request import Request, urlopen

URL = "https://api.anthropic.com/v1/messages"
KEY = os.environ["ANTHROPIC_API_KEY"]

TOOLS = [
  {"name":"add","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"mul","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"final_answer","input_schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def post(messages):
  body = json.dumps({
    "model":"claude-haiku-4-5-20251001","max_tokens":1024,
    "messages":messages,"tools":TOOLS,
  }).encode()
  req = Request(URL, method="POST", data=body, headers={
    "x-api-key": KEY,
    "anthropic-version": "2023-06-01",
    "Content-Type": "application/json",
  })
  return json.loads(urlopen(req).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  resp = post(messages)
  blocks = resp["content"]
  messages.append({"role":"assistant","content":blocks})
  calls = [b for b in blocks if b["type"] == "tool_use"]
  if not calls:
    print("".join(b.get("text", "") for b in blocks)); break
  results = []
  for b in calls:
    result = tool(b["name"], b["input"])
    print(f"{b['name']}({b['input']}) -> {result}")
    results.append({"type":"tool_result","tool_use_id":b["id"],"content":result})
    if b["name"] == "final_answer": raise SystemExit
  messages.append({"role":"user","content":results})

Anthropic-dialect proxy. The condense key rides in X-Condense-Auth-Token (same as the OpenAI path); your Anthropic key stays in x-api-key. Streaming ("stream": true) works identically to the direct path.

bashcurl https://api.condense.chat/anthropic/v1/messages \
  -H "X-Condense-Auth-Token: $CONDENSE_KEY" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-haiku-4-5-20251001","max_tokens":256,"messages":[{"role":"user","content":"hi"}]}'
pythonimport json, os
from urllib.request import Request, urlopen

URL = "https://api.condense.chat/anthropic/v1/messages"
ANT = os.environ["ANTHROPIC_API_KEY"]
CON = os.environ["CONDENSE_KEY"]

TOOLS = [
  {"name":"add","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"mul","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"final_answer","input_schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def post(messages):
  body = json.dumps({"model":"claude-haiku-4-5-20251001","max_tokens":1024,"messages":messages,"tools":TOOLS}).encode()
  req = Request(URL, method="POST", data=body, headers={
    "X-Condense-Auth-Token": CON,
    "x-api-key": ANT,
    "anthropic-version": "2023-06-01",
    "Content-Type": "application/json",
  })
  return json.loads(urlopen(req).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  resp = post(messages); blocks = resp["content"]
  messages.append({"role":"assistant","content":blocks})
  calls = [b for b in blocks if b["type"] == "tool_use"]
  if not calls: print("".join(b.get("text", "") for b in blocks)); break
  results = []
  for b in calls:
    result = tool(b["name"], b["input"])
    print(f"{b['name']}({b['input']}) -> {result}")
    results.append({"type":"tool_result","tool_use_id":b["id"],"content":result})
    if b["name"] == "final_answer": raise SystemExit
  messages.append({"role":"user","content":results})

Anthropic two-step. The compressed body comes back from condense and you forward it to api.anthropic.com yourself. x-api-key and anthropic-version are only needed on the upstream forward; the rewrite step takes the condense key alone.

bash# step 1: get the compressed body
curl https://api.condense.chat/anthropic/v1/messages \
  -H "X-Condense-Auth-Token: $CONDENSE_KEY" \
  -H "X-Condense-Function: rewrite" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-haiku-4-5-20251001","max_tokens":256,"messages":[{"role":"user","content":"hi"}]}' \
  > rewritten.json

# step 2: forward it to Anthropic yourself
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d @rewritten.json
pythonimport json, os
from urllib.request import Request, urlopen

REWRITE  = "https://api.condense.chat/anthropic/v1/messages"
UPSTREAM = "https://api.anthropic.com/v1/messages"
ANT = os.environ["ANTHROPIC_API_KEY"]
CON = os.environ["CONDENSE_KEY"]

TOOLS = [
  {"name":"add","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"mul","input_schema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}},
  {"name":"final_answer","input_schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}},
]

def tool(name, args):
  if name == "add": return str(args["a"] + args["b"])
  if name == "mul": return str(args["a"] * args["b"])
  return args["text"]

def turn(messages):
  body = json.dumps({"model":"claude-haiku-4-5-20251001","max_tokens":1024,"messages":messages,"tools":TOOLS}).encode()
  rewritten = urlopen(Request(REWRITE, method="POST", data=body, headers={
    "X-Condense-Auth-Token": CON,
    "X-Condense-Function": "rewrite",
    "Content-Type": "application/json",
  })).read()
  return json.loads(urlopen(Request(UPSTREAM, method="POST", data=rewritten, headers={
    "x-api-key": ANT,
    "anthropic-version": "2023-06-01",
    "Content-Type": "application/json",
  })).read())

messages = [{"role":"user","content":"Compute (17 + 25) * 3 using add and mul, then call final_answer."}]
for _ in range(6):
  resp = turn(messages); blocks = resp["content"]
  messages.append({"role":"assistant","content":blocks})
  calls = [b for b in blocks if b["type"] == "tool_use"]
  if not calls: print("".join(b.get("text", "") for b in blocks)); break
  results = []
  for b in calls:
    result = tool(b["name"], b["input"])
    print(f"{b['name']}({b['input']}) -> {result}")
    results.append({"type":"tool_result","tool_use_id":b["id"],"content":result})
    if b["name"] == "final_answer": raise SystemExit
  messages.append({"role":"user","content":results})

claude-agent-sdk-python is the official Anthropic SDK for spawning long-running tool-using agents. It shells out to claude under the hood, so all you need to do is point its ANTHROPIC_BASE_URL at condense's /anthropic prefix and pass your condense key via the SDK's env option. direct and rewrite modes aren't relevant here: the agent loop needs upstream completions.

bash# install once
pip install claude-agent-sdk
npm install -g @anthropic-ai/claude-code  # the SDK shells out to this
pythonimport anyio, os
from claude_agent_sdk import query, ClaudeAgentOptions

opts = ClaudeAgentOptions(env={
  "ANTHROPIC_BASE_URL": "https://api.condense.chat/anthropic",
  "ANTHROPIC_CUSTOM_HEADERS": f"X-Condense-Auth-Token: {os.environ['CONDENSE_KEY']}",
  "ANTHROPIC_API_KEY": os.environ["ANT_API_TOKEN"],
})

async def main():
  async for msg in query(prompt="Compute (17 + 25) * 3 step by step.", options=opts):
    print(msg)

anyio.run(main)

Every tool turn passes through condense, which compresses older context before forwarding upstream. To set additional per-request headers for one session (e.g. X-Condense-Session-Id), append them to ANTHROPIC_CUSTOM_HEADERS.

Endpoints

POST /v1/compress direct compression · no upstream call

Compress a transcript and get it back in the same shape: N messages in, N messages out, each compressed independently with its role and order preserved. No conversation tracking, no upstream model call. Requires the rewrite capability on your account; returns 403 otherwise.

Request body

model string Required
The compressor to run, by public name, e.g. helene-1 or adeline-1. An unknown or undeployed name returns 400 with the list of currently selectable compressors.
messages array Required
The transcript, in OpenAI chat shape ({"role", "content"}). A message the compressor abstains on (empty, too short, or quality-gated) comes back with its original content unchanged.
compression_rate number
Optional, helene-1 only. Fraction of tokens to remove, between 0 and 1. Omit to let the model pick the rate. Out-of-range values return 400.
POST /v1/compress
import httpx

resp = httpx.post(
    "https://api.condense.chat/v1/compress",
    headers={"X-Condense-Auth-Token": "ak_..."},
    json={
        "model": "helene-1",
        "compression_rate": 0.6,
        "messages": [
            {"role": "system", "content": "You are a terse assistant."},
            {"role": "user", "content": "<a long transcript to compress>"},
        ],
    },
)
print(resp.json())
Response
json{
  "model": "helene-1",
  "messages": [
    {"role": "system", "content": "terse assistant."},
    {"role": "user", "content": "<surviving text, verbatim>"}
  ]
}
POST /anthropic/v1/messages Anthropic dialect · chain-tracking proxy

Identical request and response shape to api.anthropic.com/v1/messages. Streaming (stream: true) is preserved end-to-end; all anthropic-* headers (prompt caching, betas) forward through unchanged.

POST /anthropic/v1/messages
import httpx

resp = httpx.post(
    "https://api.condense.chat/anthropic/v1/messages",
    headers={"X-Condense-Auth-Token": "ak_...", "x-api-key": "sk-ant-...", "anthropic-version": "2023-06-01"},
    json={"model": "claude-haiku-4-5", "max_tokens": 256, "messages": [{"role": "user", "content": "hi"}]},
)
print(resp.json())
Response is Anthropic's, verbatim.
POST /openai/v1/chat/completions OpenAI dialect · chain-tracking proxy

Identical request and response shape to api.openai.com/v1/chat/completions. Streaming is preserved; tool calls round-trip.

POST /openai/v1/chat/completions
import httpx

resp = httpx.post(
    "https://api.condense.chat/openai/v1/chat/completions",
    headers={"X-Condense-Auth-Token": "ak_...", "Authorization": "Bearer sk-..."},
    json={"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "hi"}]},
)
print(resp.json())
Response is OpenAI's, verbatim.
POST /openai/v1/responses OpenAI Responses dialect · Codex

Drop-in for the OpenAI Responses API (used by Codex). Same request and response shape as api.openai.com/v1/responses.

POST /openai/v1/responses
import httpx

resp = httpx.post(
    "https://api.condense.chat/openai/v1/responses",
    headers={"X-Condense-Auth-Token": "ak_...", "Authorization": "Bearer sk-..."},
    json={"model": "gpt-4o-mini", "input": "hi"},
)
print(resp.json())
Response is OpenAI's, verbatim.
GET /{provider}/… pass-through · forwarded verbatim

Any other path under a provider prefix (a models list, embeddings, and so on) is forwarded to the upstream unchanged. The compression pipeline does not touch it; this is purely an SDK-compat convenience so one base URL covers the whole provider surface.

GET /{provider}/…
import httpx

resp = httpx.get(
    "https://api.condense.chat/openai/v1/models",
    headers={"X-Condense-Auth-Token": "ak_...", "Authorization": "Bearer sk-..."},
)
print(resp.json())
Response is the provider's, verbatim.

Debugging requests

Failures come back as standard HTTP status codes with the dialect's normal error body; the full breakdown is in Errors below. Two things help when something goes wrong:

Compression never breaks a call on its own: if the condense pipeline hits an internal error mid-request, the proxy forwards your original body upstream unchanged and the request completes without compression.

Backwards compatibility

condense avoids breaking changes. The request and response shapes are the provider's own (Anthropic / OpenAI), so upgrading condense never changes the wire format your SDK expects. Model ids are stable aliases: helene-1 and adeline-1 keep pointing at the current best engine while internal versions move underneath.

Changes we make freely, without notice:

Retirements are announced ahead of time on Deprecations, and notable changes land in the Changelog.

Errors

Errors follow standard HTTP status codes. Bodies are the dialect's native error JSON for upstream-origin failures (so SDK error parsers keep working); condense-origin failures use a small {"error": {"type": "...", "message": "..."}} shape.

Status Meaning
400 Bad request body, a malformed Authorization header, or an unknown model / out-of-range compression_rate on /v1/compress.
401 Missing or invalid condense key.
403 Your key is valid but the account isn't entitled to what the request asked for: rewrite, the proxy itself, or an upstream URL override.
429 Rate-limited. The Retry-After response header says how many seconds to wait.
5xx Upstream provider error. The upstream status and body are forwarded verbatim.

Compression itself never breaks a conversation: if the condense pipeline hits an internal error mid-request, the proxy forwards your original body upstream unchanged and the call completes without compression.