Asynchronous Job Pattern
Instead of making the caller wait, the API accepts the work, hands back a job ID, and tells you when it is done.
See it
What it is
Some work cannot finish inside one HTTP request: video encoding, big exports, model runs, bulk imports. The asynchronous job pattern splits the call in two. The first request accepts the work and answers immediately with 202 Accepted, a job ID, and a status URL. The caller then finds out about completion in one of three ways: polling the status URL, receiving a webhook, or watching an SSE stream.
The status resource is the whole contract. Give it a small state machine (queued, running, succeeded, failed, cancelled), a progress number when you can compute one, a structured error when it fails, and a result location when it succeeds. Behind it, the actual work almost always lives on a message queue with a pool of workers.
Gotcha: the two states people forget are failure and expiry. A job that sits at 'running' forever because a worker died will hang every client polling it, so give jobs a deadline that flips them to failed. And say plainly how long results stay downloadable. One more: pair job creation with an idempotency key, or a nervous client tapping retry will queue the same expensive job five times.
Ask AI for it
Convert this long-running endpoint into an asynchronous job API. POST should validate the input, enqueue the work, and return 202 Accepted with a job ID and a Location header pointing at 'GET /jobs/{id}'. That status endpoint returns status (queued, running, succeeded, failed, cancelled), a progress percentage, a structured error object on failure, and a result URL on success. Accept an idempotency key on creation so retries return the existing job instead of starting a second one, expire jobs that exceed a maximum runtime into the failed state, and document how long results stay retrievable. On the client, poll with exponential backoff and render each state distinctly.