Poll many transcription jobs without a 429: next_poll_after_seconds
Poll Sume job status with the next_poll_after_seconds the API sends, back off on 429 with retry-after, and stop on a terminal status.

When you poll Sume transcription jobs over REST, sleep for the next_poll_after_seconds in the last response, fall back to exponential backoff when it is absent, and stop as soon as terminal is true. On 429 rate_limited, wait for the retry-after header and keep the job ids you already hold. Do not submit a new paid job because a poll failed. These rules are in Jobs and results and Errors and rate limits, read 2026-10-06.
Fields to read on every poll
The envelope tells you what to do next, so you do not need to guess an interval.
| Field | Use |
|---|---|
terminal | True for completed, failed and canceled; stop polling |
next_poll_after_seconds | Sleep this long before the next status call |
result_ready | True when GET result_url will return the result |
status_url, result_url | Use these links instead of building paths |
retry-after header | Seconds to wait after a 429 |
A poll loop for one job
Run one loop per job id from a worker pool, or loop over the pending set in a single thread with a shared sleep. Cap the number of status calls you make per second so a large batch does not trip the abuse limit.
import os, time, requests
API = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def wait_job(job_id, max_seconds=300):
deadline = time.time() + max_seconds
delay = 2.0
while time.time() < deadline:
r = requests.get(f"{API}/v1/jobs/{job_id}/status", headers=H, timeout=30)
if r.status_code == 429:
time.sleep(float(r.headers.get("retry-after", delay)))
continue
r.raise_for_status()
body = r.json()
job = body.get("data", body)
if job.get("terminal"):
return job
delay = float(job.get("next_poll_after_seconds") or min(delay * 2, 30))
time.sleep(delay)
return NoneWhen polling is the wrong tool
For a large batch, a webhook_url on the submit removes polling entirely. For agent clients, the hosted MCP can wait on up to 20 jobs in one call; see jobs_wait for 20 jobs.
Sources
Related posts
More in Developers
- Clicks or gaps when joining TTS MP3 clips: render WAV, join once
Joined MP3 voiceover clips can gap or click. Sume's Timeline audio docs explain why: MP3 adds priming padding at each edge. Keep WAV until the last step.
- Postgres SKIP LOCKED poll table for AI video jobs with next_poll_at
Track Sume video jobs in one Postgres table with next_poll_at, claim due rows with FOR UPDATE SKIP LOCKED and reschedule from next_poll_after_seconds.
- pytest: fail CI when a configured image model id isn't in Sume's list
A pytest that reads your image model ids and checks each against GET /v1/images/models, so a retired id such as gpt-image-1 fails CI before it fails a customer.
- Python asyncio semaphore: submit transcription jobs with a cap
Run Sume STT submits through asyncio.Semaphore and asyncio.to_thread, honor retry-after on 429, and keep one Idempotency-Key per clip. Tested code.
Written by Sume