Guides

Async Polling

When a PDF is too large for synchronous processing or you explicitly request async mode, PDFPipe queues the job and returns a poll URL. This guide explains the flow and shows how to implement it.

When does async processing happen?

Async processing is used when either:

  • The PDF file is 10 MB or larger
  • You set "async": true in the request body
  • You use the batch endpoint (always async)

The API returns 202 Accepted instead of 200, with a pollUrl you can use to check progress.

The async flow

1. Submit the request

curl — async request
curl -X POST https://api.pdfpipe.dev/v1/convert \
  -H "Authorization: Bearer pk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/large-report.pdf",
    "format": "json",
    "async": true
  }'

2. Receive the poll URL

202 — Accepted
{
  "requestId": "req_01J9X7K2M...",
  "status": "pending",
  "pollUrl": "/v1/status/req_01J9X7K2M..."
}

3. Poll for status

Make GET requests to /v1/status/:requestId every 5 seconds. The status progresses through:

pendingprocessingcomplete
Still processing
{
  "requestId": "req_01J9X7K2M...",
  "status": "processing",
  "format": "json",
  "type": "inline",
  "createdAt": "2026-02-22T11:00:00.000Z",
  "updatedAt": "2026-02-22T11:00:02.500Z"
}
Complete — result ready
{
  "requestId": "req_01J9X7K2M...",
  "status": "complete",
  "format": "json",
  "type": "inline",
  "detectedType": "inline",
  "pagesProcessed": 48,
  "creditsUsed": 1,
  "resultUrl": "https://pdfpipe-results.s3...",
  "expiresAt": "2026-02-23T11:00:00.000Z",
  "processingDurationMs": 12450,
  "createdAt": "2026-02-22T11:00:00.000Z",
  "updatedAt": "2026-02-22T11:00:12.450Z"
}

4. Handle failures

If the status is failed, the response includes an error object with a code, message, and optional suggestion:

Failed response
{
  "requestId": "req_01J9X7K2M...",
  "status": "failed",
  "format": "json",
  "type": "inline",
  "error": {
    "code": "PROCESSING_ERROR",
    "message": "Processing failed. Please retry or contact support.",
    "suggestion": "Ensure the URL is publicly accessible and returns a valid PDF."
  },
  "createdAt": "2026-02-22T11:00:00.000Z",
  "updatedAt": "2026-02-22T11:00:08.000Z"
}

Polling best practices

  • Poll every 5 seconds. Most conversions complete within 10–30 seconds.
  • Set a timeout. Stop polling after 5 minutes (60 attempts) and treat it as a failure.
  • Check for terminal states. Stop polling when status is complete or failed.
  • Download the result promptly. The resultUrl is a presigned link that expires based on your tier (1 hour to 7 days).

Full Node.js example

Node.js / TypeScript
async function convertPdf(apiKey: string, pdfUrl: string) {
  // 1. Submit the request
  const res = await fetch("https://api.pdfpipe.dev/v1/convert", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ url: pdfUrl, format: "json", async: true }),
  });

  const data = await res.json();

  // 2. If synchronous, return immediately
  if (res.status === 200 && data.resultUrl) {
    return data;
  }

  // 3. Poll until complete or failed
  const pollUrl = `https://api.pdfpipe.dev/v1/status/${data.requestId}`;
  const maxAttempts = 60;

  for (let i = 0; i < maxAttempts; i++) {
    await new Promise(r => setTimeout(r, 5000));

    const poll = await fetch(pollUrl, {
      headers: { "Authorization": `Bearer ${apiKey}` },
    });
    const status = await poll.json();

    if (status.status === "complete") return status;
    if (status.status === "failed") throw new Error(status.error.message);
  }

  throw new Error("Polling timed out");
}