25 Async Operations
title: Async Operations in REST API Design — Complete Guide weight: 35 date: 2026-06-28 lastmod: 2026-06-28 description: Design asynchronous REST API operations using 202 Accepted, status polling, webhooks, and callback URLs for long-running tasks that exceed typical request timeouts. tags: [api-development, rest]
Async operations in REST APIs handle long-running tasks by returning 202 Accepted immediately with a status polling endpoint, allowing clients to check progress without blocking on the initial request.
```mermaid
flowchart LR
A[Client] -->|POST /reports| B[Server]
B -->|202 Accepted + Location| A
A -->|GET /operations/42| C[Server]
C -->|200 + status: pending| A
A -->|GET /operations/42| D[Server]
D -->|200 + status: completed| A
A -->|GET /reports/42| E[Server]
E -->|200 + Report Data| A
style A fill:#e1f5fe
style B fill:#fff9c4
style E fill:#c8e6c9
When a client sends a request that takes too long to complete synchronously, the server accepts it (202 Accepted) and returns a Location header pointing to a status resource. The client polls this resource until the status changes to completed or failed. Alternatively, the server can call a webhook URL provided by the client.
Think of async operations like ordering a custom cake. You do not wait at the bakery (synchronous). You place the order (202 Accepted), get a pickup time (status URL), and come back later when the cake is ready (status: completed).
Example: Starting an Async Operation
import requests
# Start a long-running report generation
response = requests.post(
"https://api.example.com/reports",
json={"type": "sales_summary", "date_range": "2026-01-01..2026-06-28"}
)
print(f"Status: {response.status_code}")
status_url = response.headers.get("Location")
print(f"Poll at: {status_url}")
Expected output:
Status: 202
Poll at: /operations/op_abc123
Example: Polling the Status
import requests
import time
def poll_operation(status_url, max_retries=30, interval=2):
for attempt in range(max_retries):
response = requests.get(f"https://api.example.com{status_url}")
status = response.json()
print(f"Attempt {attempt+1}: {status['status']}")
if status['status'] == 'completed':
return status['result_url']
elif status['status'] == 'failed':
raise Exception(f"Operation failed: {status['error']}")
time.sleep(interval)
raise Exception("Operation timed out")
status_url = "/operations/op_abc123"
result_url = poll_operation(status_url)
print(f"Result at: {result_url}")
Expected output:
Attempt 1: pending
Attempt 2: processing
Attempt 3: completed
Result at: /reports/sales_summary_2026.pdf
Example: Webhook Callback Pattern
import requests
# Client provides a webhook URL
webhook_data = {
"type": "sales_summary",
"date_range": "2026-01-01..2026-06-28",
"webhook_url": "https://myapp.com/webhooks/report-complete"
}
response = requests.post(
"https://api.example.com/reports/async",
json=webhook_data
)
print(f"Status: {response.status_code}")
print(f"Operation ID: {response.json()['operation_id']}")
# Server will POST to webhook_url when done:
# POST https://myapp.com/webhooks/report-complete
# Body: {status: "completed", result_url: "/reports/op_abc123"}
Expected output:
Status: 202
Operation ID: op_abc123
Common Mistakes
- Returning 200 with a polling delay message — Use 202 Accepted for accepted operations, not 200. 200 implies the request completed.
- Not providing a status endpoint — Clients should not have to re-send the original request to check status. Provide a dedicated status URL.
- Polling with too short intervals — Clients polling every 100ms waste server resources. Recommend a minimum interval of 1-2 seconds in documentation.
- Not implementing webhook retries — Webhooks can fail. Implement retry logic with exponential backoff and a dead-letter queue.
- Missing operation timeouts — Long-running operations should have a maximum execution time. Return status: failed with a timeout reason if exceeded.
Practice Questions
- What status code should you return for an accepted async operation?
- How does a client check the progress of an async operation?
- What is the advantage of webhooks over polling?
- How do you handle webhook delivery failures?
- Challenge: Implement an async operation system in Python with a task queue, status polling endpoint, webhook callback, and operation timeout. The system should support concurrent operations and provide estimated completion times.
FAQ
Mini Project
Build an async task processing system in Python. The system should accept tasks via POST (returning 202), provide a status polling endpoint, support webhook callbacks, implement retry logic for failed webhooks, and include operation timeout. Create a CLI client that submits tasks and polls for completion.
What's Next
Now start the API design project and explore further with Building REST APIs with Node.js.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro