To convert HTML to PDF in PHP with RelayPDF, call POST /v1/pdf with a UTF-8 html string. The documented html to pdf php api client is composer require relaypdf/relaypdf. That package wraps the same JSON field names as REST (html, filename, options, response). Methods are camelCase. Product page: https://relaypdf.com/html-to-pdf. PHP SDK: https://relaypdf.com/docs/sdks/php. REST hub: https://relaypdf.com/docs.
You do not run Chromium on the PHP host. The API prints the document in a remote Chromium. Default response is binary PDF bytes. The SDK save() helper writes those bytes to a path. You can also request a 24-hour download URL or an async job.
Install the official PHP SDK
Official docs list the Composer package as relaypdf/relaypdf. Requirements on the PHP SDK page: PHP 8.1 or newer with ext-curl, ext-json, and hash. Default base URL is https://api.relaypdf.com. Authentication is HTTP Bearer. The constructor takes the API key; missing apiKey throws before any request. Keys are not JWT. Load RELAYPDF_API_KEY from the env file written by npx @relaypdf/cli setup. Do not paste a key into chat.
The same docs page says the current line is 0.1.x and, until Packagist publish, you require the path in the SDK repo. Packagist returned 404 for relaypdf/relaypdf on 23 August 2026. composer require relaypdf/relaypdf is still the documented install line. Until the package is on Packagist, use a path or VCS require from the repo that ships that composer.json, or call REST with curl as shown below. Do not install generatepdfs/php-sdk or pdfy/php-sdk; those are other products.
composer require relaypdf/relaypdf
<?php
use RelayPDF\RelayPDF;
$client = new RelayPDF(getenv('RELAYPDF_API_KEY'));
$pdf = $client->pdf->fromHtml(
'<h1>Invoice #1042</h1><p>Total: $1,200.00</p>',
['filename' => 'invoice.pdf'],
);
$pdf->save('invoice.pdf');
What fromHtml sends
fromHtml is POST /v1/pdf. Send exactly one source. For this how-to that source is html, a JSON string, not Base64. Optional extras match REST: filename ending in .pdf; response binary (default), url, or async; callbackUrl for job completion (https only). Print controls go under options: format (letter default; A4, legal, tabloid, and other named Chromium sizes), landscape, printBackground (default true), preferCSSPageSize, scale 0.1–2, margin as CSS lengths, headerTemplate and footerTemplate (HTML; add extra margin so Chromium does not clip them), pageRanges, width/height, waitUntil (default networkidle0), timeout in milliseconds up to 60000, extraHTTPHeaders, cookies, waitForSelector, waitForTimeout (max 30000 ms).
The same client also exposes fromUrl, fromMarkdown, and fromTemplate on pdf. fromTemplate takes a published template id or slug plus a data array. Those are still POST /v1/pdf. Office files are POST /v1/convert. Merging existing PDFs is POST /v1/pdf/merge. Screenshots are POST /v1/images.
$pdf = $client->pdf->fromUrl('https://example.com', [
'filename' => 'page.pdf',
'options' => ['format' => 'A4', 'printBackground' => true],
]);
$md = $client->pdf->fromMarkdown("# Hello\n\nFrom **Markdown**.");
$invoice = $client->pdf->fromTemplate('invoice', [
'number' => 'INV-1042',
'total' => 1458,
], ['filename' => 'invoice.pdf', 'strict' => true]);
Binary, URL, and async
binary is the default: file bytes plus x-relaypdf-id, x-relaypdf-size, and content-disposition. The PHP client exposes save(). url returns JSON with a public download good for 24 hours (GET /v1/files/:id, no key). async returns 202; poll jobs.wait / jobs.get or set callbackUrl. The SDK does not retry failed requests.
$urlResult = $client->pdf->fromHtml('<h1>Hi</h1>', ['response' => 'url']);
$job = $client->convert->fromPath('deck.pptx', [
'to' => 'pdf',
'response' => 'async',
]);
$done = $client->jobs->wait($job->id);
$client->files->download($done['id'])->save('deck.pdf');
REST from PHP without the package
If Composer cannot resolve the package yet, POST the same body with ext-curl. Field names do not change. Authorization is Bearer. Content-Type is application/json.
<?php
$ch = curl_init('https://api.relaypdf.com/v1/pdf');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('RELAYPDF_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'html' => '<h1>Invoice #1042</h1><p>Total: $1,200.00</p>',
'filename' => 'invoice.pdf',
]),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
fwrite(STDERR, $body);
exit(1);
}
file_put_contents('invoice.pdf', $body);
Errors and limits
HTTP failures throw RelayPDFError with status, code, message, and optional retryAfter. REST failures use { error: { code, message } }. Failed jobs are never billed. payment_required means an empty wallet. rate_limited is 429 with Retry-After and is not billed. Trial wallets are 20/min; funded or auto-reload 60/min; burst 5 / 10s. url_not_allowed rejects private, loopback, or metadata hosts. callbackUrl must be https. options.timeout is the Chromium render budget, max 60s, not an HTTP client timeout. Render failures return render_failed and are not billed.
try {
$client->pdf->fromUrl('https://example.com');
} catch (RelayPDF\RelayPDFError $err) { echo $err->status, $err->code, $err->getMessage(), $err->retryAfter;
}
Short contrast with Dompdf
Dompdf (dompdf/dompdf) is an in-process HTML and CSS renderer written in PHP. Its own README describes it as mostly CSS 2.1 compliant. It downloads stylesheets and images in PHP, lays out the document, and writes a PDF without Chrome. That is the point of the library: no Node, no browser process, no paid API. Spatie’s laravel-pdf Dompdf driver notes the same: it works wherever PHP runs.
Documented Dompdf limits, from the project README and maintainer comments, not from marketing copy: it does not support CSS flexbox (issue 971; maintainer restated this in February 2025). It does not support CSS Grid (issue 2988). It does not execute JavaScript (maintainer: “We support HTML + CSS and that’s it”). Table cells are not pageable; a row must fit on one page. Floats larger than a page push following content. A single Dompdf instance should not render more than one HTML document because leftover parse state can affect the next run. Remote assets are off by default in many wrappers (isRemoteEnabled / is_remote_enabled).
RelayPDF is the other trade. You send HTML over HTTPS and Chromium prints it. Flex, grid, webfonts, @page, and client-side scripts that finish before waitUntil are in scope because the engine is a browser, not a CSS 2.1 PHP layout engine. You pay per successful job, you need a network hop, and you cannot run the printer offline. You also get URL, Markdown, published Handlebars templates, headers and footers that Chromium repeats per page, and the rest of the API (convert, merge, protect, stamp) on the same key.
Use Dompdf when the document is already a table-or-float layout, JavaScript is not required, and you must stay inside the PHP process. Use the html to pdf php api when the HTML is a real page (or a URL) and you want Chromium print options without installing Chrome next to php-fpm.
| Dompdf | RelayPDF PHP | |
|---|---|---|
| Where it runs | In the PHP process | POST https://api.relaypdf.com/v1/pdf |
| Engine | CSS 2.1 PHP renderer | Chromium print |
| Flex / Grid | No (README / issues 971, 2988) | Yes, via Chromium |
| JavaScript | Does not execute | Runs until waitUntil |
| Install | composer require dompdf/dompdf | composer require relaypdf/relaypdf |
| Offline | Yes | No |
What else the PHP client covers
The official PHP SDK uses ext-curl and mirrors the Node client. It covers the full public API: pdf tools (merge, extract, protect, unlock, bookmarks, raster, fromImages, stamp, rotate, deletePages, compress, info, text, formFields, formFill), images.fromHtml / fromUrl, convert.create / fromHtml / fromPath / wkhtml, templates, barcodes and zip, jobs and files, account and health, and Webhooks::verify for RelayPDF-Signature (HMAC-SHA256). JSON bodies keep REST camelCase.
Next step
Generate the first invoice HTML against https://relaypdf.com/html-to-pdf. Read method names on https://relaypdf.com/docs/sdks/php. Field names stay on https://relaypdf.com/docs. OpenAPI is https://relaypdf.com/openapi.json.