Poll every 2 s or 30 s? Reads per 20-minute video job on Free and Pro
Polling a Sume video job every 2 s is 600 reads in 20 minutes; every 30 s is 40. Share of the read budget on Free and Pro, with a Python check.

Polling a video job every 2 seconds for 20 minutes is 600 reads; every 30 seconds it is 40. Even at 2 seconds, a Pro workspace with all 24 accepted jobs polled by one key uses 6.00% of its read budget, and a Free workspace with its 6 jobs uses 3.75%. So rate limits are not the reason to slow down; cost of your own compute and noise are. The 30-second cadence in Sume's examples is a default, not a limit.
The two budgets
Each API key has a per-minute budget for all of /v1, set by the plan of the workspace that owns it. Reads and writes are counted separately, so a tight poll loop cannot cause a 429 on your own submits. A read is any GET or HEAD, including polls of status, events and result. Free gets 4,800 reads and 120 writes per minute; Pro gets 12,000 reads and 300 writes.
The number of jobs you can have in flight is capped too. Free accepts 6 paid generation jobs at a time (1 processing plus 5 queued) and Pro accepts 24 (4 plus 20), so those are the worst cases for the share table: every accepted job being polled at the same interval.
| Interval | Polls per job (20 min) | Free (6 jobs) | Pro (24 jobs) |
|---|---|---|---|
| 2 s | 600 | 3.75% | 6.00% |
| 5 s | 240 | 1.50% | 2.40% |
| 10 s | 120 | 0.75% | 1.20% |
| 30 s | 40 | 0.25% | 0.40% |
How the numbers are computed
For Pro at 2 seconds: 24 jobs x 60 / 2 = 720 reads per minute, and 720 / 12,000 = 6.00%. For Free at 30 seconds: 6 x 60 / 30 = 12 reads per minute, and 12 / 4,800 = 0.25%. Polls per job is 1,200 seconds divided by the interval. The script does the same arithmetic from the two plan tables so you can add Startup and Scale.
READS_PER_MIN = {"free": 4800, "pro": 12000, "startup": 24000, "scale": 48000}
ACCEPTED_JOBS = {"free": 6, "pro": 24, "startup": 48, "scale": 120}
DEADLINE_S = 20 * 60
print("interval polls_per_job free(6 jobs) pro(24 jobs)")
for interval in (2, 5, 10, 30):
row = []
for plan in ("free", "pro"):
per_min = ACCEPTED_JOBS[plan] * 60 / interval
row.append(f"{per_min / READS_PER_MIN[plan]:.2%}")
print(f"{interval:>6}s {DEADLINE_S // interval:>13} {row[0]:>12} {row[1]:>12}")What to do instead of tuning
Fixed intervals are the simplest policy and they are fine. Better ones are cheap to add. On the generic job routes the status response can include next_poll_after_seconds, and the docs say to obey it when present and use backoff when it is not. A webhook with callback_url removes most polls, and the docs still advise keeping a slow poll as a backup for deliveries that never arrive. A webhook receiver with a 30-second backup poll uses 40 reads per 20-minute job at most, the last row of the table, and usually far fewer because the poll stops when the callback lands.
One caveat: the budget is per key. If several services share one key, add their polls together before you read the table.
Startup and Scale follow the same arithmetic. Startup reads 24,000 per minute with 48 accepted jobs, and Scale reads 48,000 per minute with 120 accepted jobs. At a 2-second interval that is 48 x 30 / 24,000 = 6.00% and 120 x 30 / 48,000 = 7.50% of the read budget, so the share stays in single digits at every self-serve plan even for the most aggressive loop.
- Start fast for short clips, then back off.
- Poll less when a job is queued; it cannot finish before it starts.
- Keep a 30-second backup poll when you use webhooks.
Sources
Related posts
More in Developers
- Status reads for a full Sume queue: 3,600 to 72,000
Poll every accepted job every 2 s for 20 minutes: Free makes 3,600 reads, Scale 72,000. The math, and how one field cuts it.
- Polling a 5-minute video: 30 s is 10 reads, 2 s is 150 on Sume
How often to poll a Sume video job: read counts for a 300 s job at 30 s and 2 s, and an asyncio loop that obeys next_poll_after_seconds.
- Porting chat history to Agent Completions: assistant turns fail
Sume Agent Completions take OpenAI-style messages but return 400 on any assistant turn and start each call in a new thread. What to send instead.
- OpenRouter video payload on Sume: drop seed, size, provider.options
Sume /v1/videos follows the OpenRouter shape but rejects seed, size and provider.options with a 400. A Node function that strips them and checks the model id.
Written by Sume