Rate limits

Requests are metered per API key. The limits are generous for reporting and automation, and tight enough that a runaway loop cannot take the service down for everyone.

The limits

Applies toSustainedBurst
A valid API key60 / minute20
Requests with no valid key, per IP20 / minute

Limits are counted with a token bucket: you refill at the sustained rate and may spend up to the burst allowance at once. A scheduled job that fires twenty requests in a second and then goes quiet stays comfortably inside the limit.

The limit applies per key, so splitting a workload across two keys does not double your budget in any meaningful way — but it does let you keep a noisy backfill from starving an interactive dashboard.

Reading your remaining budget

Successful responses carry your current standing:

Response headers
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 17

X-RateLimit-Remaining is tokens left in the bucket right now. Watching it fall toward zero is a cheaper signal to slow down than waiting to be rejected.

When you exceed a limit

You get 429 with code rate_limited and a Retry-After header in seconds:

429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 7

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded (60 requests per minute). Retry in 7s.",
    "traceId": "0HN7A2QK9V1M4:00000009"
  }
}

Honour Retry-After

It is computed from how long the bucket actually needs to refill enough for your request. Retrying sooner will simply be rejected again, and a tight retry loop against a 429 keeps your own bucket permanently empty.

If you are not already using a client that backs off, the whole handling is short:

Node
async function callNubo(path) {
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch(`https://api.nubo-chat.com${path}`, {
      headers: { "X-API-Key": process.env.NUBO_KEY },
    });

    if (res.status !== 429) return res;

    // Retry-After is authoritative; fall back to a small delay if it is absent.
    const wait = Number(res.headers.get("Retry-After") ?? 5);
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  throw new Error("Nubo API: still rate limited after 5 attempts");
}

Staying well under

Most integrations that hit the limit are polling far more often than their data changes. Usage aggregates move slowly; polling /v1/usage every few minutes gives you nothing that polling hourly would not.

If you are syncing sessions, walk closed time windows on a schedule rather than re-reading the most recent page in a loop — it uses fewer requests and, as the Endpoints page explains, it is also the only way to avoid missing rows.

Will these change?

The current limits are operational rather than commercial — every plan gets the same numbers today. They may be raised, and may eventually vary by plan. Read your budget from the response headers rather than hardcoding 60, and your client will keep working either way.