PDFShot

REST API

Generate, fetch, share, and delete PDFs via HTTPS. Same auth as the rest of DeepSyte — Bearer token from your dashboard.

Base URL

https://api.deepsyte.com

The API is hosted on Railway. Webhooks and SSE streams are served from the same origin, so you only need to allowlist one host.

Authentication

All endpoints (except the public share viewers) require a Bearer token in the Authorization header:

curl https://api.deepsyte.com/v1/screenshot/<id> \
  -H "Authorization: Bearer $DEEPSYTE_KEY"

Generate a key from the DeepSyte dashboard → API keys — one account, one set of keys works for PDFShot and every other DeepSyte product.

Generate a PDF

POST /v1/screenshot
Content-Type: application/json
Authorization: Bearer <key>

{
  "url": "https://example.com",
  "pdf": true,
  "fullPage": true,
  "width": 1280,
  "height": 800,
  "delay": 0
}

Returns immediately with a screenshotId and a status: "pending". The worker generates the PDF in the background; track it via polling, SSE, or webhooks.

Tunable params

ParamDefaultNotes
urlrequiredHTTP/HTTPS only.
pdffalseSet true for PDF, false for PNG/JPEG.
fullPagefalseScrolls before capture to trigger lazy content.
width1280Viewport width before render.
height800Viewport height before render.
delay0Extra ms to wait after page load. Useful for SPAs.
darkModefalseSends prefers-color-scheme: dark.

Check status

GET /v1/screenshot/<id>
Authorization: Bearer <key>

Response:

{
  "id": "wJqTW...",
  "url": "https://example.com",
  "status": "done",
  "publicUrl": "https://pub-...r2.dev/screenshots/<id>.pdf",
  "thumbnailUrl": "https://pub-...r2.dev/screenshots/<id>.thumb.png",
  "pageTitle": "Example Domain",
  "tags": ["other"],
  "width": 1280,
  "height": 1024,
  "createdAt": "2026-05-28T03:42:00.000Z",
  "completedAt": "2026-05-28T03:42:09.211Z"
}

Stream completion (SSE)

For UIs that want a live spinner without polling:

const es = new EventSource(
  `https://api.deepsyte.com/v1/screenshot/${id}/stream`,
);
es.addEventListener("status", (event) => {
  const { status } = JSON.parse(event.data);
  // "pending" → "processing" → "done" | "failed"
});
es.addEventListener("done", (event) => {
  const { publicUrl } = JSON.parse(event.data);
  es.close();
});

The stream sends : ping heartbeats every 15 seconds and times out after 5 minutes with a timeout event.

Share a PDF

POST   /api/screenshots/<id>/share      # mint
DELETE /api/screenshots/<id>/share      # revoke

See Sharing for the full response shape.

List your PDFs

GET /v1/screenshots?limit=50&before=<iso>
Authorization: Bearer <key>

Cursor-paginated. nextCursor is null on the last page.

Download with attachment headers

The dashboard's Download button hits the apex Next.js route /api/pdf/download/<id> which proxies R2 and adds Content-Disposition: attachment so browsers save instead of opening inline. Use it client-side instead of linking to the raw R2 URL.

On this page