ACPpotamia

Advanced guide / Chapter 1 of 7

How a call flows through ACPpotamia.

ACPpotamia sits between your agent and the model provider. You keep your OpenAI or Anthropic SDK and change one thing, the base URL. From then on each call makes two stops before it reaches the provider. The first is the Cloudflare location nearest your agent. The second is your team's control object: one small server that holds all of your team's limits and makes each allow-or-block decision in a single step, so two agents can't both squeeze through the last dollar.

The life of a call through ACPpotamiaYour agentOpenAI or AnthropicSDK, unchangedEdge checkACPpotamia keynearest CloudflareTeam control object1 Revoked key, suspended team2 Model policy3 Kill switch4 Rate limits: team, key, tenant, session5 Loop detection6 Budget hold: team, key, tenant, sessionAll decided in one atomic stepProviderOpenAI, Anthropicor your own serverSettlereal cost replaces the holdAudit logD1 records,R2 daily archivecallallowedanswer streams back to your agent, tokens counted liveblocked: 401 · 402 · 403 · 429, never sent
The life of a call. The control object decides, the provider answers, and tokens are counted as the answer streams back. When it ends, the real cost is settled and the call goes into the audit log.

Step by step

  1. The nearest Cloudflare location checks your ACPpotamia key. An unknown or revoked key gets HTTP 401 and the call stops there.
  2. Your team's control object runs its checks in a fixed order (shown below). If one fails, the call is refused with a specific code and the provider never sees it.
  3. If everything passes, the control object holds the call's estimated cost against every budget it counts toward: team, API key, tenant and session.
  4. ACPpotamia forwards the call with your own provider key. We pass that key through and never store it.
  5. The answer streams back to your agent byte for byte while ACPpotamia counts tokens. If a budget runs dry mid-stream, the stream ends with an error event in the provider's own format, so your SDK reports it normally.
  6. When the call ends, the provider's real usage replaces the estimate and any difference goes back into the budget.
  7. A few seconds later the call shows up in the audit log, whether it was allowed or blocked.

The checks, in order

The checks every call passes, in order, and the error each one returnsKey valid?no401 invalid_api_key, key_revokedTeam active?no403 team_suspendedModel allowed?no403 model_not_allowedTeam or session stopped?no429 team_killed, session_killedWithin rate limits?no429 rate_limited, key/tenant/session_rate_limitedNot looping?no429 loop_detected (session stops)Budget can pay?no402 budget_exhausted, key/tenant/session_budget_exhaustedSent to the providerevery outcome, allowed or blocked, is written to the audit log
What can stop a call, in the order it is checked, and the HTTP status and code each check returns.

The headers you send

HeaderPurpose
Authorization: Bearer acp_… or X-ACP-KeyYour ACPpotamia key.
X-Upstream-Key (or x-api-key for Anthropic)Your provider key. Passed through, never stored. Not needed for test keys.
X-ControlPlane-Agent-IdWhich agent is calling. Groups activity and spend.
X-ControlPlane-Session-IdOne task. Scope for loop detection, session limits and stopping one task.
X-ControlPlane-Tenant-IdYour end-customer, for per-customer budgets (Pro, Enterprise).
X-ControlPlane-FailModeopen or closed: what happens if limits cannot be checked. See chapter 7.

The headers you get back

HeaderMeaning
X-ControlPlane-Decisionallow, block, fail-open or fail-closed
X-ControlPlane-Block-ReasonThe exact reason when blocked, such as tenant_budget_exhausted.
X-ControlPlane-Budget-Remaining-USDTeam budget left after this call's hold.
X-ControlPlane-Overhead-MsTime ACPpotamia added before the provider was called.
X-ControlPlane-Request-IdThe call's id in the audit log. Quote it to support.

What is stored, and what is not

Tip. Watch X-ControlPlane-Overhead-Ms in your logs. It's usually under 100 ms. The first call after a quiet spell can be slower, because your team's control object has to wake up.