Async API Job Status Endpoint Example: 202 Accepted, Polling and Long-Running Operations
Async API Job Status Endpoint Example & Best Practices
Asynchronous API Design

Async API Job Status Endpoint Example: 202 Accepted, Polling and Long-Running Operations

When work cannot finish within a normal request-response window, accept the request and return an operation resource rather than keeping the connection open indefinitely. A clean asynchronous API gives the client an operation ID, status URL, lifecycle states, retry guidance and a final result or error it can retrieve deterministically.

Implementation guideAPI Example
Start response202 Accepted
Track withOperation resource
Client patternPolling / callback
Key ruleStatus is independently queryable

Async API Example with 202 Accepted

An async API job status design should separate request acceptance from eventual completion: return 202 Accepted, expose a stable operation resource, and let the client observe queued, running, succeeded or failed states without keeping the original connection open.

RFC 9110 defines 202 Accepted for a request that has been accepted for processing but is not complete. The response ought to describe the current status and point to a status monitor.

202 is noncommittal. RFC 9110 explicitly notes that the work might or might not eventually be performed and that HTTP cannot later resend a status code for the asynchronous operation. The operation/status resource is therefore part of the API design, not an automatic feature of 202.
POST /v1/reports HTTP/1.1
Content-Type: application/json

{
  "account_id": "acct_42",
  "from": "2026-09-01",
  "to": "2026-09-30"
}

HTTP/1.1 202 Accepted
Location: /v1/operations/op_7YQ2
Retry-After: 3
Content-Type: application/json

{
  "operation_id": "op_7YQ2",
  "status": "queued",
  "status_url": "/v1/operations/op_7YQ2"
}

The operation resource decouples the client from worker execution. The original HTTP connection can end immediately while processing continues elsewhere.

REST API Job Status Endpoint Example

GET /v1/operations/op_7YQ2 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json
Retry-After: 5

{
  "id": "op_7YQ2",
  "status": "running",
  "progress": 65,
  "created_at": "2026-10-06T09:20:00Z",
  "started_at": "2026-10-06T09:20:02Z",
  "updated_at": "2026-10-06T09:20:18Z"
}

Clients should treat the operation as a real resource with normal authorization. Do not put sensitive job details into an unauthenticated status URL just because it is “only metadata.”

Designing the Async Job State Model

StateMeaningClient action
queuedAccepted but not startedPoll later; do not resubmit automatically.
runningWorker is processingContinue polling at the advised interval.
succeededOperation finishedFollow result/resource link.
failedTerminal failureInspect structured error; resubmit only if contract allows.
cancel_requestedCancellation accepted but not finalContinue polling until terminal state.
cancelledTerminal cancelled stateDo not expect a result.

Keep terminal states stable so clients can safely re-read them. If operation records expire, document the retention period and what status is returned after expiry.

Polling an Async API Without Creating a Thundering Herd

  • Return a suggested delay such as Retry-After when useful.
  • Increase polling intervals for long-running work rather than polling every few milliseconds.
  • Add jitter in large client populations so every client does not poll on the same schedule.
  • Use conditional GET/ETag if operation representations are large or high-volume.
  • For very long workflows, consider callbacks/webhooks or event delivery in addition to polling.

About Retry-After: HTTP standardizes it for 503 and redirection responses, and RFC 6585 allows it with 429. Some async APIs also use it as a polling hint on 202 or operation-resource responses; if you do, document that as an API convention rather than a generic 202 requirement.

If callbacks are appropriate, Ammune already has a separate webhook explainer; keep the job-status endpoint as the source of truth even when notifications are available.

Returning the Final Result or Error

When the operation succeeds, return a link to the created or generated resource rather than embedding a giant result inside every status poll:

{
  "id": "op_7YQ2",
  "status": "succeeded",
  "completed_at": "2026-10-06T09:21:04Z",
  "result": {
    "report_id": "rpt_123",
    "href": "/v1/reports/rpt_123"
  }
}

For failure, return a stable structured problem. RFC 9457 application/problem+json is a useful standard shape for machine-readable API errors.

{
  "id": "op_7YQ2",
  "status": "failed",
  "error": {
    "type": "https://api.example.com/problems/report-source-unavailable",
    "title": "Report source unavailable",
    "status": 503,
    "detail": "One required data source could not be reached."
  }
}

Should an Async API Support Cancellation?

Cancellation is useful for expensive work, but define its semantics carefully. A cancel request usually means “stop further work if possible,” not “roll back every side effect that already occurred.”

POST /v1/operations/op_7YQ2/cancel

202 Accepted
{ "id":"op_7YQ2", "status":"cancel_requested" }

Idempotent cancellation semantics are helpful: asking to cancel an already cancelled operation should not restart or duplicate anything.

Security Considerations for Job Status Endpoints

  • Authorize the operation resource to the same tenant/user context as the work it represents.
  • Do not use guessable sequential operation IDs without authorization checks.
  • Avoid exposing sensitive worker errors, internal paths or stack traces.
  • Set retention limits for operation metadata and results.
  • Rate-limit polling and cancellation endpoints.
  • Use idempotency on the start operation when duplicate jobs would be harmful.

See idempotency API examples when starting the same long-running job twice would cause duplicate work.

Common Async API Design Mistakes

  • Returning 202 with no way to discover whether the work ever completed.
  • Using an operation ID that is not authorized as a resource.
  • Keeping the client connection open for minutes even though workers are asynchronous.
  • Polling at a fixed aggressive interval with no backoff or server guidance.
  • Deleting the operation record immediately on completion so clients miss the result.
  • Conflating “cancel requested” with a guaranteed rollback.

Make Starting an Async Job Idempotent When Needed

Long-running work is often expensive, so duplicate starts can be worse than duplicate lightweight writes. If the client times out before receiving the 202 response, it may not know whether the job was queued. An idempotency key lets the start endpoint return the original operation instead of scheduling a duplicate.

POST /v1/reports
Idempotency-Key: "monthly-report-acct-42-2026-09"

202 Accepted
Location: /v1/operations/op_7YQ2

If the same key is retried while the job is still running, return or reference op_7YQ2. If it is retried after success, return the same operation/result according to the retention contract.

Polling vs Webhooks vs Event Notifications

MechanismStrengthTrade-off
PollingSimple; works behind client firewalls; client controls timingRepeated requests and slower notification.
WebhookEfficient server-to-server completion notificationRequires callback security, retry and delivery verification.
Event/messageScales for internal distributed systemsRequires shared messaging infrastructure and consumer lifecycle.

These mechanisms are not mutually exclusive. A webhook can tell the client that work changed, while the authenticated status endpoint remains the source of truth. This avoids forcing notification delivery to carry the complete authoritative result.

How Ammune Fits

Async APIs create multiple related endpoints—the starter, status resource, cancellation action and final result. Ammune can discover and observe these runtime flows, helping identify abnormal job creation, aggressive polling, repeated cancellation, or unexpected access to operation resources.

Production Implementation Checklist

  • Return 202 only when processing is genuinely not complete.
  • Create a stable operation resource with an opaque identifier.
  • Authorize every status, result and cancel request.
  • Define lifecycle states and terminal states explicitly.
  • Provide Retry-After or documented polling guidance.
  • Keep terminal results available for a documented retention window.
  • Return structured errors for failed jobs.
  • Use idempotency when duplicate job starts are harmful.
  • Define cancellation semantics separately from rollback.
  • Load-test polling behavior and worker backpressure.

Frequently Asked Questions

What status code should an asynchronous REST API return?

202 Accepted is the standard status when a request has been accepted for processing but is not complete. The response should point the client to a status monitor or otherwise describe how to track progress.

What should an API job status endpoint return?

Return a stable operation ID, lifecycle status, timestamps, optional progress, and a final result or structured error. A Retry-After hint can help clients choose a polling interval.

Should an async API use polling or webhooks?

Polling is simple and gives the client control. Webhooks can reduce repeated polling for long operations. Many APIs support both while keeping the operation resource as the authoritative status.

How often should clients poll a job status endpoint?

Use the server’s Retry-After guidance when provided, otherwise choose an interval based on expected duration and cost. Back off for long operations and add jitter at scale.

Should completed operation records be deleted?

They can expire, but keep them long enough for clients to retrieve terminal state and results. Document the retention period and behavior after expiry.

Primary References

Monitor the Full Lifecycle of Async API Operations

Long-running workflows span several endpoints and many requests. Runtime API visibility helps teams understand the complete operation lifecycle and detect abnormal automation.

© Ammune.ai — API security guidance for modern application environments.