Integrations
PHP and Laravel
The official PHP package wraps the whole API: renders, the 19 PDF tools and usage, with typed errors. It works in any PHP 8.1+ project and sets itself up in Laravel 10 to 13. Source and issues on GitHub.
Install
composer require pdfember/pdfember-php
It brings Guzzle and nothing else. The client needs an API key (pdx_live_…) and refuses to start without one: sign in and create a key on the dashboard.
Laravel
The service provider and the Pdfember facade register themselves. Add the key to .env:
PDFEMBER_API_KEY=pdx_live_…
Render a Blade view and send it to the browser:
use Pdfember\Laravel\Facades\Pdfember; public function download(Invoice $invoice) { return Pdfember::html(view('invoices.show', compact('invoice'))->render(), [ 'page' => ['size' => 'A4', 'margin' => 12], ])->download("invoice-{$invoice->number}.pdf"); }
Or store it from a queued job; the client can also be injected as Pdfember\Pdfember:
public function handle(Pdfember\Pdfember $pdfember): void { $pdf = $pdfember->url('https://example.com/report/42', ['waitForSelector' => '#ready']); Storage::put('reports/42.pdf', $pdf->contents); }
html() and url() take the render options as an array. The defaults suit most apps; publish the config to change them:
php artisan vendor:publish --tag=pdfember-config
| Variable | Default | Meaning |
|---|---|---|
PDFEMBER_API_KEY | required | Your API key. |
PDFEMBER_BASE_URL | https://pdfember.com/api/v1 | Change only for a test server. |
PDFEMBER_TIMEOUT | 70 | Seconds to wait for a PDF. A render may take up to 60. |
Any PHP app
Symfony, WordPress, a plain script: create the client with the key.
use Pdfember\Pdfember; $pdfember = new Pdfember(getenv('PDFEMBER_API_KEY')); $pdfember->html('<h1>Hello</h1>')->save('hello.pdf'); $pdfember->url('https://example.com', ['layout' => 'single-page'])->save('page.pdf');
The constructor also takes a base URL, a timeout and a Guzzle client of your own, for a proxy or for mocked responses in tests.
PDF tools
Every tool is a case of Pdfember\Tool. Pass one file or a list: paths, uploads ($request->file(…)), stream resources or Upload::fromContents($bytes, 'name.pdf'). The options are those of the tools API.
use Pdfember\Tool; Pdfember::merge(['cover.pdf', 'report.pdf'])->save('full.pdf'); Pdfember::tool(Tool::Watermark, $request->file('contract'), ['text' => 'DRAFT']); Pdfember::tool(Tool::PageNumbers, 'book.pdf', ['format' => 'Page {n} of {total}']); // Split answers with a ZIP of PDFs Pdfember::tool(Tool::Split, 'book.pdf', ['every' => 10])->save('parts.zip');
The result
Every call returns a Pdfember\Document:
$pdf->contents | The bytes of the PDF, or of the ZIP for split. |
$pdf->pages | Pages in the PDF. |
$pdf->documentsLeft | Documents left this month on your plan. |
$pdf->save($path) | Writes the file; missing directories are created. |
$pdf->download($name) | A response that downloads the file. inline() shows it in the browser. |
$pdf->toBase64() | For email attachments and JSON. |
$pdf->isZip() | True for the split tool. |
Pdfember::usage() returns the plan and this month's documents, and is a quick check that the key works.
Errors
Every exception extends Pdfember\Exceptions\PdfemberException. API errors carry $status, $errorCode (as in the error codes) and, when an option is refused, $fields.
InvalidApiKeyException | – | No key, or not a pdfember key. |
AuthenticationException | 401 | Wrong or revoked key. |
QuotaExceededException | 402 | This month's documents are used up. |
ValidationException | 422 | An option or a file was refused; see $fields. |
RateLimitException | 429 | Too many requests or renders at once; see $retryAfter. |
ApiException | other | Anything else, e.g. 504 render_timeout. |
try { $pdf = Pdfember::html($html); } catch (Pdfember\Exceptions\RateLimitException $e) { $this->release($e->retryAfter ?? 10); // in a queued job: try again later }
Other languages
The API is plain HTTP: a JSON body in, a PDF out. Any HTTP client works; the quickstart shows the request with curl.