Perplexity Async Requests

Every other provider’s batch endpoint is a discount you buy with patience. Perplexity’s asynchronous path is something else entirely: the only way to hold a reference to work that will outlive any connection you can keep open.

13 min read
Staff Pick

📡 Monitor your APIs — know when they go down before your users do

Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.

Start Free →

Affiliate link — we may earn a commission at no extra cost to you

If you came looking for a Perplexity batch API in the shape you know from other providers — upload a file of a thousand requests, wait some hours, collect the results at half price — the honest answer is that the motivation here is different. Perplexity’s asynchronous path is not primarily a cost mechanism. It exists because its research-grade models do work that takes far longer than any reasonable client will wait, and a request that runs for many minutes cannot survive a normal HTTP round trip.

That distinction changes what you build. With a discount-driven batch API, the failure you are guarding against is silent row loss inside a large file. Here, the failure you are guarding against is a job that is still running while everything holding a reference to it has already given up: a load balancer that closed the socket, a serverless function that hit its ceiling, a deploy that rolled the process waiting on the response. The work continues. The bill continues. Only your handle on it is gone.

You still batch, of course — you submit many async jobs and manage the set. But the set lives in your database, not in a file on the provider’s side, which means the bookkeeping that other providers do for you is now yours.

Why the Synchronous Call Fails First

It is worth being precise about what breaks, because the symptom is easy to misread as a Perplexity outage when it is nothing of the sort.

A long-running research request has to survive every timeout between your code and the model: the HTTP client’s default read timeout, your reverse proxy’s idle timeout, a cloud load balancer’s connection limit, a serverless platform’s hard execution ceiling, and any API gateway in between. The shortest of those wins. Whichever one fires, your side sees a dropped connection or a client-side timeout — and the provider sees a request that is proceeding normally.

So you retry. The original job is still running and still billing. The retry starts a second identical piece of expensive work. Repeat that under load and you have built a system whose cost scales with your timeout misconfiguration, while your error dashboard shows a provider problem. The async path fixes this by giving you a durable identifier instead of a fragile socket, and it is the correct answer even when the discount other providers dangle is not on offer.

What the Async Contract Actually Promises

PropertyWhat you actually getWhat that forces you to build
DurabilityA job id that survives your process, not a held connectionPersist the id transactionally at submit, before anything else can crash
DurationNo bound you can quote, and wide variance by model and questionPoll on a schedule; surface job state to users instead of a spinner
CompletionA terminal state, which may be failure as easily as successBranch on the terminal state; never treat “done” as “answered”
RetentionResults readable for a limited window measured in daysFetch and persist immediately; alert on unfetched completed jobs
FreshnessAn answer grounded in the web as it was when the job ranStore the completion timestamp with the answer and revalidate before reuse
CostBilled for work performed, whether or not you collected itReconcile submitted jobs against fetched results; orphans are pure waste

Notice how many of those rows are about your bookkeeping rather than the provider’s behaviour. That is the trade you accept when the batch unit is a job you track rather than a file the provider tracks for you.

The Lifecycle, and Where Each Stage Drops Work

Submit. You post the request to the async endpoint and receive a job id. The failure is losing it — the process crashes, or the create succeeds but the response never arrives — and now an expensive research job is running that nothing is waiting for. Write the id to durable storage in the same transaction that records the intent, and store the request alongside it so you know what this job owed you.

Wait. The job runs somewhere you cannot see, for a duration you cannot predict. The failure is treating this as bounded: blocking a user request on it, or abandoning and re-submitting a job that was merely thorough, which doubles the cost of the most expensive call in your stack. Poll on a schedule, sweep your non-terminal jobs, and advance state from the authoritative job object rather than from any push you may or may not receive.

Retrieve. The job reaches a terminal state and you fetch the result. This stage has its own clock: the output is retained for a limited window, and a completed job that is never fetched becomes money spent on an answer you cannot read. Fetch on completion, persist into your own store, and alert when a completed job has sat unfetched for a meaningful fraction of the retention window.

Reconcile. Compare the set of jobs you submitted against the set whose results you actually hold. The difference is your loss: jobs that failed terminally, jobs orphaned by a crash between submit and persist, jobs whose results expired. Route each to a retry, a dead-letter table, or a human. Without this step, the failure mode is not an outage — it is a slow, invisible leak of expensive work.

The Perplexity-Specific Trap: A Correct Answer Can Still Be Stale

Batch guides for other providers can stop at completeness: did every row come back? With Perplexity there is a second question that no status field answers, because the model is grounded in live retrieval rather than weights alone.

An async job encodes the web as it existed while the job was running. Submit a research query, let it run through a long window, read the result the next morning, and you are holding a snapshot with three different timestamps — when you asked, when it looked, and when you read — none of which your code probably records. If the job straddled a product launch, an earnings release or a news cycle, the answer is confidently, silently out of date. The job status says completed, because it did complete.

Citations decay faster than claims. A source URL that resolved when the job ran can be moved, paywalled or deleted by the time a user clicks it, which makes the answer look fabricated when it was accurate at retrieval time. Treat citation validity as a separate check with its own schedule, keep the completion timestamp attached to every stored answer, and set an explicit staleness policy per query class rather than assuming a research output is durable. See the response caching guide for how the same problem shows up when you reuse grounded answers.

Six Failures, and What They Return

FailureWhat your code seesDetection
Job id lost between submit and persistNothing. No row, no error, a running bill.Periodic list of provider-side jobs vs your own table
Synchronous retry of a still-running jobA client timeout, then a second successJobs-per-logical-request count above one
Result expired before retrievalA 404 on a job you know completedTime from terminal state to fetch, alerted under the retention window
Answer grounded in a stale snapshotSuccess. A confident, out-of-date answer.Completion timestamp stored with the answer; per-class staleness policy
Citations rotted after completionSuccess. Links that 404 for the user.Scheduled revalidation of stored citation URLs
Queue stalled by a provider incidentSuccess. Jobs simply stay non-terminal.Oldest non-terminal job age vs observed distribution; external probe

Four of these six return success to the code watching them. That is the structural problem with asynchronous work: your instrumentation observes a process that is waiting, and waiting looks the same whether the other side is working, stalled, or finished with an answer you will never collect.

What to Instrument

Five numbers make the async path legible: the age of your oldest non-terminal job against the distribution you have observed for that model; the count of submitted jobs with no persisted result, which is your leak; time from terminal state to fetch, measured against the retention window; jobs per logical request, which catches duplicate submissions from timeout-driven retries; and the age of the completion timestamp on any answer you are about to reuse. The first four protect the bill. The fifth protects the user from a correct answer about a world that has moved on.

None of them can tell you whether api.perplexity.ai was degraded while your jobs sat quiet, because a client that is polling and being told “not yet” emits no errors and no meaningful latency. That is the gap an independent probe closes.

Frequently Asked Questions

Does Perplexity have a batch API like OpenAI or Mistral?

Not in the same shape, and the difference matters more than the naming. Providers whose batch endpoints exist to sell a discount take a file of many requests and trade latency for a lower per-token price. Perplexity’s asynchronous path exists for a different reason: its research-grade models can run far longer than any sensible HTTP client or gateway will hold a connection open, so you submit a request, get a job identifier, and collect the answer later. You batch by submitting many async jobs and managing the set yourself, rather than by uploading one file. The operational problems are the same; the motivation is duration, not price.

Why can’t I just call the synchronous endpoint and wait?

Because something in the path between you and the model will give up first, and it will not be Perplexity. A deep research query that runs for many minutes exceeds default timeouts in load balancers, serverless function limits, reverse proxies and most HTTP client libraries. What you experience is a dropped connection while the work continues on the provider side, so you are billed for a job whose answer you never received and you retry, paying twice. The async path replaces a socket you cannot keep alive with a job id you can look up, which is the only durable way to hold a reference to work that outlives a request.

How long does a Perplexity async job take?

It varies enormously by model and question, and that variance is the reason the async path exists rather than a defect in it. A grounded lookup may return quickly; a research job that plans, searches and reads across many sources can run for a long stretch with no partial output to observe. Do not build anything that assumes a bound. Poll on a schedule, store the job in your own database at submission, and let completion be an event that arrives whenever it arrives. If a user is watching, show them the job state rather than a spinner you will eventually have to abandon.

How long are Perplexity async results available to fetch?

For a limited retention window measured in days, not forever, which turns retrieval into a step with its own deadline. A job that completed and was never fetched becomes a job you paid for and cannot read, and the failure surfaces as a 404 on an id you know succeeded. Persist the result into your own storage as soon as the job reaches a terminal state, treat time-from-completion-to-fetch as a metric worth alerting on well before the retention limit, and never design a system where the provider is the archive of record for an expensive research output.

Should I poll for the job or wait for a webhook?

Poll, and treat any push notification as an accelerator rather than the source of truth. A scheduled sweep that lists your non-terminal jobs and asks for their current state is the only mechanism that still works when a callback is dropped, when your receiver was mid-deploy at the moment of delivery, or when the job was submitted by a different process than the one now waiting for it. Build the poll first and make it idempotent, so it is the thing that actually advances a job to done in your database. A push, where available, just means the poll finds the answer sooner.

A Perplexity async job completed but the answer looks wrong. What failed?

Probably nothing that has an error code. Perplexity answers are grounded in live retrieval, so a completed job encodes the web as it appeared at the moment the job ran, not when you submitted it and certainly not when you read it. A long-running research job can straddle a news cycle. Citations can point at pages that have since changed or disappeared. None of that produces a failure status: the job succeeded, the content is simply stale or thinly sourced. Store the completion timestamp with the answer, treat citation validity as a separate check, and revalidate anything you will show a user later.

How do I tell a stuck async job from a slow one?

From inside your own application you often cannot, because a job queued behind a provider incident and a job that is merely doing a lot of work look identical: no error, no latency metric moving, a state that is simply not terminal yet. The workable signal is the age of your oldest non-terminal job against the distribution you have observed for that model. When the oldest job passes well beyond the tail of that distribution, treat it as stuck and fail the time-sensitive portion over. External monitoring of api.perplexity.ai is what separates a provider-side incident from a genuinely deep queue, since a waiting client produces no telemetry of its own.

Related Guides

A Queue That Stops Draining Raises No Errors

When the async path degrades, your telemetry goes quiet rather than red — jobs simply never reach a terminal state. API Status Check probes api.perplexity.ai independently and alerts on errors and latency, so you hear it from a monitor instead of from a customer asking where their report went.

Start Your Free Trial →

🛠 Tools We Use & Recommend

Tested across our own infrastructure monitoring 200+ APIs daily

Better StackBest for API Teams

Uptime Monitoring & Incident Management

Used by 100,000+ websites

Monitors your APIs every 30 seconds. Instant alerts via Slack, email, SMS, and phone calls when something goes down.

We use Better Stack to monitor every API on this site. It caught 23 outages last month before users reported them.

Free tier · Paid from $24/moStart Free Monitoring
1PasswordBest for Credential Security

Secrets Management & Developer Security

Trusted by 150,000+ businesses

Manage API keys, database passwords, and service tokens with CLI integration and automatic rotation.

After covering dozens of outages caused by leaked credentials, we recommend every team use a secrets manager.

SEMrushBest for SEO

SEO & Site Performance Monitoring

Used by 10M+ marketers

Track your site health, uptime, search rankings, and competitor movements from one dashboard.

We use SEMrush to track how our API status pages rank and catch site health issues early.

From $129.95/moTry SEMrush Free
View full comparison & more tools →Affiliate links — we earn a commission at no extra cost to you