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 2xx response). A request that returns an error, including a 429, 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 UTC each day; the monthly window resets at 00:00 UTC on 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_quota tool 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.

  1. Honor Retry-After / X-Quota-Reset on REST, and retryAfterSeconds on MCP. Wait the indicated time before retrying — don't retry immediately or in a tight loop. If Retry-After is absent (see edge throttling), fall back to exponential backoff with jitter.

  2. Watch X-Quota-Remaining and slow down before it reaches zero, rather than waiting for the 429.

  3. Pre-flight large jobs with the quota endpoint or get_account_quota, so you know your headroom on that surface before starting.

  4. 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 filter with the in operator 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 an in() filter instead of one get_* 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 429 with the JSON error body and the X-Quota-* headers.
  • Edge throttling: at extreme request rates, requests may be shed at the network edge before reaching Hubbl. That response is a bare 429 without the X-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.