Skip to main content

PHP SDK

The official PHP SDK uses Guzzle and is intended for server-side PHP applications. It supports PDFBolt's Direct, Sync, Async, Usage, and webhook signature workflows.

If you prefer calling the REST API directly with PHP, see the PHP API quick start. For the complete API parameter reference, see Conversion Parameters and the OpenAPI Reference.

Installation

composer require pdfbolt/pdfbolt

Requires PHP 8.2 or newer.

Quick Start

This example converts https://example.com to a PDF, saves it as example.pdf, and prints the SDK version and output size.

<?php

require __DIR__ . '/vendor/autoload.php';

use PDFBolt\PDFBolt;

$pdfbolt = new PDFBolt(
apiKey: getenv('PDFBOLT_API_KEY') ?: throw new RuntimeException('Set PDFBOLT_API_KEY.'),
);

$pdf = $pdfbolt->direct()->fromUrl('https://example.com', [
'printBackground' => true,
]);

$pdf->save('example.pdf');

echo 'Using PDFBolt SDK ' . PDFBolt::VERSION . PHP_EOL;
echo 'Saved ' . $pdf->size() . ' bytes' . PHP_EOL;

PHP SDK conversion parameters use the same camelCase field names as the PDFBolt REST API:

  • printBackground
  • customS3PresignedUrl
  • extraHTTPHeaders
  • additionalWebhookHeaders

templateData keys are sent unchanged, so they continue to match your template variables exactly.

Convert a URL to PDF

Use fromUrl() when you want PDFBolt to load an HTTPS page and render it as a PDF.

$pdf = $pdfbolt->direct()->fromUrl('https://example.com', [
'format' => 'A4',
'printBackground' => true,
]);

$pdf->save('url.pdf');

Convert HTML to PDF

Use fromHtml() when you have raw HTML. The SDK automatically encodes it to Base64 for the API.

$pdf = $pdfbolt->direct()->fromHtml('<h1>Hello from PDFBolt</h1>', [
'format' => 'A4',
]);

$pdf->save('hello.pdf');

If you already have a Base64-encoded HTML string, use convert() directly. It returns the same DirectConversionResult as fromHtml().

$pdf = $pdfbolt->direct()->convert([
'html' => 'PGgxPkhlbGxvPC9oMT4=',
]);

$pdf->save('hello.pdf');

Header and footer templates work the same way: fromUrl(), fromHtml(), and fromTemplate() accept raw HTML templates and automatically encode them to Base64, while convert() expects Base64-encoded template values.

This rule applies to all low-level convert() methods: direct()->convert(), sync()->convert(), and asyncConversions()->convert() send html, headerTemplate, and footerTemplate exactly as provided.

See the headerTemplate and footerTemplate parameter docs for supported placeholders and examples.

$pdf = $pdfbolt->direct()->fromHtml(
'<!doctype html><html><body><h1>Invoice</h1></body></html>',
[
'displayHeaderFooter' => true,
'headerTemplate' => '<div style="font-size:9px;width:100%;text-align:center;">Invoice</div>',
'footerTemplate' => '<div style="font-size:9px;width:100%;text-align:center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
'margin' => [
'top' => '20mm',
'bottom' => '20mm',
],
],
);

$pdf->save('invoice.pdf');

Convert a Template to PDF

Use fromTemplate() with a published PDFBolt template ID and the JSON data for that template.

$pdf = $pdfbolt->direct()->fromTemplate(
'00000000-0000-0000-0000-000000000000',
[
'invoiceNumber' => 'INV-1001',
'customerName' => 'Acme Inc.',
'total' => '$250.00',
],
);

$pdf->save('template.pdf');

Pass templateData as an associative array. The SDK does not rename keys inside your template data. For nested empty JSON objects inside templateData, use (object) []. Plain [] is encoded by PHP as a JSON array.

Direct Results

Use direct() when you want the generated PDF returned in the HTTP response. Direct conversions return a DirectConversionResult.

DirectConversionResult->buffer always contains PDF bytes. When you pass isEncoded => true, PDFBolt returns Base64 text and the SDK exposes it as DirectConversionResult->base64. DirectConversionResult->buffer still contains decoded PDF bytes, so save() works the same way.

$pdf = $pdfbolt->direct()->fromUrl('https://example.com', [
'filename' => 'example.pdf',
]);

$pdf->save('example.pdf');

echo $pdf->buffer;
echo $pdf->base64; // string only when isEncoded is true, otherwise null
echo $pdf->size();
echo $pdf->contentType;
echo $pdf->contentDisposition;
echo $pdf->filename;
echo $pdf->conversionCost;
echo $pdf->rateLimit->minute->remaining;
echo $pdf->headers['x-pdfbolt-conversion-cost'][0] ?? null;

Direct, Sync, Async job, and Usage results expose parsed rate-limit values through rateLimit. Rate-limit fields can be null when a response does not include the matching header. Direct results also expose raw HTTP headers through $pdf->headers.

Get a Temporary URL

Use sync() when you want PDFBolt to generate the document and return a temporary download URL, valid for 24 hours.

$result = $pdfbolt->sync()->fromUrl('https://example.com');

echo $result->requestId;
echo $result->status;
echo $result->documentUrl;
echo $result->expiresAt;
echo $result->duration;
echo $result->documentSizeMb;
echo $result->rateLimit->minute->remaining;
echo $result->conversionCost;

For custom S3 uploads, pass a valid presigned URL. PDFBolt uploads the generated PDF to your S3-compatible bucket, so documentUrl and expiresAt are null. Custom S3 uploads are available on paid plans.

$result = $pdfbolt->sync()->fromHtml('<h1>Invoice</h1>', [
'customS3PresignedUrl' => getenv('PDFBOLT_CUSTOM_S3_PRESIGNED_URL')
?: throw new RuntimeException('Set PDFBOLT_CUSTOM_S3_PRESIGNED_URL.'),
]);

var_dump($result->isCustomS3Bucket); // true
var_dump($result->documentUrl); // null

Presigned URLs are usually time-limited and often single-use. Generate a new one for each conversion. See Uploading to Your S3 Bucket for setup details.

Run an Async Conversion

Use asyncConversions() when the conversion should run in the background. The request returns an accepted job with a requestId immediately, and PDFBolt sends the final success or failure payload to your HTTPS webhook later.

$job = $pdfbolt->asyncConversions()->fromUrl(
'https://example.com',
'https://your-app.com/webhooks/pdfbolt',
[
'retryDelays' => [5, 15, 60],
],
);

echo $job->requestId;
echo $job->rateLimit->minute->remaining;

retryDelays are in minutes and retry the conversion attempt itself, not webhook delivery.

For async custom S3 uploads, pass a valid customS3PresignedUrl in the async request. After a successful upload, the final webhook has isCustomS3Bucket=true, documentUrl=null, and expiresAt=null.

Verify Webhook Signatures

Use the exact raw request body received from your framework. Do not parse and re-serialize JSON before verification.

For plain PHP handlers, use file_get_contents('php://input'). For Laravel and Symfony, use $request->getContent() as the raw body. For PSR-7 frameworks, read (string) $request->getBody() before any middleware consumes or modifies the body stream.

The secret value is your PDFBolt webhook signature key, not your API key. You can find the webhook signature key on the API Keys page in the Dashboard.

use PDFBolt\PDFBolt;

$event = PDFBolt::webhooks()->verifyAndParse(
rawBody: $request->getContent(),
signature: $request->headers->get('x-pdfbolt-signature'),
secret: getenv('PDFBOLT_WEBHOOK_SECRET') ?: throw new RuntimeException('Set PDFBOLT_WEBHOOK_SECRET.'),
);

echo $event->requestId;
echo $event->status;
echo $event->errorCode;
echo $event->documentUrl;

verifyAndParse() verifies the HMAC signature first and parses JSON only after the signature is valid. If you only need a boolean result, use verifySignature().

Error Handling

The PDFBolt API returns one common error response shape. The SDK represents API error responses with one class: PDFBoltApiException. Check statusCode for HTTP-level handling and errorCode for PDFBolt-specific causes.

use PDFBolt\Exceptions\PDFBoltApiException;
use PDFBolt\Exceptions\PDFBoltException;
use PDFBolt\Exceptions\PDFBoltNetworkException;
use PDFBolt\Exceptions\PDFBoltValidationException;

try {
$pdfbolt->direct()->fromUrl('https://example.com');
} catch (PDFBoltValidationException $error) {
echo $error->getMessage();
} catch (PDFBoltApiException $error) {
echo $error->statusCode;
echo $error->timestamp;
echo $error->errorCode;
echo $error->errorMessage;
echo $error->rateLimit->minute->limit;
echo $error->rateLimit->minute->remaining;
echo $error->rawBody;

if ($error->statusCode === 401) {
echo 'Check your API key.';
}
} catch (PDFBoltNetworkException $error) {
echo $error->getMessage();
} catch (PDFBoltException $error) {
throw $error;
}

See Error Handling for the full API error reference.

PDFBoltException is the base class for all SDK errors. These SDK-specific classes are worth calling out:

  • PDFBoltValidationException is thrown before a request when SDK-side parameters are invalid.
  • PDFBoltConfigurationException is thrown before a request when SDK configuration, such as the API key or global request timeout, is missing or invalid.
  • PDFBoltNetworkException means the SDK did not receive a usable API response, for example because of a network failure, SDK HTTP timeout, or malformed success response.
  • PDFBoltWebhookSignatureException is thrown by verifyAndParse() when the webhook signature or payload is invalid.

Available error classes:

PDFBoltException
PDFBoltApiException
PDFBoltNetworkException
PDFBoltWebhookSignatureException
PDFBoltValidationException
PDFBoltConfigurationException

Advanced Client Options

use GuzzleHttp\Client;
use PDFBolt\PDFBolt;

$httpClient = new Client();

$pdfbolt = new PDFBolt(
apiKey: getenv('PDFBOLT_API_KEY') ?: throw new RuntimeException('Set PDFBOLT_API_KEY.'),
baseUrl: 'https://api.pdfbolt.com',
requestTimeout: 120.0,
httpClient: $httpClient,
);

Pass a custom Guzzle client when you need custom transport configuration such as a proxy, instrumentation, or a test handler.

The SDK does not automatically retry failed requests. One SDK method call sends at most one HTTP request. If your application retries, use idempotent inputs and generate a fresh presigned URL for each custom S3 retry. For async conversion retries handled by PDFBolt, use the retryDelays conversion parameter.

requestTimeout is the SDK HTTP timeout in seconds. The default is 120.0. It is different from the conversion timeout option sent to the PDFBolt API, which is a browser render timeout in milliseconds, for example timeout => 30000.

Each conversion request can override the SDK HTTP timeout by passing requestTimeout in the options array:

$pdf = $pdfbolt->direct()->fromUrl('https://example.com', [
'requestTimeout' => 180.0,
]);

For usage requests, pass the SDK HTTP timeout directly:

$usage = $pdfbolt->usage()->get(180.0);

The SDK sends User-Agent: pdfbolt-php/<version> on requests to the PDFBolt API. This helps identify SDK traffic for support and debugging. To set headers for the page being rendered by Chromium, use the conversion extraHTTPHeaders parameter.

Common conversion options such as format, margin, printBackground, contentDisposition, filename, and compression use the same names as the REST API. See Conversion Parameters for the full parameter reference.

Usage

Use usage()->get() to read the current account plan, remaining conversion credits, and rate-limit metadata.

$usage = $pdfbolt->usage()->get();

echo $usage->plan;
print_r($usage->recurring);
print_r($usage->oneTime);
echo $usage->rateLimit->day->remaining;

SDK Reference

Main client methods:

$pdfbolt->direct()->convert(array $params);
$pdfbolt->direct()->fromUrl(string $url, array $options = []);
$pdfbolt->direct()->fromHtml(string $html, array $options = []);
$pdfbolt->direct()->fromTemplate(string $templateId, array $templateData, array $options = []);

$pdfbolt->sync()->convert(array $params);
$pdfbolt->sync()->fromUrl(string $url, array $options = []);
$pdfbolt->sync()->fromHtml(string $html, array $options = []);
$pdfbolt->sync()->fromTemplate(string $templateId, array $templateData, array $options = []);

$pdfbolt->asyncConversions()->convert(array $params);
$pdfbolt->asyncConversions()->fromUrl(string $url, string $webhook, array $options = []);
$pdfbolt->asyncConversions()->fromHtml(string $html, string $webhook, array $options = []);
$pdfbolt->asyncConversions()->fromTemplate(string $templateId, array $templateData, string $webhook, array $options = []);

$pdfbolt->usage()->get(?float $requestTimeout = null);

Webhook helpers:

PDFBolt::webhooks()->verifySignature(string $rawBody, string|array|null $signature, string $secret);
PDFBolt::webhooks()->verifyAndParse(string $rawBody, string|array|null $signature, string $secret);

Common runtime classes:

PDFBolt
DirectConversionResult
SyncConversionResult
AsyncConversionJob
AsyncConversionWebhookEvent
UsageSummary
RateLimitInfo
PDFBoltException
PDFBoltApiException
PDFBoltNetworkException
PDFBoltWebhookSignatureException
PDFBoltValidationException
PDFBoltConfigurationException

Namespaces are omitted in the reference lists for readability; result classes live under PDFBolt\Results, exception classes under PDFBolt\Exceptions, and the client class lives under PDFBolt.