laulamanapps / 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/LauLamanApps/document-signer-sdk
pkg:composer/laulamanapps/document-signer-sdk
Requires
- php: ^8.5
Requires (Dev)
- phpunit/phpunit: ^11.0
- spatie/browsershot: ^4.0 || ^5.0
Suggests
- laulamanapps/document-signer-docusign: Required to use DocuSign
- laulamanapps/document-signer-validsign: Required to use ValidSign.
- spatie/browsershot: Required to use the bundled BrowsershotPdfRenderer (default PDF renderer).
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 |
+-------------------+ +--------------------+ +----------------------+
Packages
| Package | Path | Purpose |
|---|---|---|
laulamanapps/document-signer-sdk |
sdk/ |
Domain model, placeholder parser, anchor-replacer base, Browsershot PDF renderer, SignatureProvider contract. |
laulamanapps/document-signer-validsign |
validsign/ |
ValidSign implementation. |
laulamanapps/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.
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 LauLamanApps\DocumentSigner\Sdk\Document\Document; use LauLamanApps\DocumentSigner\Sdk\Envelope\Envelope; use LauLamanApps\DocumentSigner\Sdk\Signer\Signer; use LauLamanApps\DocumentSigner\Sdk\Signer\SigningOrder; use LauLamanApps\DocumentSigner\ValidSign\ValidSignConfig; use LauLamanApps\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
Requirements
- PHP 8.5
- 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