Documentation

Getting started

Three steps and about four minutes: create a key, POST a URL, keep the file. Everything else is optional.

01 / AUTHENTICATION

Two keys, different jobs

Your access key identifies the project and can be public. Your secret key signs requests and must stay on your server. Server-side calls use a bearer token; browser calls use a signature.

export URLTODOC_KEY="sk_live_A7f9K2mQ8zL4pX6n" # every request is authenticated with a bearer token curl https://urltodoc.com/api/account \ -H "Authorization: Bearer $URLTODOC_KEY"

02 / FIRST RENDER

POST a URL, get a PDF

The response body is the file. Content-Type tells you what it is; the X-Credits-Remaining header tells you what it cost.

curl -X POST https://urltodoc.com/api/render \ -H "Authorization: Bearer $URLTODOC_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "format": "A4" }' \ --output example.pdf # HTTP/2 200 # content-type: application/pdf # x-credits-remaining: 99 # x-render-ms: 1180

Tip

If your page builds content after load, add wait_for with a selector that only exists once the page is done. It is the single option that prevents most surprises.

03 / STORAGE

Let us keep the file

With store: true the response is JSON instead of bytes: a CDN URL, a checksum, a page count and an expiry. Set retention to control how long it lives.

{ "id": "rnd_9fK2mQ8zL4", "url": "https://files.urltodoc.com/r/9fK2mQ8zL4.pdf", "checksum": "sha256:1f0c…a92b", "pages": 3, "bytes": 148221, "expires_at": "2026-08-06T09:14:22Z", "credits_spent": 1 }

04 / ASYNC

Long jobs, without holding the connection

Add async: true and a callback_url. You get a job id immediately and a signed webhook when the render finishes. Verify the signature header before trusting the payload.

// POST /api/render → 202 Accepted { "id": "job_9fK2mQ", "status": "queued" } // later, to your callback_url // x-urltodoc-signature: t=1785…,v1=8a08e62d… { "id": "job_9fK2mQ", "status": "succeeded", "url": "https://files.urltodoc.com/r/9fK2mQ8zL4.pdf", "pages": 92, "render_ms": 8420 }

05 / ERRORS

When a render fails

Failures return a machine-readable code and a sentence you can log. None of them spend a credit.

400 invalid_options A field is missing or the wrong type. The message names the field.
401 bad_credentials Unknown key, or a signature that does not match the options.
402 no_credits Out of credits and a hard ceiling is set on the project.
422 target_unreachable The page returned a non-2xx status, timed out, or refused the connection.
422 wait_condition_failed The selector or event in wait_for never appeared within the timeout.
429 rate_limited Too many concurrent renders for the plan. Retry after the header says so.
500 render_failed The page crashed the renderer. Logged on our side; not charged, and worth telling us about.

Rate limits are per project and returned in X-RateLimit-* headers. Retry 429 and 5xx with exponential backoff; the SDKs do it for you.

SDKS

Official libraries

Typed options, retries and signed-URL helpers. All five wrap the same endpoint, so the docs read the same in every language.

Node.js

npm i urltodoc

Python

pip install urltodoc

PHP

composer require urltodoc/sdk

Go

go get github.com/urltodoc/go

Ruby

gem install urltodoc

Something else

It is one POST with JSON. Ask us and we will write the snippet.