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

This asset can be read and installed directly by agents

TokRepo exposes a universal CLI command, install contract, metadata JSON, adapter-aware plan, and raw content links so agents can judge fit, risk, and next actions.

Stage only · 17/100Stage only
Agent surface
Any MCP/CLI agent
Kind
Skill
Install
Stage only
Trust
Trust: New
Entrypoint
Asset
Universal CLI install command
npx tokrepo install d68236aa-8206-46f2-9750-ffa80a79f847
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.