Skip to content
getnextpdf.com

Pro edition

NextPDF Pro quick start

You have a NextPDF Pro license envelope. This tutorial turns it into a first verified result in four short steps. You install nextpdf/pro from the private repository, activate your license, confirm the entitlement the runtime resolved, then render a templated PDF and sign it. Each step shows the output you should see.

This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.

  • PHP 8.4 and Composer 2. The premium packages require PHP >=8.4 <9.0.
  • Private repository credentials. Your portal issues a repository URL, username, and token. Setup is covered in Install and authenticate.
  • Your license envelope. Sign in to your account at app.getnextpdf.com, sign the license agreement, and download the signed envelope for your deployment. Treat it like an API key.
  • ionCube Loader (encoded builds only). The Pro trial and the paid, ionCube-encoded Pro build need the Loader for PHP 8.4 — see ionCube setup.

Point Composer at your private repository, authenticate, and require the package:

Terminal window
composer config repositories.nextpdf composer https://repo.example.com/nextpdf
composer config --auth http-basic.repo.example.com your-username your-token
composer require nextpdf/pro:^3

Substitute the repository URL and credentials from your portal. All three authentication methods (project auth.json, COMPOSER_AUTH, global auth) are described in Install and authenticate.

Next, place the signed license envelope where your deployment loads it, following your configuration convention, and run your integration’s activation step — most frameworks expose it as a console command. Under the hood, online activation is one call on the licensing surface:

public function activate(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponse

Throws or fails with: NextPDF\Enterprise\Licensing\LicenseClientException on a transport failure, a non-200 status, or a bad supplied nonce, and NextPDF\Accelerator\Exception\SpectrumAuthenticationException on any signed-status verification failure. On the ionCube channel the license also verifies periodically online; the signed-source channel verifies locally — see Two delivery channels.

Ask the entitlement evaluator — the single authority for license decisions — what your envelope resolved to. $license is the verified NextPDF\Enterprise\Licensing\LicenseKey your integration’s licensing bootstrap exposes; null shows the fail-closed no-license result.

use NextPDF\Enterprise\Licensing\EntitlementEvaluator;
$result = (new EntitlementEvaluator())->evaluate($license);
printf("status: %s\n", $result->status->value);
printf("edition: %s\n", $result->edition?->value ?? '(none)');
printf("channel: %s\n", $result->channel->value);
printf("branding: %s\n", $result->brandingMode->value);
printf("runtime: %s\n", $result->runtimeAllowed ? 'allowed' : 'disabled');

The method behind it (it does not throw):

public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResult

With an active paid Pro license, expect:

status: active
edition: pro
channel: paid
branding: none
runtime: allowed

On a trial or evaluation grant, expect channel: evaluation and branding: evaluation instead. Every Pro capability still runs, and rendered output carries a visible evaluation watermark by design. A paid license removes it with no code change — see Trial and evaluation branding.

Now the fun part: parse a JSON template, bind your data with type-aware formatting, render the bound values, and sign the document. Save this as quickstart.php next to your vendor/ directory and run php quickstart.php. You need a signing certificate as a PKCS#12 file (signing-cert.p12); a self-signed one is fine for this tutorial. Production signing needs a properly protected private key, a real certificate chain, and a trust policy your recipients accept — self-signed signatures are not suitable for trusted recipient workflows.

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Pro\Template\TemplateDataBinder;
use NextPDF\Pro\Template\TemplateParser;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
// Parse a JSON template: one A4 page, three positioned placeholders.
$template = (new TemplateParser())->parse(<<<'JSON'
{
"name": "welcome-letter",
"pageSize": "A4",
"orientation": "P",
"placeholders": [
{"name": "customer", "type": "text", "x": 25, "y": 60, "width": 160, "height": 10},
{"name": "issued", "type": "date", "x": 25, "y": 72, "width": 80, "height": 10},
{"name": "total", "type": "currency", "x": 25, "y": 84, "width": 80, "height": 10, "format": "EUR "}
]
}
JSON);
// Bind data. Keys match placeholder names case-insensitively.
$binding = (new TemplateDataBinder())->bind($template, [
'customer' => 'Aurora Paper Co.',
'issued' => '2026-07-03',
'total' => 1249.5,
]);
printf(
"Bound %d of %d placeholders (%d missing, %d warnings)\n",
$binding->count(),
count($template->placeholders),
count($binding->missingFields),
count($binding->warnings),
);
// Render the bound values with the Core document API.
$doc = Document::createStandalone();
$doc->setTitle('Welcome letter');
$doc->addPage();
$doc->setFont('helvetica', '', 12);
foreach ($binding->bindings as $bound) {
$doc->text($bound->placeholder->x, $bound->placeholder->y, $bound->formattedValue);
}
// Apply a PAdES B-B baseline signature, then save once.
$doc->setSignature(
CertificateInfo::fromPkcs12(__DIR__ . '/signing-cert.p12', (string) getenv('NEXTPDF_P12_PASSWORD')),
SignatureLevel::PAdES_B_B,
);
$doc->save(__DIR__ . '/welcome-letter-signed.pdf');
echo "Created: welcome-letter-signed.pdf\n";

Expected output:

Bound 3 of 3 placeholders (0 missing, 0 warnings)
Created: welcome-letter-signed.pdf

Open welcome-letter-signed.pdf in a PDF reader: the three bound values appear at their template positions (issued formatted Y-m-d, total as EUR 1,249.50), and the reader’s signature panel shows one signature. The emitted structure follows the PAdES baseline B-B profile; scope and conformance posture are on the PAdES levels page. If the template JSON is malformed, TemplateParser::parse() throws InvalidArgumentException with a message prefixed Template validation failed:.

The key signatures you just used, verbatim:

public function parse(string $json): TemplateDefinition
public function bind(TemplateDefinition $template, array $data): BindingResult
public static function fromPkcs12(string $p12Path, #[SensitiveParameter] string $password = ''): self
public function setSignature(CertificateInfo $certInfo, SignatureLevel $level = SignatureLevel::PAdES_B_B, ?TsaClient $tsaClient = null, ?ClientInterface $httpClient = null): static
public function save(string $path): void

Throws or fails with: parse()InvalidArgumentException when the JSON is invalid or does not conform to the expected structure; fromPkcs12()NextPDF\Exception\SignatureException when the file cannot be read or parsed; setSignature()NextPDF\Exception\InvalidConfigException when linearization is already enabled (PAdES and Fast Web View are mutually exclusive); save()NextPDF\Exception\InvalidConfigException, NextPDF\Exception\PageLayoutException, or NextPDF\Exception\CompressionException when the file cannot be written. bind() does not throw; it reports missingFields and warnings instead.

A 401/403 during composer require, or “could not be found”, means the private repository or its credentials are not configured for this project. The host key in auth.json must match the repository URL’s host exactly. Work through Install and authenticate.

Step 2 prints status: no_license, runtime: disabled, and the evaluator’s warning — the raw premium-runtime message (shared by both editions) is: No license configured. Enterprise runtime is disabled. Install a license or purchase one at https://nextpdf.dev/pricing. Premium features fail closed without a verified envelope. A present-but-broken envelope file is never treated as absent — it raises NextPDF\Enterprise\Licensing\Storage\LicenseStorageException with messages such as License file is present but unreadable: ... or License file is present but empty: .... Place the envelope at the configured path and make it readable by the PHP process user.

CertificateInfo::fromPkcs12() throws NextPDF\Exception\SignatureException when the .p12 file cannot be read or parsed. The usual causes are a wrong path, a wrong password (check NEXTPDF_P12_PASSWORD), or a file that is not actually PKCS#12. Verify with openssl pkcs12 -info -in signing-cert.p12 -noout.