Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Adobe Sign Bundle Laravel Package

postyou/adobe-sign-bundle

A Symfony bundle that integrates Adobe Sign (formerly EchoSign) into your application, providing service configuration and a client wrapper for sending agreements, managing signing workflows, and handling Adobe Sign API calls.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle (postyou/adobe-sign-bundle) targeting the Adobe Acrobat Sign REST API — it is not a Laravel package and has no service provider or facade. The framework-agnostic service classes work fine inside Laravel, but you wire them yourself.

Minimal steps:

  1. composer require postyou/adobe-sign-bundle — and pin the exact patch version ("0.0.15"), since this is still a 0.0.x release line.
  2. Read the bundle's Resources/config/services.yaml first. That file tells you the real service IDs, constructor arguments, and which classes are public — more useful than the README for figuring out what you can actually inject or resolve.
  3. In Laravel, create a small AdobeSignServiceProvider that reads config/services.php (client_id, client_secret, redirect_uri, scopes, api_host) and binds the bundle's client class as a singleton, passing the config explicitly rather than relying on Symfony's container.
  4. Authenticate once via the OAuth authorization-code flow (this is an interactive, one-time-per-account step in the sandbox). Persist the resulting access and refresh token — you cannot do anything else until you have a token.
  5. First real use case: upload a PDF as a transient document → POST /agreements with a SEND state → poll or wait for the webhook. That single flow exercises auth, file upload, error handling, and status polling, which is 90% of what you'll build.

New in v0.0.15: AdobeErrorResponseException. This is the exception you should design your error handling around from day one — it represents a well-formed error returned by Adobe (4xx/5xx with an error body), as opposed to transport/network failures. Start by writing your first try/catch against it before you write the happy path; retrofitting typed error handling into a growing integration is painful.

Implementation Patterns

Wrap, don't inject, the client everywhere. Bind the bundle client to a Laravel singleton and expose it through your own thin AdobeSign class. Every call site then depends on your class, so a breaking change in the bundle's method signatures (likely at this version) touches one file.

Proactive token refresh. Adobe access tokens are short-lived (~1 hour). Store expires_at, and refresh when now() > expires_at - 5 minutes. Adobe rotates the refresh token — if you don't persist the new one returned by the refresh call, you lose the account until someone re-authorizes manually. Do this inside a cached job/lock so concurrent requests don't race the same rotating refresh token.

Queue everything that sends. Agreement creation, sending, and reminder updates should be queued jobs with $tries = 3 and exponential backoff. Adobe calls can take several seconds and you do not want a 30s HTTP request inside a web request handler.

Centralized error translation. Catch AdobeErrorResponseException in one place (an exception handler mapping or a wrapper around every client call) and map Adobe's code field to domain outcomes:

Adobe code Typical cause Your handling
INVALID_ACCESS_TOKEN expired/revoked token refresh once, retry
PERMISSION_DENIED scopes or sender not authorized surface to user
INVALID_FILE_TYPE / MISSING_DOCUMENT bad upload 422 to user, no retry
RATE_LIMITED / 429 burst back off, honor Retry-After

Keep the raw error payload (code, message, requestId) on the exception's context when you log or rethrow.

Webhook-first status. Don't poll for agreement status in production. Register a webhook, dispatch a job from the controller, and only fall back to polling (GET /agreements/{id}) for reconciliation and for records that never got a webhook.

Test with fake HTTP, not the sandbox. Use Laravel's Http::fake() or a Guzzle MockHandler to replay recorded Adobe responses — including a recorded error body so you can assert your v0.0.15 exception path actually fires. Sandbox integration tests are slow, rate-limited, and will flake in CI.

Gotchas and Tips

  • 0.0.x means no BC guarantees. Adding a new exception class is a green flag, but the comparison URL shows they're incrementing the patch digit for everything — feature additions included. Pin exact versions and read the diff between pins; assume any release can change a method signature.
  • The new exception probably isn't a catch-all. AdobeErrorResponseException almost certainly fires only when Adobe returns a parseable error body. Network timeouts, DNS failures, and HTML error pages from a proxy will surface as the underlying HTTP client exception instead. Catch both, and don't catch (\Throwable) around the client or you'll swallow programming errors.
  • API host and shard matter. Sandbox vs. production, and na1/eu1/jp1 are different base URLs. A wrong shard returns a confusing auth or 404 error that looks like a credentials problem. Make the host a config value, not a hardcoded constant.
  • fileInfos vs. transientDocumentId vs. libraryDocumentId are mutually exclusive input shapes on agreement creation. This is the single most common source of 400 responses when integrating; validate you're sending exactly one.
  • Don't log full payloads. Agreement payloads and OAuth responses contain PII and bearer tokens. Log the Adobe requestId header and correlate — that's what Adobe support will ask for.
  • Extension point: the bundle registers its client as a container service. Decorate/override it in your service provider rather than editing vendor/. When the next 0.0.x bump rearranges the service definition, your override is the one place to fix.
  • Debugging tactic: when an error is opaque, reproduce the exact request with curl using the same token. If curl works and the bundle fails, the problem is serialization/headers (very often a multipart/form-data vs. application/json mix-up on part uploads) rather than credentials.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource