Render manifest: the portable render request
At a glance
Section titled “At a glance”A render manifest is the portable description of what to render: input, template, fonts, locale, conformance profile, signature policy, output target, and a Fast-Web-View flag. Every transport builds and submits the same RenderManifest, whether it is a command-line interface (CLI), a framework integration, a software-as-a-service (SaaS) application programming interface (API), or a future stream connector. The contract is deterministic: two equal manifests serialize to byte-identical JavaScript Object Notation (JSON), and each manifest carries a derived idempotency key so downstream systems can recognize and deduplicate the same render.
The manifest is a Core contract. It defines the schema; the engine and the premium stream processor execute the request.
Install
Section titled “Install”composer require nextpdf/core:^3Building a manifest
Section titled “Building a manifest”Use the builder as the stable construction path, or use RenderManifest::fromArray() for a deserialized manifest. The raw constructor is @internal: new optional fields are appended with defaults, so the builder and fromArray() absorb them without breaking your call sites.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Manifest\OutputObjectKey;use NextPDF\Manifest\RenderManifestBuilder;use NextPDF\Manifest\TemplateRef;
$manifest = RenderManifestBuilder::create('invoice-2026-0001') ->withInlineInput('<h1>Invoice 2026-0001</h1>') ->withTemplate(TemplateRef::html()) ->withOutputKey(OutputObjectKey::file('invoices', '2026-0001.pdf')) ->withLocale('en-US') ->linearized() ->build();
// Deterministic, canonical-key-order JSON — equal manifests are byte-identical.$json = $manifest->toJson();Fields
Section titled “Fields”| Field | Meaning |
|---|---|
jobId | Caller-stable logical identifier, echoed in events and receipts. Excluded from the idempotency key. |
idempotencyKey | Deterministic deduplication key (see below). |
input | Render data source: inline payload, a Uniform Resource Identifier (URI), or a dataset reference plus content hash. |
template | The rendering front end and an optional template identifier. |
fonts | Declared font set (empty by default). |
locale | A BCP-47 language tag (en-US by default). |
conformanceProfile | A stable profile identifier (none by default). |
signaturePolicy | A stable policy identifier (none by default). |
target | Output object key, format, and clobber policy. |
linearize | Fast-Web-View flag; composes with linearization. |
metadata | Opaque scalar key/value map echoed into events. |
Idempotency key
Section titled “Idempotency key”IdempotencyKey::derive() hashes only the render-determining subset of the manifest: template, input content hash, fonts, locale, conformance, signature policy, the linearize flag, and the target key. It deliberately excludes jobId and metadata, so two requests with identical render-determining inputs, including the output target, share a key and can be deduplicated even when their job identifiers or tracking metadata differ. A caller may also supply an explicit key; isDerived() reports which path produced it.
Schema versioning
Section titled “Schema versioning”RenderManifest::SCHEMA_VERSION pins the schema version (currently 1.0). Within a major version, evolution is additive-only: a reader tolerates unknown keys from a newer minor schema, but rejects a newer major version. SchemaCompatibility::assertReadable() enforces this in fromArray(), and canRead() / isForwardRead() let you test compatibility without throwing.
Because the manifest is a readonly data transfer object (DTO) whose constructor is @internal, build it through the builder or fromArray(). New fields are added as defaulted constructor parameters, so adding a field does not break those call sites.
Validation
Section titled “Validation”RenderManifestValidator::validate() is non-throwing and collect-all: it returns every problem it finds instead of failing on the first one. It rejects unsafe output keys (traversal, absolute paths, stream wrappers), more than one input source, an unknown conformance profile identifier, an invalid BCP-47 locale, and a clobber-policy mismatch. warnings() returns advisory, non-blocking notes.
use NextPDF\Manifest\RenderManifestValidator;
$problems = (new RenderManifestValidator())->validate($manifest);
if ($problems !== []) { // Each entry is a stable, human-readable problem string.}Rendering a manifest
Section titled “Rendering a manifest”SingleDocumentRenderer turns one manifest into one Portable Document Format (PDF) deterministically. It is pure: it returns bytes plus their sha-256 digest and writes no file, so staging and exactly-once commit stay the caller’s (or the stream processor’s) concern.
use NextPDF\Manifest\Render\SingleDocumentRenderer;use NextPDF\Manifest\Render\StandaloneDocumentFactory;
$renderer = new SingleDocumentRenderer(new StandaloneDocumentFactory());$outcome = $renderer->render($manifest);
$bytes = $outcome->bytes;$digest = $outcome->sha256;$pages = $outcome->pageCount;API surface
Section titled “API surface”| Type | Kind | Key members | Stability | Since |
|---|---|---|---|---|
RenderManifest | readonly DTO | toArray(), toJson(), fromArray(), canonicalDigestInput(), SCHEMA_VERSION | stable | 3.2.0 |
RenderManifestBuilder | builder | create(), with*(), linearized(), build() | stable | 3.2.0 |
IdempotencyKey | value object | of(), derive(), equals(), isDerived() | stable | 3.2.0 |
SchemaCompatibility | helper | canRead(), isForwardRead(), assertReadable() | stable | 3.2.0 |
RenderManifestValidator | service | validate(), warnings() | stable | 3.2.0 |
SingleDocumentRenderer | service | render(): RenderOutcome | stable | 3.2.0 |
fromArray() throws RenderManifestException when a required field is missing or the schema version is unreadable.