# API & MCP rate limits

> Per-plan throughput caps for the MCP server and Workspace API, response headers, and how to design pipelines around them.

**Category:** AI Integrations | **Tab:** integrations

---

Black Ice applies rate limits to every programmatic entry point — the MCP server, the Workspace REST API, and the OAuth client registration endpoint. Limits scale with your plan so paid workspaces can run parallel agents and CI pipelines without being throttled.

## Limits by plan

Limits are counted **per workspace**, in a rolling one-minute window.

| Plan | Read calls / min | Write calls / min |
|---|---|---|
| Free | 60 | 30 |
| Pro | 300 | 120 |
| Builder | 1,000 | 400 |

**Reads** are lookups: `check_term`, `validate_translation`, `check_market_availability`, `list_concepts`, `list_classes`, `list_relationships`, `get_market_profile`, and every `GET` against the Workspace API.

**Writes** are mutations: creating or updating concepts, terms, markets, and market definitions — through the MCP tool `suggest_candidates` (optional review-queue suggestions) or `POST`/`PATCH`/`DELETE` on the Workspace API.

MCP tool calls and direct REST calls share the same budget: an MCP call is internally a call to the same ontology functions, so 100 MCP reads and 100 REST reads both consume 100 read units.

## Monthly call cap (Free plan)

Beyond the per-minute throttle, the **Free plan has a hard cap of 10,000 API + MCP calls per calendar month, per workspace**. Pro and Builder have **no monthly cap** — only the per-minute limits above apply.

The cap is shared by every connection in the workspace — all MCP clients and API keys draw from the same 10,000 calls. It is not counted per connection, and you never need a separate subscription per connection.

| Plan | Monthly API + MCP calls |
|---|---|
| Free | 10,000 |
| Pro | Unlimited |
| Builder | Unlimited |

**What counts as a call:** every MCP tool call and every REST request to the Workspace API — reads and writes alike — counts as one call. Using the Black Ice web app, importing a spreadsheet, exporting an ontology, or running GitHub Sync does **not** consume the allowance.

**When it resets:** at 00:00 UTC on the 1st of each calendar month. Upgrading to Pro or Builder lifts the cap immediately.

**What happens at the cap:** calls return `429 Too Many Requests` with `Retry-After` and a body carrying the machine-readable code `monthly_cap_reached`:

```json
{
  "error": "Monthly call limit reached: 10,000 calls/month on the Free plan. Resets on 1 September.",
  "code": "monthly_cap_reached",
  "tier": "free",
  "limit": 10000,
  "used": 10000
}
```

Treat this differently from a per-minute 429: retrying in a few seconds will not help. Branch on `code === "monthly_cap_reached"`, stop the run, and either wait for the reset or upgrade.

**Checking your remaining allowance:** Free-plan responses carry monthly headers alongside the per-minute ones.

| Header | Meaning |
|---|---|
| `X-RateLimit-Scope` | `month` when the monthly cap applies |
| `X-RateLimit-Month-Limit` | Monthly allowance (10,000 on Free) |
| `X-RateLimit-Month-Remaining` | Calls left this month |
| `X-RateLimit-Month-Reset` | Unix timestamp of the reset (1st of next month, 00:00 UTC) |

The same figure is shown in the app under **Integrations → Usage & Analytics**, with a warning once you pass 80% of the allowance.

## Client registration (OAuth DCR)

Dynamic client registration on the MCP OAuth endpoint is capped at **10 registrations per hour per IP address**, on all plans. This protects the authorization server and is unrelated to your tool-call budget — a normal MCP client registers once and reuses its credentials.

## Reading the response headers

Every API and MCP response carries the current budget state:

| Header | Meaning |
|---|---|
| `X-RateLimit-Limit` | Maximum calls allowed in the current window |
| `X-RateLimit-Remaining` | Calls left before throttling |
| `X-RateLimit-Reset` | Unix timestamp (seconds) when the window resets |

When you exceed the limit, the response is `429 Too Many Requests` with a `Retry-After` header (seconds to wait) and a JSON body describing the limit and your plan.

```json
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded for plan 'pro'. Try again in 24 seconds.",
  "limit": 300,
  "retry_after": 24
}
```

## Designing pipelines that stay under the cap

- **Respect `Retry-After`.** Treat a 429 as a scheduling signal, not an error. Sleep for the advertised interval and resume.
- **Use exponential backoff with jitter** for retries beyond the first, so parallel workers do not retry in lockstep.
- **Batch where possible.** `list_concepts` with a filter returns many concepts in one call; looping `check_term` per string does not.
- **Cache market profiles.** Market definitions change rarely — fetch `get_market_profile` once per run and reuse it across all strings for that locale.
- **Watch `X-RateLimit-Remaining`** and slow down proactively when it drops below ~10% rather than sprinting into a 429.
- **Split heavy jobs across workspaces** if you run genuinely independent pipelines, since budgets are per workspace.

## Worked example: a CI translation check

A pull request touching 200 strings, checked on the Builder plan:

1. One `get_market_profile` call per target locale (5 locales = 5 reads, cached for the run).
2. One `list_concepts` call to pull the relevant class (1 read).
3. `validate_translation` per string per locale — 200 x 5 = 1,000 reads.

That is 1,006 reads. On Builder (1,000/min) the job completes in just over a minute with a single short pause; on Free (60/min) it would take roughly 17 minutes. Caching profiles and batching concept lookups is what keeps the number close to the theoretical minimum.

## Need more throughput?

Limits are a fair-use protection, not a hard product boundary. If your workload consistently needs more than the Builder allowance — for example a high-volume localization pipeline or an agent fleet running continuously — contact support and we will review a custom limit for your workspace.