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
| Name | Type | Default | Description |
|---|---|---|---|
source | string | required | An http(s):// URL to load, or an HTML document. Anything that does not start with http:// or https:// is treated as HTML. |
format | string | A4 | A0 to A6, Letter, Legal, Tabloid, Ledger, or a custom size such as 210mmx297mm or 8.5inx11in (units: px, in, cm, mm). |
landscape | boolean | false | Landscape orientation. |
margin | string or object | none | CSS shorthand ("20mm", "20mm 15mm", four values) or an object with top, right, bottom, left. Plain numbers are pixels. |
pages | string | all | Pages to keep, for example "1", "1-3" or "1,3-5". |
zoom | number | 1 | Scale of the content, from 0.1 to 2. |
use_print | boolean | false | Render with the print stylesheet (@media print). Needed for table headers that repeat on every page; see tables that span pages. |
disable_backgrounds | boolean | false | Leave out background colours and images. |
Header and footer
| Name | Type | Default | Description |
|---|---|---|---|
header | object | none | { "source": "<html>" } repeated at the top of every page. |
footer | object | none | Same, 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
| Name | Type | Default | Description |
|---|---|---|---|
delay | integer | 0 | Extra wait after the page has loaded, in milliseconds, up to 10000. |
wait_for | string | none | Name of a global JavaScript function. Rendering starts once it returns a truthy value. Useful for charts and data loaded by script. |
timeout | integer | 30 | Maximum render time in seconds. Values above 30 are capped at 30. |
raise_for_status | boolean | false | For a URL source: fail with 400 if the page answers with status 400 or higher, instead of rendering the error page. |
disable_javascript | boolean | false | Do not run scripts in the page. |
Injecting code
| Name | Type | Default | Description |
|---|---|---|---|
css | string | none | CSS text, or a URL to a stylesheet, added after the page loads. |
javascript | string | none | JavaScript text, or a URL to a script, run after the page loads. |
Access to protected pages
| Name | Type | Default | Description |
|---|---|---|---|
auth | object | none | { "username": "...", "password": "..." } for HTTP Basic authentication of the source URL. |
http_headers | object | none | Extra request headers, for example { "Accept-Language": "ar" }. |
cookies | array | none | Cookies to set: objects with name, value, and optionally domain, path, secure, http_only. |
Response options
| Name | Type | Default | Description |
|---|---|---|---|
encode | boolean | false | Return JSON with the PDF in base64 instead of the raw file. |
sandbox | boolean | false | Accepted 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 }
Relative links in HTML
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.