PHPackages                             lesspdf/laravel-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. lesspdf/laravel-sdk

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

lesspdf/laravel-sdk
===================

Laravel SDK for the lesspdf-engine HTML/Typst to PDF API

v1.02(1mo ago)03MITPHPPHP ^8.2

Since May 26Pushed 1mo agoCompare

[ Source](https://github.com/marmanik/lesspdf-laravel-sdk)[ Packagist](https://packagist.org/packages/lesspdf/laravel-sdk)[ Docs](https://github.com/lesspdf/laravel-sdk)[ RSS](/packages/lesspdf-laravel-sdk/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (16)Versions (4)Used By (0)

LessPDF Laravel SDK
===================

[](#lesspdf-laravel-sdk)

Laravel SDK for [lesspdf-engine](https://github.com/lesspdf/lesspdf-engine) — a self-hosted Rust service that converts HTML (via Chrome) or Typst markup to PDF.

Installation
------------

[](#installation)

```
composer require lesspdf/laravel-sdk
```

Add the following to your `.env`:

```
LESSPDF_URL=http://localhost:8080
LESSPDF_API_KEY=your-api-key
```

Optionally publish the config:

```
php artisan vendor:publish --tag="lesspdf-config"
```

Quick start
-----------

[](#quick-start)

```
use LessPdf\Facades\LessPdf;

// Render HTML → PDF bytes (stream or store as you like)
$pdf = LessPdf::renderHtml('Hello world');
return response($pdf, 200)->header('Content-Type', 'application/pdf');

// Store on server and get a URL back
$result = LessPdf::storeHtml('Invoice');
// $result->url, $result->id, $result->expiresAt
```

Render options
--------------

[](#render-options)

All options are fluent and optional. `format` defaults to `A4` — override only when needed:

```
use LessPdf\DTOs\RenderOptions;
use LessPdf\Enums\PaperFormat;

$options = RenderOptions::make()
    // format defaults to A4; override if needed:
    ->format(PaperFormat::Letter)
    ->landscape()
    ->scale(0.9)                        // 0.1 – 2.0
    ->printBackground()
    ->pageRanges('1-3,5')
    ->margins('20mm', '20mm', '15mm', '15mm')   // top, bottom, left, right
    ->metadata(title: 'My PDF', author: 'Acme', keywords: ['pdf'])
    ->waitForNetworkIdle()             // or ->waitForDomContentLoaded(settle_ms: 150)
    ->timeoutMs(15000);

$pdf = LessPdf::renderHtml($html, $options);
```

MethodDefaultNotes`format(PaperFormat)`**`A4`**A4, A3, A5, Letter, Legal, Tabloid`landscape()``false``scale(float)``1.0`0.1 – 2.0`printBackground()``false``pageRanges(string)`—e.g. `"1-3,5"``margins(top, bottom, left, right)`—units: mm, cm, in, px, pt`metadata(title, author, subject, keywords)`—PDF metadata`waitForNetworkIdle()`—Chrome wait strategy`waitForDomContentLoaded(settle_ms)`—Optionally add settle delay`waitForLoad()`—`timeoutMs(int)`server defaultPer-request timeout overrideAll render methods
------------------

[](#all-render-methods)

```
// HTML → inline PDF bytes
$pdf = LessPdf::renderHtml(string $html, ?RenderOptions $options): string

// HTML → store on server
$result = LessPdf::storeHtml(string $html, ?RenderOptions $options): StoredResult

// URL → inline PDF bytes (Chrome only; private IPs are SSRF-blocked)
$pdf = LessPdf::renderUrl(string $url, ?RenderOptions $options): string

// Typst markup → inline PDF bytes
$pdf = LessPdf::renderTypst(string $source, array $inputs = [], ?RenderOptions $options): string

// Full control
$pdf = LessPdf::render(Renderer $renderer, array|string $source, Delivery $delivery, ?RenderOptions $options): string|StoredResult
```

Batch rendering &amp; polling
-----------------------------

[](#batch-rendering--polling)

```
use LessPdf\Facades\LessPdf;

$batch = LessPdf::batch([
    ['renderer' => 'chrome', 'source' => ['html' => 'Doc A'], 'delivery' => 'store'],
    ['renderer' => 'chrome', 'source' => ['html' => 'Doc B'], 'delivery' => 'store'],
], webhook: [
    'url'    => route('webhooks.lesspdf'),
    'secret' => config('lesspdf.webhook_secret'),
    'events' => ['batch.completed'],
]);

// $batch->id, $batch->status, $batch->total

// Poll until done:
do {
    sleep(2);
    $batch = LessPdf::getBatchStatus($batch->id);
} while ($batch->status !== 'completed' && $batch->status !== 'failed');
```

Webhook setup
-------------

[](#webhook-setup)

**routes/web.php**

```
Route::post('/webhooks/lesspdf', [LessPdfWebhookController::class, 'handle'])
    ->name('webhooks.lesspdf');
```

**app/Http/Controllers/LessPdfWebhookController.php**

```
use Illuminate\Http\Request;
use LessPdf\Webhooks\LessPdfWebhook;
use LessPdf\Exceptions\SignatureException;

public function handle(Request $request): \Illuminate\Http\Response
{
    try {
        $event = LessPdfWebhook::fromRequest($request);
    } catch (SignatureException $e) {
        return response('Forbidden', 403);
    }

    if ($event->is('batch.completed')) {
        $data = $event->data; // ['batch_id', 'total', 'completed', 'failed']
        // dispatch your job...
    }

    return response('', 200);
}
```

Set `LESSPDF_WEBHOOK_SECRET` to the same secret you pass when submitting a batch.

Exception handling
------------------

[](#exception-handling)

```
use LessPdf\Exceptions\AuthenticationException;
use LessPdf\Exceptions\BrowserUnavailableException;
use LessPdf\Exceptions\LessPdfException;
use LessPdf\Exceptions\RateLimitException;
use LessPdf\Exceptions\RenderException;

try {
    $pdf = LessPdf::renderHtml($html);
} catch (AuthenticationException $e) {
    // 401 — bad API key
} catch (RateLimitException $e) {
    // 429 — retry after $e->retryAfter() seconds (SDK retries automatically by default)
} catch (BrowserUnavailableException $e) {
    // Chrome pool exhausted
} catch (RenderException $e) {
    // $e->errorCode() → 'timeout' | 'render_failed' | 'ssrf_blocked' | 'invalid_source'
} catch (LessPdfException $e) {
    // Base exception for all other errors
}
```

Status / error.codeException`401``AuthenticationException``429``RateLimitException` — `retryAfter(): int``browser_unavailable``BrowserUnavailableException``ssrf_blocked` / `timeout` / `render_failed` / `invalid_source``RenderException` — `errorCode(): string``404``NotFoundException`Other non-2xx`LessPdfException`Configuration
-------------

[](#configuration)

```
// config/lesspdf.php
return [
    'url'                       => env('LESSPDF_URL', 'http://localhost:8080'),
    'api_key'                   => env('LESSPDF_API_KEY'),
    'timeout'                   => env('LESSPDF_TIMEOUT', 60),          // HTTP timeout (seconds)
    'retry_attempts'            => env('LESSPDF_RETRY_ATTEMPTS', 2),    // auto-retry on 429
    'retry_delay_ms'            => env('LESSPDF_RETRY_DELAY_MS', 5000), // fallback delay
    'webhook_secret'            => env('LESSPDF_WEBHOOK_SECRET'),
    'webhook_tolerance_seconds' => env('LESSPDF_WEBHOOK_TOLERANCE', 300),
];
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance88

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

59d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5727095?v=4)[Nikos Marmaridis](/maintainers/MarmaNik)[@marmanik](https://github.com/marmanik)

---

Top Contributors

[![marmanik](https://avatars.githubusercontent.com/u/5727095?v=4)](https://github.com/marmanik "marmanik (3 commits)")

---

Tags

laravelpdfhtml-to-pdflesspdftypst

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/lesspdf-laravel-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/lesspdf-laravel-sdk/health.svg)](https://phpackages.com/packages/lesspdf-laravel-sdk)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k108.5M925](/packages/laravel-socialite)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[spatie/laravel-health

Monitor the health of a Laravel application

87912.0M177](/packages/spatie-laravel-health)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
