webcapture Get a free key

Poll an async render in Python with requests

A queue worker should not hold a connection for a render. ?wait=false returns a ticket at once, and the poll loop trades status for the finished bytes.

The ticket answers 202 with the id, the status queued, and two urls: poll for the JSON status and download for the artifact. Poll about once a second; the status walks queued, rendering, ready, and a failed render carries the error in the poll body. Both urls answer only to your key.

The recipe

import time
import requests
from pathlib import Path

ORIGIN = "https://webcapture.io"

ticket = requests.post(
    f"{ORIGIN}/v1/convert?wait=false",
    headers={"Authorization": "Bearer wc_your_key", "Content-Type": "application/json"},
    json={"url": "https://example.com/"},
    timeout=60,
)
ticket.raise_for_status()
# 202 {"id": "cnv_02b8c9d9", "status": "queued",
#      "poll": ".../v1/conversions/cnv_02b8c9d9",
#      "download": ".../v1/conversions/cnv_02b8c9d9.pdf"}
job = ticket.json()

row = job
while row["status"] in ("queued", "rendering"):
    time.sleep(1)
    row = requests.get(job["poll"], headers={"Authorization": "Bearer wc_your_key"}, timeout=60).json()
if row["status"] != "ready":
    raise RuntimeError(row.get("error") or f"render {row['status']}")

pdf = requests.get(job["download"], headers={"Authorization": "Bearer wc_your_key"}, timeout=60)
pdf.raise_for_status()
Path("page.pdf").write_bytes(pdf.content)

The loop stops on ready and treats anything else as a failure, so a worker can raise and retry without a second parser. A ready poll row adds attempts and bytes to the status, so the caller knows the document's size before it downloads.

Same-key GET: 401 without it; 404 for another key.

The fields this recipe uses

Related

Method

Source: convert field reference, checked 2026-10-05. Corrections.