ACPpotamia

Advanced guide / Chapter 4 of 7

Per-customer budgets for SaaS and agent platforms.

If your product runs AI agents for your customers, they all share your provider account. One customer's runaway agent, or a malicious prompt, can use up the budget and the rate limit for everyone. Tenants fix that. Each of your customers gets their own budget and rate limit, checked before every call.

Per-customer budgets: one customer reaching their budget does not affect the othersYour productone OpenAI orAnthropic accountCustomer A$25.00 of $25 · stoppedCustomer B$11.20 of $25Customer C$3.10 of $100 (own limit)ACPpotamiachecks each customer'sbudget and rate limitbefore the callProvidercalled only forB and Ceach call sendsX-ControlPlane-Tenant-Id402: only customer A is refused
Customer A has used up their budget and is refused. Customers B and C carry on as normal.

Integrate in six steps

  1. Pick a tenant id. Use your own customer or workspace id, such as customer_4821. Letters, digits and . _ : @ -.
  2. Send it with every call.
    const client = new OpenAI({
      baseURL: "https://acp.examopotamia.com/v1",
      apiKey: process.env.ACP_KEY,
      defaultHeaders: { "X-Upstream-Key": process.env.OPENAI_API_KEY },
    });
    
    // Per request, for the customer you are serving:
    await client.chat.completions.create(
      { model: "gpt-5-mini", messages },
      { headers: { "X-ControlPlane-Tenant-Id": customer.id, "X-ControlPlane-Session-Id": task.id } },
    );
  3. Set a default for every customer on Console → Limits → "Every tenant", for example $25 a month and 60 requests a minute.
  4. Set each customer's own limit from your code when they sign up or change plan:

    Node.js

    await fetch(`https://acp.examopotamia.com/v1/controlplane/tenants/${customer.id}`, {
      method: "PUT",
      headers: { Authorization: `Bearer ${process.env.ACP_ADMIN_KEY}`, "content-type": "application/json" },
      body: JSON.stringify({ monthlyBudgetUsd: plan.aiBudgetUsd, requestsPerMinute: plan.rpm }),
    });

    Python

    import os, requests
    
    requests.put(
        f"https://acp.examopotamia.com/v1/controlplane/tenants/{customer_id}",
        headers={"Authorization": f"Bearer {os.environ['ACP_ADMIN_KEY']}"},
        json={"monthlyBudgetUsd": 200, "requestsPerMinute": 300},
    )
  5. Handle the customer's limit in your product. A call refused for a tenant returns HTTP 402 tenant_budget_exhausted or 429 tenant_rate_limited. Show your own message, or offer that customer an upgrade.
  6. Show customers their usage with GET /v1/controlplane/tenants/{id}: spend this month, money held for calls in progress, requests and tokens.
CallDoes
PUT /v1/controlplane/tenants/{id}Sets monthlyBudgetUsd and requestsPerMinute; null means no limit. Applies to the next call.
GET /v1/controlplane/tenants/{id}Usage this month and the limits that apply (own or default).
GET /v1/controlplane/tenantsAll tenants by spend; ?search=, ?limit=.
DELETE /v1/controlplane/tenants/{id}Removes the customer's own limit; the default applies again.
Tip. To cut off an abusive customer right away, set their budget to 0. Their next call is refused and nobody else notices.
Good to know. The tenant API needs a key with admin access. Keep that key on your servers. It should never ship inside a browser or mobile app.