# Hierarchical budgets

Four nested scopes. Every proxied call is checked against every scope it belongs
to, and the **tightest** applicable limit wins.

```
org                      the whole account
 └── team                from x-spendline-tags team / cost_center
      └── agent          from x-agent-id
           └── customer  from x-customer-id
```

| `scope_type` | `scope_id` comes from | Example |
|---|---|---|
| `org` | nothing, `scope_id` must be omitted/null | account-wide cap |
| `team` | `x-spendline-tags` cost-centre key | `"support"` |
| `agent` | `x-agent-id` | `"support-bot"` |
| `customer` | `x-customer-id` | `"cus_123"` |

This is why attribution headers are not optional metadata: **they are the
addressing scheme budgets use**. A call with no `x-agent-id` cannot be caught by
an agent-scoped budget.

## The common asks, mapped

**"Stop this agent spending more than $500/month."**

```json
{ "scope_type": "agent", "scope_id": "support-bot", "monthly_limit_usd": 500, "strict_mode": true }
```

**"Cap this one customer at $50/month."**

```json
{ "scope_type": "customer", "scope_id": "cus_123", "monthly_limit_usd": 50, "strict_mode": true }
```

**"One hard cap across OpenAI and Anthropic together."**

```json
{ "scope_type": "org", "monthly_limit_usd": 10000, "strict_mode": true }
```

The cap spans providers because enforcement is in the request path, not in a
provider dashboard. This is the thing provider-side spend limits cannot do.

**"Cap the support team, but let one agent inside it go higher."**

Not possible, the tightest limit always wins, so the team cap binds the agent.
Model it as a higher team cap plus tighter per-agent caps instead.

## Discovering scope ids

```bash
curl https://www.spendline.ai/api/budgets/scopes \
  -H "x-spendline-key: $SPENDLINE_API_KEY"
```

Returns the `agents`, `customers` and `teams` that actually have traffic this
month. Budget against these rather than guessing identifiers.

## Spend against limit

```bash
curl https://www.spendline.ai/api/budgets/summary/all \
  -H "x-spendline-key: $SPENDLINE_API_KEY"
```

## Concurrency

Enforcement is designed so concurrent in-flight calls do not share one stale
spend baseline. You do not need to serialize calls in your application to make
budgets correct.

## Months are UTC

Budget periods are calendar months in UTC, formatted `YYYY-MM`. A budget resets
at `00:00 UTC` on the 1st.

## Overrides

When a legitimate call is blocked, the path is an **override request**
(`POST /api/budgets/overrides`) which an owner approves or rejects. Approval is
recorded with the approver. Do not solve a 402 by raising the cap silently, that
is the audit trail the product exists to produce.
