Set up
Point the agent at the plane.
Base URL https://api.reacontrolplane.com/v1. Two keys. Trial keys are issued by email until self-serve checkout is open.
What you need
| Item | Purpose |
|---|---|
| REA API key | Lets the plane know who you are. Applies your rate limit and monthly loop budget. |
| Your model key | OpenAI or Anthropic. You pay that vendor. REA does not. |
| A flexible client | Continue, Cline, the OpenAI SDK, or curl — anything that accepts a custom base URL and one extra header. |
The two headers
Authorization: Bearer YOUR_REA_API_KEY X-Upstream-Api-Key: YOUR_MODEL_KEY Content-Type: application/json
For Claude, add X-REA-Upstream: anthropic, or use a claude-* model name. The Anthropic key still goes in X-Upstream-Api-Key.
A first call
curl -s https://api.reacontrolplane.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_REA_API_KEY" \
-H "X-Upstream-Api-Key: YOUR_MODEL_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role":"user","content":"Reply with exactly: REA LIVE"}]
}'
Python
from openai import OpenAI
client = OpenAI(
api_key="YOUR_REA_API_KEY",
base_url="https://api.reacontrolplane.com/v1",
default_headers={"X-Upstream-Api-Key": "YOUR_MODEL_KEY"},
)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Reply with exactly: REA LIVE"}],
)
print(resp.choices[0].message.content)
Health
curl -s https://api.reacontrolplane.com/health
You want "status": "INTEGRATED", "byok": true, version 1.4.8-prod.
/v1 in a browser is not a page. The live route is POST /v1/chat/completions. Opening the base URL will say Not Found. That is expected.Continue or Cline
- Choose an OpenAI-compatible provider.
- Set the base URL to
https://api.reacontrolplane.com/v1. - Set the API key to your REA key.
- Add a custom header
X-Upstream-Api-Keywith your model key.
Those values live in the tool config. There is no website login. A 402 means the monthly loop pool is empty — the agent is not logged out.
What each request does
- Check the REA key. Apply the rate window and loop budget.
- If the messages carry code, hash the structure.
- Redis hit → return the stored completion. No model call.
- Otherwise probe the snippet against the ~150 ms ceiling.
- On a trap, the GPT path may attach logit bias for the next generate.
- Forward the same messages with your upstream key.
- Return the vendor text plus
rea_meta.
LoopGuard fixtures
Fences are optional. json.dumps is required. Continue and Cline often send a fenced block. Hermes and raw SDKs often send raw text. Prose that only mentions while True is NO_CODE, not a trap and not a 422.
Raw (benches / SDK):
{
"model": "gpt-4o-mini",
"messages": [{
"role": "user",
"content": "import time\nwhile True: pass"
}]
}
Fenced (Continue):
{
"model": "gpt-4o-mini",
"messages": [{
"role": "user",
"content": "```python\nwhile True:\n pass\n```"
}]
}
First call: HTTP 200, mode=block, BLOCKED_TIMEOUT, about 150–160 ms. Repeat: HTTP 200, mode=cache, cache_hit=true, same structural_hash.
The small receipt: rea_meta
| Field | Meaning |
|---|---|
mode | openai or anthropic means the vendor was called. block means the sandbox stopped a first-seen trap. cache means Redis answered the same structure. |
cache_hit | true when the model was skipped. |
structural_hash | Fingerprint of the extracted code. |
sandbox_status | BLOCKED_TIMEOUT, CRASHED, SUCCESS, or NO_CODE. |
sandbox_ms | How long the probe ran. |
Status codes
| HTTP | Meaning |
|---|---|
| 400 | Missing X-Upstream-Api-Key. No loop burned. |
| 401 | Missing or invalid REA key. |
| 402 | Loop balance is 0. |
| 403 | Key is inactive. |
| 422 | Empty or invalid JSON body (no model / messages, or Content-Length: 2 which is {}). LoopGuard does not return 422. Rebuild the body with json.dumps. |
| 429 | You crossed the tier’s per-minute cap. |