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

ItemPurpose
REA API keyLets the plane know who you are. Applies your rate limit and monthly loop budget.
Your model keyOpenAI or Anthropic. You pay that vendor. REA does not.
A flexible clientContinue, 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

  1. Choose an OpenAI-compatible provider.
  2. Set the base URL to https://api.reacontrolplane.com/v1.
  3. Set the API key to your REA key.
  4. Add a custom header X-Upstream-Api-Key with 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

  1. Check the REA key. Apply the rate window and loop budget.
  2. If the messages carry code, hash the structure.
  3. Redis hit → return the stored completion. No model call.
  4. Otherwise probe the snippet against the ~150 ms ceiling.
  5. On a trap, the GPT path may attach logit bias for the next generate.
  6. Forward the same messages with your upstream key.
  7. 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

FieldMeaning
modeopenai or anthropic means the vendor was called. block means the sandbox stopped a first-seen trap. cache means Redis answered the same structure.
cache_hittrue when the model was skipped.
structural_hashFingerprint of the extracted code.
sandbox_statusBLOCKED_TIMEOUT, CRASHED, SUCCESS, or NO_CODE.
sandbox_msHow long the probe ran.

Status codes

HTTPMeaning
400Missing X-Upstream-Api-Key. No loop burned.
401Missing or invalid REA key.
402Loop balance is 0.
403Key is inactive.
422Empty or invalid JSON body (no model / messages, or Content-Length: 2 which is {}). LoopGuard does not return 422. Rebuild the body with json.dumps.
429You crossed the tier’s per-minute cap.