webcapture Get a free key

Save the PDF to a file in Python with requests

The receipt states the document's size in bytes. Stream the download in chunks, count what arrived, and refuse to call the file finished until the two agree.

For documents big enough that you would rather not hold them twice in memory, stream the download with stream=True and iter_content, extend a bytearray, and write once at the end. The receipt's bytes field is the truth the write is checked against; a short download raises instead of passing.

The recipe

import requests
from pathlib import Path

ORIGIN = "https://webcapture.io"

receipt = requests.post(
    f"{ORIGIN}/v1/convert",
    headers={"Authorization": "Bearer wc_your_key", "Content-Type": "application/json"},
    json={"url": "https://example.com/"},
    timeout=60,
).json()

# the download url names /v1/conversions/<id>.pdf at the serving origin
chunks = bytearray()
with requests.get(
    receipt["download"],
    headers={"Authorization": "Bearer wc_your_key"},
    stream=True,
    timeout=60,
) as res:
    res.raise_for_status()
    for chunk in res.iter_content(chunk_size=65536):
        chunks.extend(chunk)

if len(chunks) != receipt["bytes"]:
    raise RuntimeError(f"short download: {len(chunks)} of {receipt['bytes']} bytes")
Path("whitepaper.pdf").write_bytes(chunks)

The size check is the point of the recipe: the endpoint tells you exactly how many bytes the render produced, so a proxy that truncates the transfer or a disk that fills mid-write becomes a loud error instead of a corrupt pdf.

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.