202 Accepted

The request has been accepted for processing, but processing has not been completed and may not be completed.

Quick Reference

Category2xx Success
RFCRFC 9110, Section 15.3.3
CacheableNo
Processing complete?No — work is queued or in-progress
Typical useAsync jobs, message queues, background processing, long-running operations

What 202 Accepted Means

HTTP 202 Accepted tells the client that the server received and accepted the request, but processing has not finished. The server makes no commitment to complete the processing or guarantee a specific outcome. RFC 9110 explicitly notes that 202 is “intentionally non-committal.”

This code exists for asynchronous workflows where the server cannot determine the final outcome before it needs to send a response. A video transcoding service cannot wait 30 minutes for a render to complete before acknowledging the upload. An email sending service cannot wait for SMTP delivery confirmation. A batch data processing job may run for hours. In all of these cases, 202 lets the server acknowledge receipt and release the HTTP connection immediately.

The important distinction from 200 OK: 200 means processing is complete and the response body contains the result. 202 means processing has been handed off; the response body typically describes where to check for status updates, not the final result.

Async Processing Patterns with 202

Pattern 1: Status Polling

The server returns a job ID and a URL where the client can poll for status. This is the most common pattern:

POST /api/exports HTTP/1.1
Content-Type: application/json

{"format": "csv", "dateRange": "2024-01"}

HTTP/1.1 202 Accepted
Content-Type: application/json
Location: /api/exports/job_7f3a2b

{
  "jobId": "job_7f3a2b",
  "status": "queued",
  "statusUrl": "/api/exports/job_7f3a2b",
  "estimatedSeconds": 30
}

The client polls the statusUrl periodically:

GET /api/exports/job_7f3a2b

{"status": "processing", "progress": 45}

# ... later ...

{"status": "complete", "downloadUrl": "/files/export_7f3a2b.csv"}

Pattern 2: Webhook Callback

The client provides a callback URL in the request. The server calls the webhook when processing is complete:

POST /api/transcode HTTP/1.1
Content-Type: application/json

{
  "videoUrl": "s3://bucket/raw.mp4",
  "format": "hls",
  "callbackUrl": "https://app.example.com/webhooks/transcode"
}

HTTP/1.1 202 Accepted
{"jobId": "tc_9x2k", "message": "transcoding queued"}

The server sends a POST to the callback URL when done, including the job result. The client does not need to poll.

Pattern 3: Server-Sent Events

For operations where the client needs real-time progress updates, a 202 kicks off the job and a separate SSE stream (or WebSocket) delivers progress events:

// Client: start the job
const jobRes = await fetch('/api/reports/generate', { method: 'POST', body });
const { jobId } = await jobRes.json(); // 202 response

// Client: subscribe to progress
const evtSource = new EventSource(`/api/reports/${jobId}/progress`);
evtSource.onmessage = e => updateProgressBar(JSON.parse(e.data));
evtSource.addEventListener('complete', e => {
  evtSource.close();
  renderReport(JSON.parse(e.data));
});

What to Include in the 202 Response Body

RFC 9110 does not mandate any specific response body format for 202. However, a useful 202 response body includes enough information for the client to track the operation:

  • Job or request ID: a unique identifier for this specific operation
  • Status URL: where to poll for status updates (also set in the Location header)
  • Current status: typically “queued” or “accepted”
  • Estimated time: optional but helpful for setting client retry intervals

Do not return an empty body with 202 if the client has no way to find out what happened to the request. An untrackable 202 is sometimes called a “fire and forget” response — valid for truly one-way operations (send email, log event, fire analytics beacon) where the client neither needs nor has a way to check the outcome.

Framework Examples

Express.js with a Job Queue

app.post('/api/reports', async (req, res) => {
  const job = await queue.add('generate-report', {
    userId: req.user.id,
    params: req.body
  });

  res.status(202).json({
    jobId: job.id,
    status: 'queued',
    statusUrl: `/api/reports/jobs/${job.id}`
  });
});

app.get('/api/reports/jobs/:id', async (req, res) => {
  const job = await queue.getJob(req.params.id);
  const state = await job.getState(); // 'waiting', 'active', 'completed', 'failed'

  if (state === 'completed') {
    res.json({ status: 'complete', result: job.returnvalue });
  } else if (state === 'failed') {
    res.status(500).json({ status: 'failed', error: job.failedReason });
  } else {
    res.json({ status: state, progress: job.progress() });
  }
});

FastAPI with Background Tasks

from fastapi import BackgroundTasks
from fastapi.responses import JSONResponse

@app.post("/reports", status_code=202)
async def generate_report(
    params: ReportParams,
    background_tasks: BackgroundTasks
):
    job_id = str(uuid4())
    background_tasks.add_task(run_report, job_id, params)
    return JSONResponse(
        status_code=202,
        content={"jobId": job_id, "statusUrl": f"/reports/{job_id}"}
    )

202 vs Related Status Codes

CodeProcessing complete?Result available?Use when
200 OKYesYes, in bodySynchronous operation with a result
201 CreatedYesYes, new resourcePOST created a resource synchronously
202 AcceptedNoNot yetLong-running async operation; job queued
204 No ContentYesNo (intentionally)Synchronous success with no result to return

Frequently Asked Questions

Does 202 guarantee the operation will complete?

No. RFC 9110 explicitly says 202 is intentionally non-committal. The server accepted the request and may have queued it, but the operation might still fail, be rejected by a downstream system, or time out. The status polling endpoint or webhook must convey the final outcome.

Is there a standard format for the 202 response body?

No. The RFC does not define a response body structure. Each API defines its own. Common fields include a job ID, a status URL (also in the Location header), and an estimated completion time. Some APIs use established job status formats from libraries like Bull or Celery.

How long should a client wait before polling a 202 status URL?

Some APIs include a Retry-After header to suggest a wait time. Without it, the client should use exponential backoff starting from the estimated time in the response body. Polling every second for a 30-minute job wastes resources; polling every minute is usually sufficient.

Can I return 202 from a GET request?

Technically yes, but it is unusual. 202 implies the request triggered processing. GET requests are meant to retrieve data, not trigger operations. If a GET triggers a background report generation, the endpoint should probably be a POST. Using 202 on a GET is a design smell indicating the endpoint may need to be reconsidered.