Start here
Installation
From composer require to a verified connection in about five minutes. By the end of this page your app can call Acrobat Sign with an Integration Key, or is ready for users to connect their own accounts through OAuth.
Requirements
| Needs | Version or detail |
|---|---|
| PHP | 8.2 or newer |
| Laravel | 12 or 13 (illuminate/* ^12.0 || ^13.0) |
| Core SDK | conceptlz/adobe-sign ^0.4, installed for you |
| HTTP client | Any PSR-18 client. Laravel already ships Guzzle, so there is nothing to add. |
| Database table | Only for OAuth (adobe_sign_tokens) |
| Acrobat Sign account | Any plan, including a free developer account |
Install in five steps
-
Require the package
composer require conceptlz/adobe-sign-laravelThis also installs the core SDK at the matching version. Both packages are released together with one version number, so you never have to line them up yourself.
-
Let auto-discovery register it
The package's
composer.jsondeclares the service providerConceptlz\AdobeSign\Laravel\AdobeSignServiceProviderand the facade aliasAdobeSign, so Laravel picks both up with no code changes. If your app turns off discovery for this package (dont-discover), add the provider tobootstrap/providers.phpyourself. -
Publish the config (optional)
php artisan vendor:publish --tag=adobe-sign-configThis copies
config/adobe-sign.phpinto your app. You only need it to change values that have no.envvariable, such as route prefixes, middleware or the retry limits. The package merges its defaults, so a key you leave out of your copy still has a value. -
Publish and run the migration (OAuth only)
php artisan vendor:publish --tag=adobe-sign-migrations php artisan migrateThis creates the
adobe_sign_tokenstable where each user's OAuth tokens are stored, encrypted withAPP_KEY. The package does not load its migration automatically, so nothing touches your database until you publish it. Skip this step if you only use an Integration Key. -
Add credentials and verify
Set the
.envkeys described below, then run:php artisan adobe-sign:verify
Integration Key or OAuth?
Acrobat Sign has two ways to authenticate API calls. The choice is about whose account sends the agreements, not about security level; both are fine for production.
| Integration Key | OAuth 2.0 | |
|---|---|---|
| Sender | One Acrobat Sign account (yours) | Each user's own Acrobat Sign account |
| Typical app | Internal tools, a SaaS that sends from its own account | A product where customers bring their own Acrobat Sign |
| Setup | One .env value | An API application at Adobe, a redirect URI, the token table |
| Expiry | Does not expire; revoke it in Acrobat Sign | Access tokens last about an hour and refresh automatically; refresh tokens lapse after 60 days without use |
| Bridge API | AdobeSign::agreements(), injected AdobeSign | AdobeSign::forUser($user), or the default client with ADOBE_SIGN_AUTH=oauth |
You can use both in one app: an Integration Key as the default client, and forUser() for users who connected their own account.
.env for an Integration Key
Create the key in Acrobat Sign under Account → Acrobat Sign API → API Information → Integration Key. Adobe asks which scopes the key may use; enable the ones your app needs (reading, writing and sending agreements, and webhooks if you receive them). Then:
ADOBE_SIGN_INTEGRATION_KEY=3AAABLblqZhB...your-key...
# Only if you receive webhooks: the client id(s) Adobe sends in X-AdobeSign-ClientId
ADOBE_SIGN_WEBHOOK_CLIENT_IDS=
ADOBE_SIGN_AUTH defaults to integration_key, so that single line is enough to make the facade work.
.env for OAuth
Create an API application in Acrobat Sign (Account → Acrobat Sign API → API Applications),
note its client id and secret, and add your callback URL as a redirect URI in the application's OAuth
configuration. The package's callback route is /adobe-sign/oauth/callback.
ADOBE_SIGN_CLIENT_ID=CBJCHBCAABAA...
ADOBE_SIGN_CLIENT_SECRET=your-client-secret
# Optional: defaults to route('adobe-sign.oauth.callback'), e.g. https://app.example.com/adobe-sign/oauth/callback
ADOBE_SIGN_REDIRECT_URI=
# Optional: make the facade and injected client use the signed-in user's connection
ADOBE_SIGN_AUTH=oauth
With OAuth configured, the webhook allow-list falls back to ADOBE_SIGN_CLIENT_ID, so
webhooks created through your OAuth app are accepted without further settings. The full flow is on
the OAuth page.
Keep the secrets out of Git
The Integration Key gives full API access to the account it belongs to, and the client secret lets anyone exchange codes for tokens. Keep both in .env or your secret manager, never in config/adobe-sign.php. The SDK redacts the Authorization header and OAuth secrets from every exception it throws.
Check the connection
adobe-sign:verify calls GET /users/me with the default
client and prints who the credentials belong to. It is the quickest way to tell a bad key from a
problem in your own code.
$ php artisan adobe-sign:verify
INFO Connected to Acrobat Sign.
User ............................................ admin@example.com
Account admin ................................................... yes
Account ...................................... CBJCHBCAABAAaccount1
On failure it prints the SDK's error message, including Adobe's error code, and exits non-zero, so you can also run it in a deploy pipeline. To check one user's OAuth connection instead of the default client, pass their token key (by default the user's id):
php artisan adobe-sign:verify --user=42
The first call also discovers your account's data centre (na1, eu1, …) and
stores it in your cache, so later requests skip that step.
The HTTP client (PSR-18)
The core SDK talks HTTP through the PSR-18 interface rather than a specific library. Every Laravel
app already has Guzzle 7, which implements PSR-18, and php-http/discovery finds it at
runtime. There is nothing to install or configure.
If you want a specific client (a proxy, custom timeouts, a client with extra middleware), bind it in
the container. The bridge uses a bound Psr\Http\Client\ClientInterface before falling
back to discovery:
use GuzzleHttp\Client;
use Psr\Http\Client\ClientInterface;
public function register(): void
{
$this->app->bind(ClientInterface::class, fn () => new Client([
'timeout' => 60, // large combined PDFs can take a while
'connect_timeout' => 10,
'proxy' => env('OUTBOUND_PROXY'),
]));
}
That binding is application-wide, so any other package that resolves ClientInterface
gets the same client. The same mechanism is how tests swap in a fake client; see
Testing.
Composer may ask about php-http/discovery
php-http/discovery is also a Composer plugin, and Composer asks whether to trust it the first time. Either answer works for a standard Laravel app: the plugin only installs missing PSR implementations, and Laravel already has them. Record your answer under config.allow-plugins in composer.json so CI doesn't ask again.
Upgrading
Update both packages together so the bridge and the core stay on the same release:
composer update conceptlz/adobe-sign-laravel conceptlz/adobe-sign
While the version is below 1.0, a minor bump (0.4 → 0.5) can contain breaking changes, and the
bridge's ^0.4 constraint keeps you on 0.4.x until you change your own constraint. Read
the changelog before moving to a new minor version. If you published the config file, compare it with
the package's copy after upgrading, since new keys only reach your app through the merged defaults.
Common questions
Do I need the migration if I only use an Integration Key?
No. The adobe_sign_tokens table only stores OAuth tokens. With an Integration Key the package never touches the database. If you later add OAuth, publish and run the migration then.
Do I have to publish the config file?
No. The package merges its own config/adobe-sign.php, and the important values come from .env. Publish it when you need to change keys that have no environment variable, such as oauth.route_prefix, webhooks.path or retries.max. See Configuration.
adobe-sign:verify says MisconfiguredException. What is missing?
The message names the missing setting: usually ADOBE_SIGN_INTEGRATION_KEY, or OAuth client credentials when ADOBE_SIGN_AUTH=oauth. With ADOBE_SIGN_AUTH=oauth the command has no signed-in user, so check a specific connection with --user=. If you cache config, run php artisan config:clear after editing .env. More in Troubleshooting.
Do I need to install Guzzle or another HTTP library?
No. Laravel requires Guzzle, which implements PSR-18, and the SDK discovers it automatically. Bind your own Psr\Http\Client\ClientInterface only if you need custom options such as a proxy.
Does it work with Lumen or Laravel 11?
The package supports Laravel 12 and 13 only, which is what CI tests. On other frameworks, including older Laravel versions, use the framework-agnostic core SDK directly; it only needs PSR interfaces.