la-souris/document-signer-docusign
DocuSign driver for la-souris/document-signer that lets Laravel and PHP apps send documents for eSignature, track envelope signing status, and retrieve completed, signed files through one consistent, framework-agnostic signing API.
This package is the DocuSign driver for la-souris/document-signer-sdk. You do not call DocuSign directly — you call the SDK's SignatureProvider contract, bind DocuSignProvider in the container, and swap it for the ValidSign (or another) implementation without touching call sites.
Minimum steps:
la-souris/document-signer-sdk ^1.0 are hard requirements. If you're on PHP 8.2, or Laravel 10 on an older CI image, bump those before anything else — this is the single most likely reason an install fails on day one.composer require <vendor>/<docusign-package> — confirm the exact name in the README).Document in the DocuSign demo account, receive the Connect webhook, then call downloadSignedDocument($document->id) and confirm you get the signed PDF back rather than the Summary.pdf certificate.Where to look first, in order: DocuSignConfig (everything tunable lives here), then DocuSignProvider (contract implementation — the surface you'll actually call), then DocuSignPlaceholderReplacer (the part most likely to need tuning), then DocuSignJwtAuth only if you hit auth errors.
Bind the provider, don't instantiate it. Register DocuSignProvider against the SDK's SignatureProvider interface in a service provider, driven by DocuSignConfig built from config/services.php. This is what makes the package swappable per environment (demo vs. prod account) and lets you fake it in tests.
Anchor-based templating is the core workflow. Placeholders in your source PDF/DOCX are replaced by DocuSign tabs. The package drops each tab's top edge onto the anchor line via anchorYOffset and sends an explicit size for every field type — deliberately matching ValidSign's rendering. That means documents you already templated for ValidSign should land in roughly the same place, which is the main migration story here.
Tune globally before touching code. DocuSignConfig::$anchorYOffsetPixels (positive = down) shifts every tab on every page. When a whole document set drifts uniformly, adjust this value rather than editing each anchor; per-field offsets stay for genuinely per-field corrections. Keep it at 0 until you've compared a rendered envelope against the original.
Download by your own id, not DocuSign's. downloadSignedDocument() takes Document::$id. The mapping to DocuSign's positional ids is persisted in an envelope-level sdkDocumentMap custom field, with a normalised document-name match as fallback. Pass your domain id and let the package resolve it.
Treat SignedDocumentUnavailableException as a retry signal, not a failure. Thrown when the envelope isn't finalised yet. In a queued job, release() with a backoff (30–120s) and a bounded attempt count — never an unbounded retry(). Webhooks are usually faster than polling anyway, so prefer downloading from the webhook handler and keep the exception path for reconciliation jobs.
Webhook flow. Point a DocuSign Connect subscription at a POST route, map the payload through the package's EventType mapping, and download on the "completed" event. Keep the handler idempotent — Connect retries on non-2xx and duplicates are normal — and store the envelope id as the dedupe key.
Audit trail: two outputs, pick deliberately. downloadAudit() gives DocuSign's Certificate of Completion as .pdf — that's the artefact to attach to a case file or email to a counterparty. DocuSignClient::downloadAuditEventsJson() gives the raw audit_events feed, which is what you want if you're loading timestamps and signer actions into your own tables. Many teams end up storing both: PDF for humans, JSON for querying.
anchorYOffsetPixels vs. DocuSign's own units. DocuSign documents anchor offsets in points, not pixels. Confirm from the source whether DocuSignPlaceholderReplacer converts before you start dialling in fractions of a pixel — otherwise your fine-tune will be off by a constant factor.sig_1, sig_2) rather than reusing a generic label.Summary.pdf skip is name-based. If one of your documents happens to be named Summary.pdf, it will be dropped from downloadSignedDocument() without warning. Namespace your filenames.sdkDocumentMap custom field is missing or unreadable. If you see it firing repeatedly, envelopes are being created outside the package (manual sends, other tooling) or the custom field is being stripped by a DocuSign template/field setting — fix the root cause rather than relying on the fallback, and make sure the normalised name comparison won't collide on documents like Contract.pdf.sdkDocumentMap value ships inside the envelope. It's visible to anyone with envelope access. Keep it to id → positional-index mappings and nothing sensitive, and watch DocuSign's custom-field value length limits on envelopes with many documents.DocuSignClient is the seam if you need a raw DocuSign call the SDK doesn't model (it's already exposed for downloadAuditEventsJson()); DocuSignConfig is the seam for environment-specific behaviour; and the SignatureProvider binding is the seam for local testing — implement a trivial fake rather than mocking DocuSignClient internals.anchorYOffsetPixels, then per-field anchorYOffset, then whether the tab has an explicit size being overridden by a template. Render the same document through the ValidSign provider and diff visually — the package is explicitly aiming for parity, so any gap is a bug worth reporting.How can I help you explore Laravel packages today?