# Limits, budgets, and usage

> Distinguish request rate, monthly quota, hard budget, credits, and Usage API counters.

Canonical guide: <https://api.blackpearl.com/docs/usage-quotas>

Raw Markdown: <https://api.blackpearl.com/docs/raw/usage-quotas.md>

OpenAPI: <https://api.blackpearl.com/v1/openapi.json>

Five controls can affect whether work starts:

| Control | Purpose | Failure and recovery |
|---|---|---|
| Request rate | Limits request pace for a project key. | `rate_limit_exceeded`; retry after `Retry-After`. |
| Usage quota | Limits metered requests, tokens, or cost at organization, project, API-key, and optional capability scope for a UTC calendar month. | `quota_exceeded`; use `error.details.resets_at`, wait for reset, or ask an administrator to change the quota. |
| Hard cost budget | Stops new capability work after an organization or project monthly cost ceiling is reached. | `budget_exceeded`; use `error.details`, wait for reset, or ask an administrator to change the budget. |
| Usage-tier cost cap | Stops new capability work at the organization's tier-based monthly spend ceiling. | `budget_exceeded` with `error.details.scope: usage_tier`; wait for reset or a tier change. |
| Prepaid credits | Requires a positive spendable balance when billing is enabled; no future job price is estimated or reserved. | `insufficient_credits`; add credits or let auto-recharge complete. |

Only the rate-limit case is a transient automatic retry. See [Errors](https://api.blackpearl.com/docs/errors).

All quota and budget periods begin at `00:00:00 UTC` on the first day of a calendar month and reset at the next month's boundary. An error's structured `details` reports the applicable scope, limit, current value, remaining value, and `resets_at`. Do not automatically retry either code merely because its HTTP status is `429`: an administrator may change a control before reset, but only `rate_limit_exceeded` is transient by itself.

## What each counter records

One newly accepted Playbooks job or Audience cycle adds exactly `1` to Usage `requests`. Idempotent replay returns the original job without adding another request. Rejected job creation, campaign setup, reads, polling, candidate retrieval, and Usage calls add `0` to this monthly counter. They can still consume the API-key request-rate window.

When a job finishes, its capability execution adds attributed `tokens` and downstream `cost_usd`; it does not add a second request. A request quota checks whether the next new job would exceed its limit. Token and cost quotas stop new jobs once recorded usage has reached the limit. Work already accepted continues even if a later completion crosses a token, cost, or budget threshold.

Budgets use the append-only downstream cost ledger, independently of Usage quotas. A soft budget records alerts but does not reject work. A hard budget rejects new work at or above its monthly ceiling. Prepaid billing is separate: any positive spendable balance permits work to start, with no admission estimate or price reserve. At completion, actual downstream cost with the organization's billing markup is charged. If that actual price exceeds the remaining balance, the balance is consumed and the job fails without exposing its result; auto-recharge is then triggered. `credits.balance_usd` is the current ledger balance, not a monthly counter.

Usage records are append-only. The public Usage API returns the authenticated project's current monthly rollup and capability breakdown:

```bash
curl --fail-with-body --silent --show-error \
  "$BLACKPEARL_API_BASE_URL/v1/usage" \
  --header "Authorization: Bearer $BLACKPEARL_API_KEY" | jq .
```

```json
{
  "project_id": "proj_example",
  "period": "2026-07",
  "period_start": "2026-07-01T00:00:00Z",
  "period_end": "2026-08-01T00:00:00Z",
  "rollup": {
    "requests": 12,
    "tokens": 45200,
    "cost_usd": 1.243
  },
  "by_capability": [
    {
      "capability_key": "playbooks",
      "requests": 12,
      "tokens": 45200,
      "cost_usd": 1.243
    }
  ],
  "usage_tier": {
    "key": "growth",
    "name": "Growth",
    "rank": 2,
    "rate_limit_per_minute": 120,
    "monthly_cost_cap_usd": 250.0
  },
  "rate_limit": {
    "limit": 120,
    "window_seconds": 60
  },
  "quotas": [
    {
      "metric": "requests",
      "period": "month",
      "scope": "project",
      "capability_key": "playbooks",
      "limit_value": 1000,
      "used": 12,
      "remaining": 988,
      "resets_at": "2026-08-01T00:00:00Z"
    }
  ],
  "budgets": [
    {
      "period": "month",
      "scope": "project",
      "capability_key": null,
      "limit_usd": 50,
      "spend_usd": 1.243,
      "remaining_usd": 48.757,
      "hard_limit": true,
      "resets_at": "2026-08-01T00:00:00Z"
    }
  ],
  "credits": {
    "billing_enabled": true,
    "balance_usd": 98.757,
    "topup_increment_usd": 25.0
  }
}
```

`period_start` is inclusive and `period_end` is exclusive. `rollup` totals the project, while `by_capability` reconciles those counters by capability key. `usage_tier` is nullable and reports the organization's resolved rate and monthly cost cap when tiering applies. `quotas` includes every organization, project, or API-key quota that can affect this key; `budgets` includes every organization or project budget that can affect this project. Empty arrays mean no matching control is configured. Compare a completed job's `usage` with these rollups while allowing for other jobs in the same period.

Usage retrieval is OpenAPI operation `usage_v1_usage_get` with schema `PublicUsageResponse`.
