Manage an ibl.ai organization's LLM spend caps via the platform API — admin-imposed maximum LLM cost at three scopes (organization-wide, one agent, or one user on one agent), each with a rolling interval (day/week/month/year), a hard-block or alert-only enforcement mode, and near-limit alert thresholds. Read the current fill/zone for a user's applicable caps (safe to show end users, dollars hidden). Use when setting a budget ceiling on an org/agent/user, listing configured caps, checking how ...
Installs into .claude/skills of the current project.
Are you the author of Iblai Api Spend Caps?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/iblai-iblai-api-spend-caps)
---
name: iblai-api-spend-caps
description: Manage an ibl.ai organization's LLM spend caps via the platform API — admin-imposed maximum LLM cost at three scopes (organization-wide, one agent, or one user on one agent), each with a rolling interval (day/week/month/year), a hard-block or alert-only enforcement mode, and near-limit alert thresholds. Read the current fill/zone for a user's applicable caps (safe to show end users, dollars hidden). Use when setting a budget ceiling on an org/agent/user, listing configured caps, checking how close a user is to their limit, or removing a cap. Spend counters are reconciled from ClickHouse and are read-only.
metadata:
kind: api
---
# iblai-api-spend-caps
Configure and read **LLM spend caps** for an organization. A spend cap is an
admin-imposed maximum LLM cost enforced at one of three scopes:
- `tenant` — the whole org (one cap per organization).
- **agent** — one agent (one cap per agent).
- **user_agent** — one user on one agent (an explicit per-user cap).
Each cap has a rolling **interval** (`day`/`week`/`month`/`year`, calendar
aligned), a dollar limit (`max_cost_usd`), an **enforcement** mode
(`block` refuses further chats once exceeded; `alert_only` only notifies), and
**alert thresholds** (fractions of the limit that fire a near-limit alert). When
a chat is blocked, the request is refused with **HTTP 429** and a body naming the
interval that was hit (dollar amounts are deliberately omitted). Spend counters
are reconciled from ClickHouse on a schedule and surfaced **read-only** so a UI
can render a progress bar.
## Auth & conventions
- **Base URL:** `https://api.iblai.app/dm` — these are Data Manager (DM)
endpoints, so the **`/dm` prefix is required**; the `/api/ai-mentor/...` paths
below are appended to it (e.g.
`https://api.iblai.app/dm/api/ai-mentor/orgs/$IBLAI_ORG/spend-caps/tenant/`).
Omitting `/dm` will not resolve.
- **Header:** `Authorization: Api-Token $IBLAI_API_KEY` on every request.
- **Path vars:** `{org}` = `$IBLAI_ORG` (the org key). `{mentor}` = an agent's
`unique_id` (a UUID). `{user_id}` / `{username}` = the target user.
- **Endpoint prefix twin:** every path under `api/ai-mentor/` also resolves
under `api/ai-agent/` (alias); either works, pick one and be consistent.
- **Permission tiers:** all cap **configuration** endpoints (organization / agent /
user-agent read+write) require a **platform admin** (RBAC action prefix
`Ibl.Mentor/SpendCaps/*`). The **status** endpoint is safe to show end users: any
authenticated member may read **their own** status, and admins may read any
user's — it returns only a coarse zone + percent, never raw dollars.
- **PUT is upsert:** writing a cap that doesn't exist yet returns **201
Created**; writing over an existing one returns **200 OK**.
- DELETE and PUT (destructive / budget-changing) calls say "Confirm with the
user first."
- Not connected yet? Run **`/iblai-api-login`** first to populate `IBLAI_ORG`,
`IBLAI_USERNAME`, and `IBLAI_API_KEY`.
## Concepts
- **scope** — `tenant` | `agent` | `user_agent`. Set by the endpoint you call,
never sent in the body. Narrower scopes carry `mentor_unique_id` (agent,
user_agent) and `username` (user_agent).
- **interval_type** — `day` | `week` | `month` | `year`. The rolling window is
calendar aligned (day = midnight, week = Monday, month = 1st, year = Jan 1).
- **enforcement** — `block` (default): once `current_spend_usd >= max_cost_usd`
the next chat is refused with 429. `alert_only`: never blocks; only drives
near-limit alerts.
- **alert_thresholds** — a list of fractions in `(0, 1]` (default `[0.8, 0.95]`
= 80% and 95%). Each fires an admin alert once per period.
- **Read-only counters** — `current_spend_usd`, `remaining_usd`, `is_exceeded`,
`period_started_at`, `last_reconciled_at` are reconciled from ClickHouse and
ignored if sent in a write body.
- **Applicability** — for a given chat, the organization cap always applies; the agent
cap applies when an agent is in play; the user's own per-agent cap applies when
both agent and user are known. When several hard-block caps are exceeded, the
**most specific** one (user > agent > organization) is reported.
## Reads
### Organization cap
- **GET** `/api/ai-mentor/orgs/{org}/spend-caps/tenant/` — the org-wide cap, or
`404` if none is set. Returns the full cap object (see Schema).
### Agent caps
- **GET** `/api/ai-mentor/orgs/{org}/spend-caps/agents/[?mentor={mentor}]` — list
agent-scoped caps for the org; pass `mentor` to filter to one agent. Returns a
list of cap objects.
- **GET** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-cap/` — the single
cap for one agent, or `404` if none. The agent is resolved org-scoped, so
an agent from another org returns `404`.
### User-per-agent caps
- **GET** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-caps/users/[?username=&email=]`
— list explicit per-user caps on one agent; optional `username` / `email`
filters.
- **GET** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-caps/users/{username}/`
— the one cap for a specific user on that agent, or `404`.
### User spend status (safe to show end users)
- **GET** `/api/ai-mentor/orgs/{org}/spend-caps/status/{user_id}/[?mentor={mentor}]`
— the coarse status across every cap that applies to `{user_id}` (organization cap
always; agent + that user's own per-agent cap when `mentor` is given). Any
member may read their own; admins may read anyone's. Returns **only** a zone
and percentage — never raw spend/limit dollars — so it is safe to surface to
end users. Returns `400` if `mentor` is not a valid UUID.
```json
{
"status": "warning",
"blocked": false,
"caps": [
{
"scope": "tenant",
"interval_type": "month",
"enforcement": "block",
"status": "warning",
"percent_used": 82.5,
"warning_threshold": 0.8,
"mentor_unique_id": null,
"username": null
}
]
}
```
`status` is the worst zone across the applicable caps (`ok` → `warning` →
`exceeded`); `blocked` is `true` when a hard-block cap is already exceeded (the
next chat would be refused). This shape names `username` only to say which
scope a row belongs to — it deliberately carries no email or display name, so
it stays safe to render to the capped user themselves.
## Writes (platform admin — confirm with the user first)
All writes accept the same body fields: `max_cost_usd` (**required** on create,
> 0), `interval_type` (**required**), `enforcement` (default `block`),
`alert_thresholds` (default `[0.8, 0.95]`), `enabled` (default `true`). `scope`,
the agent, and the user are inferred from the URL — never the body. Counter
fields sent in the body are ignored.
### Organization cap
- **PUT** `/api/ai-mentor/orgs/{org}/spend-caps/tenant/` — create (201) or update
(200) the org-wide cap.
- **DELETE** `/api/ai-mentor/orgs/{org}/spend-caps/tenant/` — remove it (`204`).
### Agent cap
- **PUT** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-cap/` — create/update
the cap for one agent.
- **DELETE** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-cap/` — remove it.
### User-per-agent cap
- **PUT** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-caps/users/{username}/`
— create/update the cap for one user on one agent (username comes from the URL,
not the body).
- **DELETE** `/api/ai-mentor/orgs/{org}/mentors/{mentor}/spend-caps/users/{username}/`
— remove it.
## Example
```bash
dm=https://api.iblai.app/dm
auth="Authorization: Api-Token $IBLAI_API_KEY"
# Set a $200/month hard-block tenant cap that alerts at 75% and 90%.
curl -X PUT "$dm/api/ai-mentor/orgs/$IBLAI_ORG/spend-caps/tenant/" \
-H "$auth" -H 'Content-Type: application/json' \
-d '{"max_cost_usd": "200.00", "interval_type": "month",
"enforcement": "block", "alert_thresholds": [0.75, 0.9]}'
# Cap one agent at $50/week, alert-only (never blocks chats).
curl -X PUT "$dm/api/ai-mentor/orgs/$IBLAI_ORG/mentors/$MENTOR/spend-cap/" \
-H "$auth" -H 'Content-Type: application/json' \
-d '{"max_cost_usd": "50.00", "interval_type": "week", "enforcement": "alert_only"}'
# How close is a user to their limits? (learner-safe, dollars hidden)
curl "$dm/api/ai-mentor/orgs/$IBLAI_ORG/spend-caps/status/$IBLAI_USERNAME/?mentor=$MENTOR" \
-H "$auth"
# Remove the tenant cap.
curl -X DELETE "$dm/api/ai-mentor/orgs/$IBLAI_ORG/spend-caps/tenant/" -H "$auth"
```
## Notes
- **Blocking is 429, not 402.** A spend cap that blocks a chat returns HTTP
**429** with `{"error_code": "spend_cap_exceeded", ...}`; this is distinct from
the **402** returned when a user runs out of purchased *credits* (see
`iblai-api-billing`). A cap ceilings admin-set LLM cost; credits are a per-user
prepaid balance.
- **Counters are eventually consistent.** `current_spend_usd` is refreshed by a
scheduled reconcile task from ClickHouse, so it can lag real-time spend
slightly. Enforcement reads the cached value to stay off the hot path.
- **Status hides dollars by design.** The status endpoint only exposes
`percent_used` and a zone so a non-admin cannot read org- or agent-wide spend
totals; use the admin read endpoints for the dollar figures.
- **One cap per (scope, agent, user).** Unique constraints allow a single organization
cap, one cap per agent, and one cap per (agent, user); PUT upserts that single
row.
- **Disable vs delete.** Set `enabled: false` to pause a cap without losing its
configuration; DELETE removes it entirely.
## Schema
Cap object (read; write accepts the non-read-only fields):
| Field | Type | Notes |
|---|---|---|
| `id` | int | read-only |
| `scope` | str | `tenant` \| `agent` \| `user_agent`; read-only (from URL) |
| `platform_key` | str | read-only |
| `mentor_unique_id` | str \| null | read-only; set for agent/user_agent |
| `mentor_name` | str \| null | read-only |
| `username` | str \| null | read-only; set for user_agent |
| `email` | str \| null | read-only; set for user_agent |
| `user_full_name` | str \| null | read-only; the capped user's display name, set for user_agent |
| `interval_type` | str | **write**, required: `day`\|`week`\|`month`\|`year` |
| `max_cost_usd` | decimal string | **write**, required on create, > 0 |
| `enforcement` | str | **write**: `block` (default) \| `alert_only` |
| `alert_thresholds` | list[float] | **write**: fractions in `(0, 1]`; default `[0.8, 0.95]` |
| `enabled` | bool | **write**: default `true` |
| `period_started_at` | datetime \| null | read-only (reconciled) |
| `current_spend_usd` | decimal string | read-only (reconciled) |
| `remaining_usd` | decimal string | read-only (`max_cost_usd - current_spend_usd`, floored at 0) |
| `is_exceeded` | bool | read-only (`current_spend_usd >= max_cost_usd`) |
| `last_reconciled_at` | datetime \| null | read-only |
| `created_at` / `updated_at` | datetime | read-only |
Status summary (from the status endpoint):
| Field | Type | Notes |
|---|---|---|
| `status` | str | worst zone: `ok` \| `warning` \| `exceeded` |
| `blocked` | bool | a hard-block cap is already exceeded |
| `caps[]` | list | one entry per applicable cap |
| `caps[].scope` | str | `tenant` \| `agent` \| `user_agent` |
| `caps[].interval_type` | str | `day` \| `week` \| `month` \| `year` |
| `caps[].enforcement` | str | `block` \| `alert_only` |
| `caps[].status` | str | `ok` \| `warning` \| `exceeded` |
| `caps[].percent_used` | float | 0–100+, one decimal |
| `caps[].warning_threshold` | float \| null | lowest configured alert threshold |
| `caps[].mentor_unique_id` | str \| null | set for agent/user_agent caps |
| `caps[].username` | str \| null | set for user_agent caps |