Video generation broke every assumption my request-handling code was built on. A job takes anywhere from forty seconds to eleven minutes. It fails a small but non-trivial fraction of the time for reasons unrelated to your input. It costs real money per attempt, so a careless retry is a charge, not a hiccup. And you're doing this across several providers, each with its own idea of what a job status API looks like.

This is not an HTTP problem. It's a distributed systems problem wearing an HTTP costume.

Own the job, not the request

The first architectural decision that matters: your job ID is not the provider's job ID. POST /generate returns 201 {"job_id": "job_7fc2a1", "status": "queued"}, and that ID is minted before you talk to any provider. That indirection buys you three things: retrying onto a different provider without the client noticing, surviving a provider that loses its own job ID, and a stable identity for logs and billing.

The state machine should be explicit and boring: