la-souris / document-signer-sdk
Provider-agnostic e-signature SDK for PHP: build envelopes from HTML templates with {[type:signer:name]} placeholders, render them to PDF, and send them through any SignatureProvider implementation (ValidSign, DocuSign, or your own).
Package info
github.com/la-souris/package-document-signer-sdk
pkg:composer/la-souris/document-signer-sdk
Requires
- php: ^8.2
Requires (Dev)
- phpunit/phpunit: ^11.0 || ^13.0
- spatie/browsershot: ^4.0 || ^5.0
Suggests
- la-souris/document-signer-docusign: Required to use DocuSign
- la-souris/document-signer-validsign: Required to use ValidSign.
- spatie/browsershot: Required to use the bundled BrowsershotPdfRenderer (default PDF renderer).
This package is not auto-updated.
Last update: 2026-07-22 23:01:12 UTC
README
A provider-agnostic PHP SDK for sending HTML documents through e-signature providers.
You author contracts as HTML with {[type:signer:name]} placeholders; the SDK
translates them to the provider's native anchor format, renders the HTML to PDF,
and creates the envelope.
+-------------------+ +--------------------+ +----------------------+
| HTML + signers | --> | documentsigner | --> | ValidSign / |
| (your code) | | sdk + provider | | DocuSign API |
+-------------------+ +--------------------+ +----------------------+
Contents
- Packages
- Framework integrations
- Fluent builder
- Page decoration
- End-to-end example
- Documentation
- Requirements
Packages
| Package | Path | Purpose |
|---|---|---|
la-souris/document-signer-sdk |
sdk/ |
Domain model, placeholder parser, anchor-replacer base, Browsershot PDF renderer, SignatureProvider contract. |
la-souris/document-signer-validsign |
validsign/ |
ValidSign implementation. |
la-souris/document-signer-docusign |
docusign/ |
DocuSign eSignature implementation. |
All three are installed together for local development through the root
composer.json, which exposes them as path repositories.
Framework integrations
Rather than wiring the SDK by hand, two packages integrate it into the popular
PHP frameworks. Each gives you a container-managed DocumentSignerManager that
resolves a SignatureProvider by name, verified webhook routes, and a signer-
email recipient override for dev/staging. They mirror each other — same
providers-list config, same webhook event — so the two stay conceptually
identical:
| Package | Repository | Purpose |
|---|---|---|
la-souris/document-signer-symfony |
document-signer-symfony | Bundle: configuration, driver manager, verified webhook routes, translated event labels. |
la-souris/document-signer-laravel |
document-signer-laravel | Config, service provider, driver manager, facade, Blade placeholder components, verified webhook routes. |
Install the one matching your framework:
composer require la-souris/document-signer-symfony # Symfony composer require la-souris/document-signer-laravel # Laravel
Fluent builder
The positional new Envelope(...) constructor still works, but for
step-by-step assembly there's a builder:
$envelope = Envelope::builder() ->name('NDA 2026-06') ->emailSubject('Please sign the NDA') ->emailMessage('Hi Jane, please sign at your convenience.') ->addDocument($document) ->addSigner($signer) ->signingOrder(SigningOrder::Parallel) ->withMetadata('contract_id', 42) ->build();
addSigner() and addDocument() each accept either a pre-built value
object or the raw constructor arguments via named parameters, so you can
mix styles depending on what reads best at each call site:
Envelope::builder() ->name('NDA') ->emailSubject('Please sign') // Pre-built object: ->addDocument(new Document(id: 'nda', name: 'NDA', html: $html)) // Inline named args: ->addSigner(key: 'counterparty', name: 'Jane Doe', email: 'jane@example.com') ->build();
build() delegates every domain invariant (duplicate signer keys, empty
document list, etc.) to Envelope's constructor — so a half-configured
builder never blows up mid-chain.
Page decoration
Document accepts optional header and footer HTML with per-document
placement:
new Document( id: 'nda', name: 'NDA', html: '<h1>NDA</h1>...', headerHtml: '<div class="brand">Acme Legal</div>', footerHtml: '<div>Confidential</div>', headerPlacement: HeaderPlacement::FirstPage, // or ::AllPages footerPlacement: FooterPlacement::AllPages, );
Under the hood the SDK's PageDecoration is threaded through to the PDF
renderer. AllPages uses the underlying engine's native repeat-on-every-page
header/footer slot; FirstPage inlines the HTML at the top/bottom of the
body (since browsers have no native "first-page only" flag). See
PDF rendering for the details.
End-to-end example
use LaSouris\DocumentSigner\Sdk\Document\Document; use LaSouris\DocumentSigner\Sdk\Envelope\Envelope; use LaSouris\DocumentSigner\Sdk\Signer\Signer; use LaSouris\DocumentSigner\Sdk\Signer\SigningOrder; use LaSouris\DocumentSigner\ValidSign\ValidSignConfig; use LaSouris\DocumentSigner\ValidSign\ValidSignProvider; $envelope = new Envelope( name: 'NDA 2026-06', documents: [ new Document( id: 'nda', name: 'Non-disclosure agreement', html: '<h1>NDA</h1><p>Signed by {[text:counterparty:fullname]}</p>' . '<p>{[signature:counterparty:sig]} on {[date:counterparty:signdate]}</p>', ), ], signers: [ new Signer(key: 'counterparty', name: 'Jane Doe', email: 'jane@example.com'), ], emailSubject: 'Please sign the NDA', emailMessage: 'Hi Jane, please sign at your convenience.', signingOrder: SigningOrder::Parallel, ); $provider = new ValidSignProvider( new ValidSignConfig(apiKey: getenv('VALIDSIGN_API_KEY')), ); $receipt = $provider->send($envelope); // $receipt->providerEnvelopeId is now the ValidSign package id.
Swapping providers is a one-line change: instantiate DocuSignProvider with a
DocuSignConfig instead — the Envelope is untouched.
Documentation
Start with Getting started, then dive into the relevant guide:
- Getting started
- Architecture
- Placeholder syntax
- PDF rendering
- ValidSign provider
- DocuSign provider
- Extending the SDK
- Writing a custom provider
- Error handling
- Webhook events
- Symfony integration
- Laravel integration
Requirements
- PHP 8.2
- A PDF renderer. The SDK bundles a
BrowsershotPdfRendererthat wraps spatie/browsershot, but that package is an optional dependency you must install explicitly if you want to use the default:composer require spatie/browsershot
ConstructingBrowsershotPdfRendererwithout it throws a clear install-hint. To use a different engine, implementPdfRendereryourself (see PDF rendering). - Node.js + Puppeteer (only when using the Browsershot renderer — for headless Chromium)
- A ValidSign or DocuSign account with API credentials