Usage Quota
Hubbl's public API enforces per-account quota limits on its two surfaces, each with its own quota:
- API quota: direct requests to the REST API (
api.hubbl.com). - MCP quota: direct tool calls to the MCP server (
mcp.hubbl.com).
Requests made by Hubbl's verified Ask Hubbl and Slack agents are logged for usage tracking without consuming customer quota.
This page covers how each quota counts, the headers on every REST response, what a quota-exceeded response looks like on each surface, which calls are quota-exempt, how to check your remaining quota, and the patterns we recommend for staying under the limit.
How the limits work
- Separate quotas per surface. REST requests draw on your account's API quota, and MCP tool calls draw on its MCP quota. Using one surface never reduces your allowance on the other.
- One tool call counts once. A tool call made directly to the MCP server counts as one request against the MCP quota, however many reads it performs on your behalf. The requests the MCP server makes to the REST API for that call do not count against your API quota.
- Only successful requests count. A REST request counts only when it succeeds (a
2xxresponse). A request that returns an error, including a429, does not draw down your quota. On MCP, a tool call counts only when it returns a result that is not an error. - Hubbl agent traffic is exempt. Ask Hubbl and the Slack agent are recognized from their verified client identity. A caller-supplied header cannot grant this exemption.
- Two windows, enforced together. Each quota has a daily limit and a monthly limit, both active at once. Exceeding either throttles that surface until that window resets — the other window keeps counting independently.
- Calendar-aligned, in UTC. The daily window resets at
00:00 UTCeach day; the monthly window resets at00:00 UTCon the first day of each month. These are fixed calendar boundaries, not a rolling window — your full allowance is available again the moment the window resets. - Limits are account-specific and may change. Do not hardcode them. Read your current limit and remaining allowance from the response headers, the quota endpoint or the
get_account_quotatool at runtime.
Quota-exempt calls
These calls never count toward either quota, however often you make them:
| Surface | Call |
|---|---|
| REST | GET /v1/account/quota |
| MCP | get_account_quota tool |
| MCP | server_info tool |
The API reference and the MCP reference mark each quota-exempt endpoint and tool.
Response headers
Every REST response — success or 429 — carries these headers, which describe your API quota:
| Header | Meaning |
|---|---|
X-Quota-Limit |
The maximum requests allowed in the current window. |
X-Quota-Remaining |
Requests remaining before you are throttled. |
X-Quota-Reset |
Unix timestamp (seconds) when the window resets and the count clears. |
X-Quota-Limit: <N>
X-Quota-Remaining: <N>
X-Quota-Reset: <unix-timestamp>
Because two windows are in effect at once, these headers describe a single window — the most restrictive one for you at that moment: the limit you are closest to hitting, or, when you are throttled, the one currently blocking you. For a full per-window breakdown of both daily and monthly state, call the quota endpoint.
When you exceed the limit
REST
When your API quota is exhausted, the request returns HTTP 429 Too Many Requests with a Retry-After header (seconds to wait) alongside the standard X-Quota-* headers, and this body:
{
"error": {
"status": 429,
"title": "Too Many Requests",
"detail": "Quota limit exceeded. Retry after <N> seconds."
}
}
MCP
When your MCP quota is exhausted, a tool call comes back as an error tool result, because MCP tool calls have no HTTP status to return to the client. Detect it programmatically via structuredContent.error === "quota_exceeded"; retryAfterSeconds tells you how long to wait. The text content carries the same message for display.
{
"isError": true,
"content": [{ "type": "text", "text": "Quota limit exceeded. Retry in <N> seconds." }],
"structuredContent": {
"error": "quota_exceeded",
"retryAfterSeconds": <N>,
"limit": <N>
}
}
Check your quota
GET /v1/account/quota returns your account's API quota for both windows. Checking your quota does not count against it; poll it as often as you need. Authenticate the same way as for any other endpoint.
{
"data": {
"quotaLimit": {
"daily": { "limit": <N>, "remaining": <N>, "resetAt": "2026-06-09T00:00:00.000Z" },
"monthly": { "limit": <N>, "remaining": <N>, "resetAt": "2026-07-01T00:00:00.000Z" }
}
}
}
On MCP, the get_account_quota tool returns your account's MCP quota in the same shape, in its structuredContent. It is quota-exempt too. Use it as a pre-flight check before launching an ambitious fan-out workflow so you can pace your calls.
Recommended client patterns
Honor
Retry-After/X-Quota-Reseton REST, andretryAfterSecondson MCP. Wait the indicated time before retrying — don't retry immediately or in a tight loop. IfRetry-Afteris absent (see edge throttling), fall back to exponential backoff with jitter.Watch
X-Quota-Remainingand slow down before it reaches zero, rather than waiting for the429.Pre-flight large jobs with the quota endpoint or
get_account_quota, so you know your headroom on that surface before starting.Prefer bulk reads over by-id fan-out. Fetching records one ID at a time costs one request — and one unit of quota — per record. Use the list endpoint's
filterwith theinoperator to fetch many in a single request instead:# Instead of N requests: GET /v1/orgs/{orgId}/connectedApps/{id} (repeated per id) # Make one request: GET /v1/orgs/{orgId}/connectedApps?filter=in(id,1,2,3)One request, one unit of quota, the same data. On MCP, the same applies: call a
list_*tool with anin()filter instead of oneget_*call per record. This is the single biggest lever for staying under the limit when reading many records.
Edge throttling
There are two distinct sources of a REST 429, and they look different:
- Your API quota limit (everything above): a
429with the JSON error body and theX-Quota-*headers. - Edge throttling: at extreme request rates, requests may be shed at the network edge before reaching Hubbl. That response is a bare
429without theX-Quota-*headers or the JSON body, and reflects raw burst rate rather than your account quota.
Handle both the same way — back off and retry — but a headerless 429 means you are bursting too fast; spread your requests out rather than firing them in parallel.