HTTP status code · Success (2xx)
202 Accepted
202 Accepted means the server has accepted the request for processing but has not finished it, and the work may still fail later. It is the right answer when you queue a job, such as a video transcode or a large export, and return before the work is done.
| Class | 2xx, Success |
|---|---|
| Defined in | RFC 9110 §15.3.3 |
| Cacheable by default | Only with explicit Cache-Control or Expires |
| Safe to retry | Do not resubmit; poll the status URL instead |
| Relevant headers |
|
What 202 means
RFC 9110, section 15.3.3, calls 202 intentionally noncommittal. HTTP has no way to send a second status later for the same request, so the response ought to describe the current state and point to a status monitor where the client can follow progress.
A common shape: POST /exports returns 202 with Location: /exports/jobs/7f3a. GET on that job returns 200 with {"status": "running"} while it works, then a link to the finished file, or a 303 See Other to it. Many APIs also add Retry-After to suggest a polling interval; that is a convention, since RFC 9110 defines Retry-After only for 503, 429 and redirects.
When to use it
- Work that outlives a sensible request timeout: media processing, bulk imports, report generation, sending a batch of emails.
- Webhook receivers that store the event and process it later; most webhook senders only need any 2xx quickly.
Common causes
If you run the server
- The client treats 202 as "done" and shows success, then the background job fails and nobody is told.
- There is no status resource, so the client resubmits the job to find out what happened and creates duplicates.
How to fix it
If you run the server
- Always return a job URL (Location header or a link in the body) whose status moves through queued, running, succeeded or failed.
- For long jobs, offer a callback URL or webhook so clients do not need to poll at all.
How to send 202
app.post('/exports', (req, res) => {
res.set('Location', '/exports/jobs/7f3a');
res.status(202).json({ status: 'queued', statusUrl: '/exports/jobs/7f3a' });
});// app/exports/route.ts
export async function POST() {
return Response.json(
{ status: 'queued', statusUrl: '/exports/jobs/7f3a' },
{ status: 202, headers: { 'Location': '/exports/jobs/7f3a' } }
);
}mux.HandleFunc("POST /exports", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", "/exports/jobs/7f3a")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted) // 202
w.Write([]byte(`{"status":"queued","statusUrl":"/exports/jobs/7f3a"}`))
})from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/exports")
def start_export():
return JSONResponse(status_code=202, content={"status": "queued", "statusUrl": "/exports/jobs/7f3a"}, headers={"Location": "/exports/jobs/7f3a"})Commonly confused with
- 202 vs 201
- 201 Created says the resource exists now; 202 only promises the work was accepted and may complete, or fail, later.
- 202 vs 204
- 204 means the action is complete and there is nothing to return; 202 means it is not complete yet.
Frequently asked questions
- Does 202 Accepted mean the request succeeded?
- Only that it was accepted. RFC 9110 says the request might or might not eventually be acted upon, so the real outcome has to be checked later through a status resource or callback.
- How does the client learn the result of a 202?
- Through a URL the server hands back, usually in the Location header or the body. The client polls it until the job reports success or failure, or the server calls a webhook when it is done.
- Should a webhook endpoint return 200 or 202?
- Either works for most senders, which only look for any 2xx. 202 is the more precise answer when you store the event and process it asynchronously.
Last reviewed by Arielton Oberek.