webcapture Get a free key

Migrate from PDFShift in one line

Change two values, keep the body: aim POST /v3/convert/pdf (or png, jpeg, webp) at this API and swap the API key. Three contract details differ, one sentence each: on the pdf path the body's format names the paper size (A4, A3, Letter, Legal, A5), never the output format; the response is raw bytes, not a JSON envelope carrying a download URL; and timeout clamps to a 60,000ms ceiling where their paid plans wait up to 100 seconds.

The whole migration is two values

Same POST, same JSON body, same X-API-Key header. Their call:

curl -X POST \
  https://api.pdfshift.io/v3/convert/pdf \
  -H "X-API-Key: sk_your_pdfshift_key" \
  -H "Content-Type: application/json" \
  -d '{"source": "https://example.com", "format": "A4", "margin": "10mm", "quality": 90, "timeout": 30}'

This API's:

curl -X POST \
  https://webcapture.io/v3/convert/pdf \
  -H "X-API-Key: wc_your_webcapture_key" \
  -H "Content-Type: application/json" \
  -d '{"source": "https://example.com", "format": "A4", "margin": "10mm", "quality": 90, "timeout": 30}'

The two bodies are byte-identical; only the host and the key move. Run the second call with -o page.pdf, because there is no URL to fetch afterward: the response body is the document itself, with its content type, and x-credits-cost, x-credits-used, and x-credits-remaining headers beside it.

Already holding an HTML string? Keep it in source: {"source": "<html><body><h1>Invoice 42</h1></body></html>"} renders directly. Raw HTML cannot carry http_headers, cookies or auth on this shim; use the native /v1 html and baseUrl fields when relative assets or origin-pinned fetch controls are needed.

The 40 parameters, mapped

Three columns: their parameter, what it becomes on this endpoint, and the status. The rows are generated from the shim's own source, the code that actually decides, so the table cannot promise a mapping that is not performed.

What maps (31)

pdfshift parameterwhat it becomes herestatus
sourcesource, required: the page URL or a pasted HTML document. Raw HTML renders directly; combining it with http_headers, cookies or auth answers 422 because the shim has no base-url parameter to pin them safelymapped, url or raw html
formaton the pdf path, the page size: A4, A3, Letter, Legal, A5. On image paths the path segment already carries the output format, so it is ignoredsupported as the PDF page size
landscapelandscape: true prints the page rotatedmapped
marginmargin: a number with an optional mm, cm, in or px unit, 100 or less; present on an image path it answers 400 instead of applyingmapped, pdf only
qualityquality: an integer from 1 to 100mapped
delaysettle: milliseconds to wait after load before capture, ceiling 10,000mssupported as settle
timeoutthe request's render budget in milliseconds, converted from seconds and clamped to a 60,000ms ceilingsupported as the render budget
watermarkthe pdfshift object's text becomes our watermark string: a centered text stamp on the rendered pdf (Helvetica-Bold 48pt, 0.15 opacity, 45deg); other watermark options refuse with a 422mapped, pdf only
metadatametadata: an object with title, author, subject and keywords, riding the same shape and caps as /v1/convertmapped, pdf only
protectionprotection: the user and owner passwords become encryption's userPassword and ownerPassword; permission flags refuse with a 422mapped as encryption
http_headerscustom request headers with the source fetch: an object of header name and value strings, at most 20 headers, riding /v1's admission rules (a cookie header refuses, and so do host and content-length)mapped
cookiescookies: an array of name and value entries pinned to the source URL's hostname (an entry whose domain differs answers 400, and attributes beyond domain are ignored), at most 20, and the cookie jar never survives the rendermapped, host-pinned
authbasic auth credentials (username and password) sent with the source fetch over the browser's own credential channelmapped
is_hipaaphi: the zero-residue render mode. The source url is never stored, the artifact is deleted on first download, and the render is audit-noted without the url; requires an executed BAA on the account, and a request from an account without one answers 403mapped as phi, BAA-gated
csscss: an inline stylesheet string of 1 to 20,000 characters injected into the page after load, before the capture; url and object forms answer 400 instead of fetching a caller urlmapped
javascriptjavascript: an inline script string of 1 to 20,000 characters run in the page after load, before the capture; url and object forms answer 400 the same way. A disable_javascript body alongside it answers 422mapped
use_printusePrint: emulate print media before the capture, so print-keyed media queries apply the way the printed page sees themmapped as usePrint
disable_javascriptdisableJavaScript: render with the page's JavaScript off at the browser context; it cannot combine with javascript (the pairing answers 422)mapped as disableJavaScript
disable_backgroundsdisableBackgrounds: pdf output prints without page backgrounds when true; unset keeps themmapped as disableBackgrounds
wait_forwaitFor: a CSS selector of 1 to 500 characters the render waits to see before the capture, capped by the same settle ceiling as delay. pdfshift's function-name form is NOT replicated: a string naming a function never matches a selector, and the render fails like any page error when the wait budget endsmapped as waitFor
zoomscale: a number from 0.1 to 2 applied as the render's scalemapped as scale
filenamefilename: stored with the render and used as the download's file name, 1 to 100 characters of letters, digits, dot, dash or underscoremapped
wait_for_networkwaitForNetwork: hold navigation until the network has been quiet (a networkidle window) instead of capturing at the load event, so pages that keep fetching settle before the capturemapped as waitForNetwork
ignore_long_pollingaccepted for parity: it maps onto the same waitForNetwork wait, because that wait's quiet window already ignores long polls; there is no second switch to setmapped onto waitForNetwork
lazy_load_imageslazyLoadImages: keep waiting after load until images finish (loaded or failed), before any capture on every format, on a min(settle, 10 seconds) budget; a budget that runs out fails the render instead of shipping a half-loaded capturemapped as lazyLoadImages
raise_for_statusraiseForStatus: a source that answers an http 400+ status fails the render with that status instead of printing the error page, and the failure is terminal, never retriedmapped as raiseForStatus
remove_blankremoveBlank: pdf pages with no marking operators (no text, path, shading or image marks) are dropped after render, before stamping; an all-blank document keeps its original pages and the count removed is never echoedmapped, pdf only
clipclip: an object with x, y, width and height (non-negative integers, width and height of at least 1) cropping the screenshot to that page region; requires fullPage, the default, and it cannot combine with css_selectormapped, image paths only
css_selectorcssSelector: a css selector of 1 to 500 characters whose matched element is captured instead of the page; it cannot combine with clip, and the capture waits for the element within the render's own wait budgetmapped as cssSelector, image paths only
dpidpi: output density from 1 to 4 applied as the browser's device scale factor, so page and element captures come out at the requested density; pdf points are dpi-independent, so the pairing refusesmapped, image paths only
transparenttransparent: true prints png and webp screenshots without the default white background; jpeg has no alpha channel and the pairing refusesmapped, png and webp only

What refuses (9)

Present in a body, these answer a 422 whose error names every offending parameter at once; nothing is dropped silently. Anything outside both lists is ignored silently, matching pdfshift's own tolerance for unknown fields, so a drop-in caller never hard-stops on a harmless extra.

pdfshift parameterwhat it would take herestatus
sandboxno test mode; the free tier is the dry runnot supported
encodeno base64 mode; the bytes arrive rawnot supported
s3_destinationuse a presigned PUT URL as destination insteadnot supported
webhookrenders are synchronous; the bytes are the responsenot supported
is_gdprno GDPR-only processing modenot supported
log_requestno per-request logs here; usage lives in the dashboardnot supported
headerno running headers; margins are the only page furniture herenot supported
footerno running footers; margins are the only page furniture herenot supported
encryptionuse protection with a userPassword insteadnot supported

Timeout, said plainly

pdfshift's timeout counts seconds: their spec allows up to 300, and paid plans wait up to 100 seconds (re-checked 2026-10-03). This endpoint clamps the converted ask to 60,000ms, and the value behaves as a ceiling on the job budget, not a timer you set: a caller asking for timeout: 5 waits up to this endpoint's budget, not five seconds. The ceiling caps the wait; the job budget decides the actual bound.

Clamped values are not surfaced in the response: raw bytes leave no channel for notes, so send timeout at or under 60 and delay at or under 10000 rather than relying on the clamp.

Everything else in the envelope

Errors keep their shape: {"success": false, "error": "...", "code": ...}. A malformed value is a 400; a capability refusal, an unsupported parameter or raw HTML combined with fetch controls, is a 422 naming itself; out of credits is 403 with the quota numbers in an errors object, and a phi request (is_hipaa) from an account without an executed BAA is 403 too; a render past the budget is 408; a failed render is 502. Authentication takes their X-API-Key header, and a Bearer header works too, so one credential can serve both surfaces.

Where this fits

The money side, one render per document against their credit-per-5Mb model, is on webcapture vs PDFShift. The native API this shim fronts, with its own contract and Markdown output, is in the docs; the product page keeps engine, prices, and quick start together.

Method

Checked 2026-10-05. The mapping table is generated from this API's shim source: the exported refusal list and the mapping function beside it, so the columns describe the code that runs, not a spec retype. The PDFShift side of the table comes from pdfshift.io's OpenAPI spec and live docs. Questions or corrections: hello@webcapture.io.

Render your first page in seconds

Mint a key, POST a URL, and the finished document comes back in the same response; pass ?wait=false for a job ticket with poll and download URLs. The first 50 renders a month are free, and there is no credit card. Not ready for a key? The free URL to PDF tool renders public pages without one.