Adobe Sign for Laravelconceptlz/adobe-sign-laravel GitHub

Laravel 12 & 13 · PHP 8.2+ · Acrobat Sign REST API v6

E-signatures, the Laravel way.

conceptlz/adobe-sign-laravel plugs the Acrobat Sign PHP SDK into Laravel. You get .env configuration, a facade and an injectable client, OAuth routes so each user can connect their own Acrobat Sign account, an encrypted token table, a webhook endpoint that turns Adobe's callbacks into Laravel events, and php artisan adobe-sign:verify to check it all works.

composer require conceptlz/adobe-sign-laravel

What the bridge adds

The core package, conceptlz/adobe-sign, does the Acrobat Sign work: uploading PDFs, building agreements with a signing order, choosing a signature level, discovering your account's data centre, retrying throttled calls and parsing webhooks. It is framework-free on purpose, so it knows nothing about your config files, your cache, your logged-in users or your queues.

This package is the thin layer that connects those two worlds. It contains no Acrobat Sign API logic of its own; every request still goes through the core client. What it adds is the wiring a Laravel developer would otherwise write by hand:

  • Configuration. One config/adobe-sign.php file read from .env, covering auth mode, OAuth app, signature level, cache store, retries, log channel and webhooks.
  • A client you can inject. Type-hint Conceptlz\AdobeSign\AdobeSign in a controller, job or command, or use the AdobeSign facade. Both come pre-configured with Laravel's cache, logger and HTTP client.
  • OAuth without the plumbing. Two routes run the authorization-code flow, check the single-use state, store tokens encrypted with APP_KEY and fire an OAuthConnected event. AdobeSign::forUser($user) then acts with that user's account and refreshes tokens as needed.
  • A ready-made webhook endpoint. It answers Adobe's verification handshake within the 5-second limit, rejects unknown client ids, drops retried duplicates and fires a WebhookReceived event for your queued listeners.
  • A credentials check. php artisan adobe-sign:verify calls Acrobat Sign and prints who the key or token belongs to.

A first taste

Here is a contract going out from a controller through the facade. The client already knows your Integration Key, your cache store and your project's default signature level, so the code only describes the business process.

app/Http/Controllers/ContractController.php
use Conceptlz\AdobeSign\Builder\{AgreementInfo, FileInfo, ParticipantSetInfo, WebhookInfo};
use Conceptlz\AdobeSign\Laravel\Facades\AdobeSign;
use Conceptlz\AdobeSign\Webhook\EventType;

public function store(Request $request): JsonResponse
{
    $pdf = $request->file('contract');
    $documentId = AdobeSign::transientDocuments()->upload($pdf->getRealPath(), 'msa.pdf', 'application/pdf');

    $agreementId = AdobeSign::agreements()->create(
        AgreementInfo::create('Master Services Agreement')
            ->file(FileInfo::transientDocument($documentId))
            ->participantSet(ParticipantSetInfo::signer('client@example.com')->order(1))
            ->participantSet(ParticipantSetInfo::signer('ceo@example.com')->order(2)),
    );

    AdobeSign::webhooks()->create(
        WebhookInfo::forAgreement("Agreement $agreementId", route('adobe-sign.webhook'), $agreementId)
            ->events(EventType::AGREEMENT_ALL),
    );

    return response()->json(['agreement_id' => $agreementId], 201);
}

When everyone has signed, Adobe calls the package's webhook route. The package acknowledges Adobe straight away and fires an event; your queued listener does the slow work:

app/Listeners/StoreSignedContract.php
use Conceptlz\AdobeSign\Laravel\Events\WebhookReceived;
use Conceptlz\AdobeSign\Webhook\AgreementEvent;
use Illuminate\Contracts\Queue\ShouldQueue;

final class StoreSignedContract implements ShouldQueue
{
    public function handle(WebhookReceived $received): void
    {
        if ($received->event instanceof AgreementEvent && $received->event->isWorkflowCompleted()) {
            DownloadSignedAgreement::dispatch($received->event->agreementId());
        }
    }
}

The download job re-checks the status with the API and streams the signed PDF into any Laravel disk. The walkthrough builds the whole loop step by step.

Features

  • .env configurationIntegration Key or OAuth, signature level, qualified issuers, cache store, log channel and webhook client ids, all with sensible defaults. See Configuration.
  • Facade & injectionThe AdobeSign facade forwards to AdobeSignManager; type-hinting the core AdobeSign class gives you the default client.
  • OAuth connect routesadobe-sign.oauth.redirect and adobe-sign.oauth.callback, behind web and auth, with single-use state and an OAuthConnected event.
  • Encrypted token tableadobe_sign_tokens keeps each user's access and refresh token encrypted with APP_KEY. Tokens refresh automatically and are written back.
  • Webhook endpointGET|POST /adobe-sign/webhook: client-id allow-list, the echo Adobe requires, 72-hour duplicate suppression and a typed WebhookReceived event.
  • Signature levelsSet SES, AES or QES for the whole project in .env, then check the result with AdobeSign::signatureShortfalls($id).
  • Production-friendlyThe manager is bound scoped, so it is rebuilt per Octane request and per queued job. The data-centre lookup is cached in your Laravel cache store.
  • TestableBind any PSR-18 client in the container and every request goes to it instead of Guzzle. Post a fake webhook to the route and assert on the event. See Testing.

How it fits together

Your application talks to the facade or the injected client. The bridge builds that client from config and Laravel services, and owns the two HTTP entry points Adobe and your users hit. Everything that speaks to Acrobat Sign lives in the core.

Your app controllers, jobs, listeners adobe-sign-laravel AdobeSign facade / manager config/adobe-sign.php OAuth routes + token table webhook route → events adobe-sign:verify Core SDK conceptlz/ adobe-sign Acrobat Sign webhooks, OAuth redirects
The bridge configures the core client and owns the routes Adobe and your users call back on. API logic stays in the core.

The core package and its documentation

Installing this package pulls in conceptlz/adobe-sign. Both packages share one version number (currently 0.4.0) and are always released together, and the bridge requires the core at ^0.4. All builders (AgreementInfo, ParticipantSetInfo, FileInfo, WebhookInfo, Verification), resources (agreements(), transientDocuments(), webhooks(), …), models and exceptions come from the core and are documented in the core SDK documentation. This site covers what is specific to Laravel and shows the core calls in a Laravel setting.

You want to…Read
Install, configure and verify credentials in LaravelInstallation, Configuration
Use the facade, inject the client, act as another userUsing the client
Let each user connect their own Acrobat Sign accountOAuth
Receive signing progress in queued listenersWebhooks
Learn every builder option, identity checks, downloadsCore: Creating agreements, Identity verification, Downloads
Understand SES, AES and QES in legal termsCore: Signature levels

Requirements

  • PHP 8.2 or newer.
  • Laravel 12 or 13 (illuminate/* ^12.0 || ^13.0). The test suite runs on both.
  • An Acrobat Sign account. A free developer account is enough to build and test; its agreements are marked as demo documents.
  • A database table only if you use OAuth (for the tokens), and a public HTTPS URL only if you receive webhooks.

Where next