Documentation menu

Getting started

API reference

Guides

Trust and support

HTML to PDF

Converts an HTML document or a web page into a PDF. The request and response follow PDFShift v3.

POST https://api.sahifa.dev/v3/convert/pdf
Content-Type: application/json

Minimal request

{ "source": "<h1>Hello</h1>" }

The response body is the PDF (Content-Type: application/pdf). The header X-Response-Duration gives the render time in milliseconds.

Parameters

Source and page

NameTypeDefaultDescription
sourcestringrequiredAn http(s):// URL to load, or an HTML document. Anything that does not start with http:// or https:// is treated as HTML.
formatstringA4A0 to A6, Letter, Legal, Tabloid, Ledger, or a custom size such as 210mmx297mm or 8.5inx11in (units: px, in, cm, mm).
landscapebooleanfalseLandscape orientation.
marginstring or objectnoneCSS shorthand ("20mm", "20mm 15mm", four values) or an object with top, right, bottom, left. Plain numbers are pixels.
pagesstringallPages to keep, for example "1", "1-3" or "1,3-5".
zoomnumber1Scale of the content, from 0.1 to 2.
use_printbooleanfalseRender with the print stylesheet (@media print). Needed for table headers that repeat on every page; see tables that span pages.
disable_backgroundsbooleanfalseLeave out background colours and images.
NameTypeDefaultDescription
headerobjectnone{ "source": "<html>" } repeated at the top of every page.
footerobjectnoneSame, at the bottom of every page.

Variables replaced on every page: {{page}}, {{total}}, {{date}}, {{title}}, {{url}}.

A header or footer needs a margin. Without margin the request is refused with 400, because the header would sit on top of the content. The header and footer are drawn inside the margin, at 10 px, so give them 15 to 25 mm.

They are rendered in isolation: styles of the main document do not apply, and scripts do not run. Put the styles inline. height is accepted but the space comes from the margin. start_at is not supported.

{
  "source": "<html dir=\"rtl\">...</html>",
  "margin": { "top": "25mm", "bottom": "20mm", "left": "15mm", "right": "15mm" },
  "header": { "source": "<div style=\"width:100%;text-align:right;font-size:9px\">{{title}}</div>" },
  "footer": { "source": "<div style=\"width:100%;text-align:center\">صفحة {{page}} من {{total}}</div>" }
}

Loading and timing

NameTypeDefaultDescription
delayinteger0Extra wait after the page has loaded, in milliseconds, up to 10000.
wait_forstringnoneName of a global JavaScript function. Rendering starts once it returns a truthy value. Useful for charts and data loaded by script.
timeoutinteger30Maximum render time in seconds. Values above 30 are capped at 30.
raise_for_statusbooleanfalseFor a URL source: fail with 400 if the page answers with status 400 or higher, instead of rendering the error page.
disable_javascriptbooleanfalseDo not run scripts in the page.

Injecting code

NameTypeDefaultDescription
cssstringnoneCSS text, or a URL to a stylesheet, added after the page loads.
javascriptstringnoneJavaScript text, or a URL to a script, run after the page loads.

Access to protected pages

NameTypeDefaultDescription
authobjectnone{ "username": "...", "password": "..." } for HTTP Basic authentication of the source URL.
http_headersobjectnoneExtra request headers, for example { "Accept-Language": "ar" }.
cookiesarraynoneCookies to set: objects with name, value, and optionally domain, path, secure, http_only.

Response options

NameTypeDefaultDescription
encodebooleanfalseReturn JSON with the PDF in base64 instead of the raw file.
sandboxbooleanfalseAccepted for PDFShift compatibility, and ignored.

With encode: true the response is:

{ "success": true, "data": "JVBERi0xLjQK...", "filesize": 40356, "duration": 412 }

Not supported

filename, webhook and s3_destination are refused with 400. They require storing the file, and Sahifa never stores what it renders: the PDF is returned in the response and nowhere else.

Loading a URL

A URL source is loaded by a real browser in Jeddah. Only public http and https addresses are allowed; private, local and cloud metadata addresses are blocked, for the page and for every image, script and frame it loads.

{ "source": "https://example.com/report", "format": "A4", "margin": "15mm", "raise_for_status": true }

An HTML source has no address of its own, so relative links such as /logo.png cannot be resolved. Use absolute URLs, a <base href="https://your-site/"> tag, or embed images as data: URIs.