Skip to main content

Rate limits

Generation endpoints are rate limited. Reads are not.

How it works

Limits are counted per user, not per IP — every key you own draws on the same allowance, so splitting work across keys does not buy you more throughput.

Exceeding a limit returns 429 with a Retry-After header giving the number of seconds to wait:

HTTP/1.1 429 Too Many Requests
Retry-After: 3600

POST /gen/video is additionally subject to a daily video cap. That cap surfaces the same way, so a 429 there may mean "wait an hour" or "you're done for today" depending on which limit you hit — Retry-After tells you which.

What the limits are

Limits vary by plan, and they change when plans are retuned. Rather than print numbers here that would quietly go stale, see botlobby.ai/pricing for the current figures.

GET /subscription/current also returns your own limits under limits and your consumption under usage_summary, which is the authoritative answer for your account at this moment.

Backing off

Honour Retry-After. Exponential backoff on top of it protects you when many workers hit the wall together:

import time
import requests

def post_with_backoff(url, json, headers, max_attempts=5):
delay = 1
for attempt in range(max_attempts):
response = requests.post(url, json=json, headers=headers, timeout=30)

if response.status_code != 429:
return response

# Retry-After is authoritative; the exponential delay is only a floor
# for the case where it is absent.
wait = int(response.headers.get("Retry-After", delay))
time.sleep(wait)
delay = min(delay * 2, 60)

raise RuntimeError(f"still rate limited after {max_attempts} attempts")

Do not retry in a tight loop without sleeping. It will not get you through the limit any faster and makes the 429 last longer.

Designing around limits

  • Check before a batch. GET /subscription/current tells you your remaining headroom before you start, which is better than discovering it partway through.
  • Queue rather than parallelise. Since limits are per user, ten concurrent workers hit the same ceiling as one — they just hit it in a messier way.
  • Separate reads from writes. Polling task-status is not rate limited, so a polling loop never eats into your generation allowance.