Quick Use
- POST
/async/chat/completionswith request body + optional webhook - Poll
/async/chat/completions/{id}until status=COMPLETED — or wait for webhook - Verify webhook HMAC-SHA256 signature before processing
Intro
Perplexity's Async Jobs API submits long-running research as a background job rather than blocking a request — perfect for sonar-deep-research queries that take minutes and would otherwise time out a normal HTTP connection. Poll the status endpoint or register a webhook for completion. Best for: research reports, market analyses, multi-source comparisons, anywhere you'd rather email/notify than block. Works with: REST, Python httpx, JS fetch. Setup time: 10 minutes.
Submit a deep research job
import httpx, os
headers = {"Authorization": f"Bearer {os.environ['PPLX_API_KEY']}"}
job = httpx.post(
"https://api.perplexity.ai/async/chat/completions",
headers=headers,
json={
"request": {
"model": "sonar-deep-research",
"messages": [{"role": "user", "content": "Comprehensive 2026 state of voice AI agents: top platforms, latency benchmarks, pricing, target use cases. 1500 words."}],
"search_domain_filter": ["livekit.io", "vapi.ai", "retellai.com", "elevenlabs.io", "techcrunch.com", "a16z.com"],
},
},
).json()
print(job["id"], job["status"]) # status: "QUEUED"Poll for completion
import time
while True:
r = httpx.get(f"https://api.perplexity.ai/async/chat/completions/{job['id']}", headers=headers).json()
if r["status"] == "COMPLETED":
print(r["response"]["choices"][0]["message"]["content"])
print("Citations:", r["response"]["citations"])
break
elif r["status"] == "FAILED":
raise RuntimeError(r.get("failed_reason"))
time.sleep(5)Webhook completion (preferred for prod)
job = httpx.post(
"https://api.perplexity.ai/async/chat/completions",
headers=headers,
json={
"request": {...},
"webhook": {"url": "https://your-app.com/perplexity/done", "secret": "shared-signing-secret"},
},
).json()
# Resulting POST to your endpoint:
# { "job_id": "...", "status": "COMPLETED", "response": {...} }
# Verify HMAC-SHA256(body, secret) against X-Perplexity-Signature header.Status lifecycle
| Status | Meaning |
|---|---|
| QUEUED | Accepted, awaiting worker |
| IN_PROGRESS | Worker started; searching + drafting |
| COMPLETED | Done; response field populated |
| FAILED | Error; check failed_reason |
When to use Async over sync
- Deep-research model with >30s expected duration → Async (sync hits 60s timeout)
- Background batch jobs (overnight reports) → Async
- User clicks 'Generate report' button and walks away → Async + webhook → email
- Real-time chat → sync sonar/sonar-pro
FAQ
Q: How long can a job run? A: Up to 30 minutes for deep-research. Most finish in 1-5 min. Webhook is mandatory above ~5 min unless you can keep a poll loop alive — most platforms can't reliably.
Q: What if my webhook is down when the job completes? A: Perplexity retries with exponential backoff for up to ~24 hours. After that the result stays retrievable via GET on the job ID for 7 days. Build idempotency: store job_id, dedupe on retry.
Q: Can I cancel an in-flight job? A: Yes — DELETE on the job endpoint. Useful when a user navigates away from a research request. No partial result is returned; charges depend on what was already searched.
Source & Thanks
Built by Perplexity. Async API docs at docs.perplexity.ai/api-reference/async-chat-completions-post.
REST + OpenAI-compat