SkillsMay 11, 2026·4 min read

Perplexity Async Jobs — Long Research with Webhook Callbacks

Perplexity Async Jobs API runs deep research as background. Submit query, poll or webhook for completion. For reports and multi-step synthesis.

Agent ready

Safe staging for this asset

This asset is staged first. The copied prompt tells the agent to inspect the staged files and ask before activating scripts, MCP config, or global config.

Stage only · 29/100Policy: stage
Agent surface
Any MCP/CLI agent
Kind
Skill
Install
Stage only
Trust
Trust: Community
Entrypoint
Asset
Safe staging command
npx -y tokrepo@latest install d68236aa-8206-46f2-9750-ffa80a79f847 --target codex

Stages files first; activation requires review of the staged README and plan.

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.


Quick Use

  1. POST /async/chat/completions with request body + optional webhook
  2. Poll /async/chat/completions/{id} until status=COMPLETED — or wait for webhook
  3. 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

🙏

Source & Thanks

Built by Perplexity. Async API docs at docs.perplexity.ai/api-reference/async-chat-completions-post.

REST + OpenAI-compat

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets