Drop in the SDK or call the REST API directly — grab a key, paste a snippet, and your first PDF is rendering in minutes.
Use the PHP / Laravel SDK for the cleanest integration. Or call the API directly with curl.
PHP SDK on GitHubOne fluent builder per API field. Auto-discovered Laravel service provider, facade, and config. Typed exceptions so validation errors flow into your existing form-error UI.
composer require htmltopdfapi/php-sdkHTML_TO_PDF_API_KEY=sk_live_xxxxxxxxxxxxxxxxuse HtmlToPdfApi\Laravel\Facades\HtmlToPdf;
Route::get('/invoices/{invoice}.pdf', function (Invoice $invoice, Request $request) {
$html = view('invoices.pdf', compact('invoice'))->render();
return HtmlToPdf::html($html)
->paperSize('a4')
->margins(top: 25, bottom: 25)
->footer('<div class="text-center">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>')
->waitUntil('networkidle0')
->generate()
->toResponse($request);
});use HtmlToPdfApi\HtmlToPdf;
$sdk = new HtmlToPdf(['api_key' => getenv('HTML_TO_PDF_API_KEY')]);
$sdk->url('https://example.com/dashboard')
->landscape()
->waitUntil('networkidle0')
->retina()
->generate()
->saveAs('/tmp/dashboard.pdf');use HtmlToPdfApi\Exceptions\ValidationException;
try {
$pdf = HtmlToPdf::html($html)->generate();
} catch (ValidationException $e) {
foreach ($e->errors() as $field => $messages) {
report("[$field] " . $messages[0]);
}
}Any HTTP client works. Bearer token auth, JSON body, PDF bytes back. The full request shape is documented in the API reference.
curl -X POST https://platform.htmltopdfapi.co/api/v1/pdf/generate \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Hello world</h1>",
"paper_size": "a4",
"margin_top": 25,
"margin_bottom": 25,
"footer_html": "<div style=\"text-align:center;font-size:9px\">Page <span class=\"pageNumber\"></span></div>"
}' \
--output document.pdfCommon patterns for the most-asked use cases.
Render a Blade view, add a footer with .pageNumber / .totalPages spans, stream inline.
Wait for JS-rendered charts with wait_for_selector, then capture the full page.
Send paper_width + paper_height in millimetres for non-standard sizes.
ValidationException, UsageLimitException, ConnectionException — what to catch and when to retry.
Every error response uses the same envelope so you can parse it once and reuse it everywhere.
| Status | Meaning | What to do |
|---|---|---|
| 401 | Bad / missing API key | Verify the Bearer token; rotate if compromised. |
| 422 | Request validation failed | Read errors map: { field → [messages] }; surface inline. |
| 429 | Plan quota exceeded | Wait for the reset window or upgrade plan. |
| 5xx | Server error | Retry with backoff. Persistent? Email support. |