Loading states for a Generate clip button: pending to cancelled

Map Sume's five video job statuses to five UI states, handle the 409 job_not_completed case, and poll at the interval the API suggests instead of a fixed timer.

4 min readSume
All posts

A Generate clip button on top of Sume needs five states, one per job status: pending, in_progress, completed, failed and cancelled. Show a queued message for pending, a progress state for in_progress, the video for completed, a retry button for failed and a quiet reset for cancelled. Sora's UI had four, because it had no cancelled.

Five states

Keep copy short and honest. Rendering a clip takes longer than a typical web request, so say that it is running, show elapsed time, and tell the user they can leave the page. A progress bar with a fake percentage invites distrust when it sticks at 90.

Status to interface mapping (read 2026-10-07)
StatusWhat the user seesButton
pendingWaiting for a slotCancel disabled or hidden
in_progressRendering, with elapsed timeDisabled
completedThe clip, with downloadGenerate again
failedThe error text and no charge noteRetry
cancelledNothing was producedGenerate

What changes from the Sora states

OpenAI's Sora guide, read 2026-10-07, listed queued, in_progress, completed and failed. Rename queued to pending in your state machine, and add the fifth state. If the same screen also reads /v1/jobs, which spells it processing and canceled, normalize both into one internal enum first.

Persist the id

Rendering takes long enough that the screen must survive a reload. Store the job id the moment the 202 arrives and resume polling from it on the next visit. The route returns a polling_url, so the client never has to build one.

Error codes in the UI

A job that is not finished answers a content request with 409 job_not_completed, which is retryable. A failed job answers with 409 job_failed, which is not. Show the first as still working and the second as a retry choice.

  • 409 job_not_completed: keep the spinner.
  • 409 job_failed: show the error and stop polling.
  • 402 insufficient_credits: show a top-up message before any job exists.
  • 429 rate_limited or queue_full: wait and try again.

Poll politely

Poll /v1/jobs/{id}/status and honor next_poll_after_seconds where it is returned, instead of a fixed 2 second timer. It cuts needless requests and follows the server's guidance as it changes. Stop on terminal true. Jobs and results lists the fields.

On failure, show the error text from the job rather than a generic message. The failed status carries an error field, and your support inbox will thank you when users can quote it.

Away from the page

A webhook can update your database while the user is away, so the page shows the finished clip on return. The Sora polling post compares the two approaches.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume