PHPackages                             laulamanapps/document-signer-laravel - 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. [API Development](/categories/api)
4. /
5. laulamanapps/document-signer-laravel

ActiveLibrary[API Development](/categories/api)

laulamanapps/document-signer-laravel
====================================

Laravel integration for the document signer SDK: config, service provider, manager, facade, and webhook routes for ValidSign and DocuSign.

v1.4.0(1mo ago)07↑2471.4%proprietaryPHPPHP ^8.5CI passing

Since Jun 30Pushed 1mo agoCompare

[ Source](https://github.com/LauLamanApps/document-signer-laravel)[ Packagist](https://packagist.org/packages/laulamanapps/document-signer-laravel)[ RSS](/packages/laulamanapps-document-signer-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (11)Versions (8)Used By (0)

Laravel integration for the document signer SDK
===============================================

[](#laravel-integration-for-the-document-signer-sdk)

Laravel integration for the [Document Signer SDK](https://github.com/LauLamanApps/document-signer-sdk): config, service provider, driver manager, facade, and verified webhook routes for both ValidSign and DocuSign.

Install
-------

[](#install)

```
composer require laulamanapps/document-signer-laravel
```

Then add at least one provider package — the laravel package treats both as optional:

```
composer require laulamanapps/document-signer-validsign   # for the validsign driver
composer require laulamanapps/document-signer-docusign    # for the docusign driver
```

Publish the config:

```
php artisan vendor:publish --tag=document-signer-config
```

Configure
---------

[](#configure)

`config/document-signer.php` reads from `.env`. Minimum for ValidSign:

```
VALIDSIGN_API_KEY=your-base64-key
```

Minimum for DocuSign:

```
DOCUSIGN_INTEGRATION_KEY=...
DOCUSIGN_USER_ID=...
DOCUSIGN_ACCOUNT_ID=...
DOCUSIGN_PRIVATE_KEY_PATH=/path/to/private.pem
```

### Default driver

[](#default-driver)

`DOCUMENT_SIGNER_DRIVER` is optional. If left unset the manager auto-selects the sole configured driver — i.e. the one whose primary credential (`VALIDSIGN_API_KEY` or `DOCUSIGN_INTEGRATION_KEY`) is present. Set the variable explicitly only when you configure both providers in the same app:

```
# Both configured — pick the implicit default:
DOCUMENT_SIGNER_DRIVER=validsign
```

Without an explicit choice in the "both configured" case, the first implicit `DocumentSigner::send()` call throws with the list of configured drivers.

Sending an envelope
-------------------

[](#sending-an-envelope)

```
use LauLamanApps\DocumentSigner\Laravel\Facades\DocumentSigner;
use LauLamanApps\DocumentSigner\Sdk\Document\Document;
use LauLamanApps\DocumentSigner\Sdk\Envelope\Envelope;
use LauLamanApps\DocumentSigner\Sdk\Signer\Signer;

$receipt = DocumentSigner::send(new Envelope(
    name:         'NDA',
    documents:    [new Document(
        id:   'nda',
        name: 'NDA',
        html: '{[signature:counterparty:sig]} on {[date:counterparty:signdate]}',
    )],
    signers:      [new Signer(key: 'counterparty', name: 'Jane Doe', email: 'jane@example.com')],
    emailSubject: 'Please sign the NDA',
));

// Switch driver at runtime:
$receipt = DocumentSigner::driver('docusign')->send($envelope);
```

You can also type-hint the manager directly:

```
use LauLamanApps\DocumentSigner\Laravel\DocumentSignerManager;

public function __construct(private DocumentSignerManager $signer) {}
```

Blade components
----------------

[](#blade-components)

The raw `{[type:signer:name]}` syntax is safe to type inside `.blade.php`files — `{[` / `]}` doesn't collide with Blade's `{{ }}` echo tags. For ergonomics, though, the package ships five anonymous components that compile to the raw placeholder token so contracts read like normal HTML:

```
Mutual NDA

I, , agree.

Signed:
   on

   I would like to receive updates.
```

ComponentCompiles to```{[signature:…:…]}````{[initials:…:…]}````{[text:…:…]}````{[date:…:…]}````{[checkbox:…:…]}`The components are registered under the `document-signer::` namespace by the service provider. Both `signer` and `name` are required attributes. After the view renders, the resulting HTML is what you pass to `Document::$html` — the SDK parser sees the literal `{[type:signer:name]}` tokens and proceeds as usual.

PDF renderer
------------

[](#pdf-renderer)

The manager wires a [`PdfRenderer`](https://github.com/LauLamanApps/document-signer-sdk/blob/main/src/Pdf/PdfRenderer.php)into every driver it resolves. By default it uses the SDK's `BrowsershotPdfRenderer`. Two other options are built in.

### Default: install spatie/browsershot

[](#default-install-spatiebrowsershot)

The SDK bundles the `BrowsershotPdfRenderer` class but not the Composer dependency — you need to install it explicitly if you want to keep the default:

```
composer require spatie/browsershot
```

Without it the manager throws an `InvalidArgumentException` pointing at the install command the first time it tries to build the renderer.

### Use spatie/laravel-pdf

[](#use-spatielaravel-pdf)

If your application already configures [spatie/laravel-pdf](https://github.com/spatie/laravel-pdf) — custom Node binary, default paper size, headers/footers, Browsershot tweaks — switch the SDK over so it picks up that configuration:

```
composer require spatie/laravel-pdf
```

```
DOCUMENT_SIGNER_PDF_RENDERER=laravel-pdf
```

The SDK then renders every envelope document through the `Pdf` facade. If `laravel-pdf` isn't installed when this option is selected, the manager throws an `InvalidArgumentException` pointing at the install command.

### Bind a fully custom renderer

[](#bind-a-fully-custom-renderer)

For any other engine (wkhtmltopdf, Gotenberg, an external service, a tuned Browsershot setup), implement the SDK's `PdfRenderer` interface and bind it in a service provider — the manager picks up the container binding first and ignores the config value:

```
use LauLamanApps\DocumentSigner\Sdk\Pdf\PdfRenderer;
use App\Pdf\GotenbergRenderer;

$this->app->bind(PdfRenderer::class, GotenbergRenderer::class);
```

See [Writing a custom renderer](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/pdf-rendering.md)for the interface and an example.

Webhooks
--------

[](#webhooks)

The signing secret **is** the on/off switch. A webhook route is registered for each driver whose secret is set:

- `DOCUSIGN_CONNECT_HMAC_SECRET` set → `POST /document-signer/webhooks/docusign`
- `VALIDSIGN_CALLBACK_SECRET` set → `POST /document-signer/webhooks/validsign`

If neither is set, no webhook routes are registered at all — a webhook with no secret would 401 every request anyway, so exposing it wouldn't be useful. This is also the switch to use when callbacks are handled by a separate service (queue worker, edge function, external ingest): just leave the secret unset.

DocuSign only:

```
DOCUSIGN_INTEGRATION_KEY=...
DOCUSIGN_CONNECT_HMAC_SECRET=...
```

ValidSign only:

```
VALIDSIGN_API_KEY=...
VALIDSIGN_CALLBACK_SECRET=...
```

The common prefix (default `document-signer/webhooks`) and middleware (default `['api']`) live under `document-signer.webhooks` in the config file.

ProviderRegistered whenRoute nameURLSignature mechanismDocuSign`DOCUSIGN_CONNECT_HMAC_SECRET` is set`document-signer.webhooks.docusign``POST /document-signer/webhooks/docusign`HMAC-SHA256 of raw body in `X-DocuSign-Signature-1..N`ValidSign`VALIDSIGN_CALLBACK_SECRET` is set`document-signer.webhooks.validsign``POST /document-signer/webhooks/validsign`Shared secret in `Authorization: Basic ` — accepted as `base64("user:secret")`, `base64(secret)`, or the raw stringBoth verifiers use `hash_equals` for constant-time comparison and reject unverified requests with HTTP 401.

Listen to the event in `app/Providers/EventServiceProvider.php`:

```
use LauLamanApps\DocumentSigner\Laravel\Events\DocumentSignerWebhookReceived;

protected $listen = [
    DocumentSignerWebhookReceived::class => [
        \App\Listeners\HandleSignerWebhook::class,
    ],
];
```

The controller resolves the payload's event token against the provider's `WebhookEvent` enum before dispatching, so listeners can classify events without doing the enum look-up themselves:

```
use LauLamanApps\DocumentSigner\Laravel\Events\DocumentSignerWebhookReceived;

final class HandleSignerWebhook
{
    public function handle(DocumentSignerWebhookReceived $event): void
    {
        // Provider-agnostic — same code serves DocuSign and ValidSign once
        // both enums ship. Null-safe: unknown tokens fall through to default.
        match (true) {
            $event->event?->isCompleted() => $this->onCompleted($event->payload),
            $event->event?->isDeclined()  => $this->onDeclined($event->payload),
            $event->event?->isFailure()   => $this->pageOncall($event->payload),
            default                       => null,
        };
    }
}
```

The raw payload is still available on `$event->payload` (and the original `Illuminate\Http\Request` on `$event->request`) if you need vendor-specific fields.

### Translated event labels

[](#translated-event-labels)

Each `WebhookEvent` can be rendered as a human-readable string via `EventTranslator`, backed by the package's translation files:

```
use LauLamanApps\DocumentSigner\Laravel\Webhook\EventTranslator;
use LauLamanApps\DocumentSigner\ValidSign\Webhook\EventType;

public function handle(
    DocumentSignerWebhookReceived $event,
    EventTranslator               $labels,
): void {
    if ($event->event === null) {
        return;
    }

    // "Package complete" in en, "Pakket voltooid" in nl.
    Log::info($labels->label($event->event));

    // Or force a locale:
    $subject = $labels->label($event->event, locale: 'nl');
}
```

The package ships English (`en`) and Dutch (`nl`) translations for every ValidSign event out of the box. To add a locale or override the wording, publish the translations and edit the copies:

```
php artisan vendor:publish --tag=document-signer-translations
# → lang/vendor/document-signer/{en,nl}/validsign-events.php
```

Translation keys mirror the enum's raw provider tokens verbatim (`document-signer::validsign-events.PACKAGE_COMPLETE`), so you can also reach them via `trans()` directly.

Testing
-------

[](#testing)

Swap the live provider for a fake in tests:

```
use LauLamanApps\DocumentSigner\Laravel\Facades\DocumentSigner;
use LauLamanApps\DocumentSigner\Sdk\Envelope\EnvelopeStatus;
use LauLamanApps\DocumentSigner\Sdk\Provider\EnvelopeReceipt;
use LauLamanApps\DocumentSigner\Sdk\Provider\SignatureProvider;

DocumentSigner::set('validsign', new class implements SignatureProvider {
    public function send($envelope): EnvelopeReceipt {
        return new EnvelopeReceipt(
            provider: 'validsign',
            providerEnvelopeId: 'test-id',
            status: EnvelopeStatus::Sent,
        );
    }
    public function getStatus(string $id): EnvelopeStatus { return EnvelopeStatus::Completed; }
    public function downloadSigned(string $id): \SplFileInfo { return new \SplFileInfo('/dev/null'); }
    public function downloadAudit(string $id): \SplFileInfo { return new \SplFileInfo('/dev/null'); }
    public function getFieldValues(string $id): array { return []; }
    public function cancel(string $id, ?string $reason = null): void {}
});
```

For full end-to-end provider mocking, see [Extending the SDK](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/extending.md).

Requirements
------------

[](#requirements)

- PHP 8.5
- Laravel 13
- `laulamanapps/documentsigner-sdk`
- `laulamanapps/documentsigner-validsign` *or* `laulamanapps/documentsigner-docusign` (each is optional; installed only for the drivers you actually use — the manager throws a clear `composer require` hint if a missing driver is requested)
- Node.js + Puppeteer (for the default Browsershot renderer)

Documentation
-------------

[](#documentation)

- [SDK README](https://github.com/LauLamanApps/document-signer-sdk)
- [Getting started](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/getting-started.md)
- [ValidSign provider guide](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/providers/validsign.md)
- [DocuSign provider guide](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/providers/docusign.md)
- [Placeholder syntax](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/placeholders.md)
- [Extending the SDK](https://github.com/LauLamanApps/document-signer-sdk/blob/main/docs/extending.md)

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity56

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

7

Last Release

46d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/930ca3b1756d00a63c8ff3363e81f16f961cf3ef79ff0c9d362670c36d97e456?d=identicon)[LauLaman](/maintainers/LauLaman)

---

Top Contributors

[![LauLaman](https://avatars.githubusercontent.com/u/8283992?v=4)](https://github.com/LauLaman "LauLaman (10 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/laulamanapps-document-signer-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/laulamanapps-document-signer-laravel/health.svg)](https://phpackages.com/packages/laulamanapps-document-signer-laravel)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

79227.1M225](/packages/laravel-mcp)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k31.8M160](/packages/laravel-cashier)[nuwave/lighthouse

A framework for serving GraphQL from Laravel

3.5k12.2M128](/packages/nuwave-lighthouse)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

818355.4k3](/packages/defstudio-telegraph)

PHPackages © 2026

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