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/currenttells 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-statusis not rate limited, so a polling loop never eats into your generation allowance.