Skip to content

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
VariableDefaultMeaning
PDFEMBER_API_KEYrequiredYour API key.
PDFEMBER_BASE_URLhttps://pdfember.com/api/v1Change only for a test server.
PDFEMBER_TIMEOUT70Seconds 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->contentsThe bytes of the PDF, or of the ZIP for split.
$pdf->pagesPages in the PDF.
$pdf->documentsLeftDocuments 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.
AuthenticationException401Wrong or revoked key.
QuotaExceededException402This month's documents are used up.
ValidationException422An option or a file was refused; see $fields.
RateLimitException429Too many requests or renders at once; see $retryAfter.
ApiExceptionotherAnything 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.