NextPDF Connect in production
At a glance
Section titled “At a glance”A production NextPDF Connect deployment gives you several operating controls: health and readiness probes, synchronous and asynchronous render paths, idempotency, per-client and per-Internet Protocol (IP) rate limits, and optional stateful sessions. Use this page to run them with predictable behavior.
Install
Section titled “Install”composer require nextpdf/serverConceptual overview
Section titled “Conceptual overview”The Representational State Transfer (REST) transport is a PHP Standards Recommendation (PSR)-15 middleware pipeline. Each request moves through middleware in order: request-id assignment, body-size limits, Cross-Origin Resource Sharing (CORS), authentication, capability authorization, rate limiting, idempotency, and timeout. The request then reaches a handler. The gRPC transport reuses the same application services behind the RoadRunner gRPC worker.
Rendering has two paths. A synchronous POST /api/v1/render runs the
operations and returns the Portable Document Format (PDF) file in the
response. An asynchronous job uses POST /api/v1/jobs. It returns
immediately with a job id, and you fetch the result later from
GET /api/v1/jobs/{id}/result. Jobs persist in a shared SQLite store, so
any worker can answer a status or result query.
API surface
Section titled “API surface”Health and readiness
Section titled “Health and readiness”| Endpoint | Auth | Meaning |
|---|---|---|
GET /healthz | none | The process is running |
GET /readyz | none | The server is ready to accept requests |
Wire /healthz to a liveness probe and /readyz to a readiness probe.
Both endpoints are anonymous, so orchestrators do not need credentials.
Async jobs
Section titled “Async jobs”| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/jobs | POST | Submit a render job |
/api/v1/jobs/{id} | GET | Job status |
/api/v1/jobs/{id}/result | GET | Job result (the PDF) |
/api/v1/jobs/{id} | DELETE | Cancel a job |
Sessions (opt-in)
Section titled “Sessions (opt-in)”When NEXTPDF_SESSIONS_ENABLED is true and tools are available, the
session endpoints provide a stateful build flow. You create a session, add
pages, text, images, tables, and HyperText Markup Language (HTML), set the
font, then render. Sessions have a per-client cap and an idle timeout.
They are off by default.
Code sample — Quick start
Section titled “Code sample — Quick start”Submit an async job and poll for the result:
JOB=$(curl -sS -X POST http://localhost:8080/api/v1/jobs \ -H "Authorization: Bearer $NEXTPDF_KEY" \ -H 'Content-Type: application/json' \ -d '{"operations":[{"type":"add_text","text":"async render"}]}' \ | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
curl -sS "http://localhost:8080/api/v1/jobs/$JOB/result" \ -H "Authorization: Bearer $NEXTPDF_KEY" --output out.pdfCode sample — Production
Section titled “Code sample — Production”Make a submission safe to retry by sending an idempotency key:
curl -sS -X POST http://localhost:8080/api/v1/jobs \ -H "Authorization: Bearer $NEXTPDF_KEY" \ -H 'Idempotency-Key: 7b1c2d3e-…' \ -H 'Content-Type: application/json' \ -d '{"operations":[{"type":"add_text","text":"safe retry"}]}'A request replayed with the same idempotency key returns the original outcome instead of creating a second job. That makes the submission safe to repeat after a communication failure. This matches the property an idempotent method provides: sending the same request again has the same intended effect as sending it once (RFC 9110 §9.2.2). The request can therefore be retried automatically if the connection drops before the client reads the response (RFC 9110 §9.2.2).
Edge cases and gotchas
Section titled “Edge cases and gotchas”-
Rate limiting needs Redis to be correct across workers. The per-client and per-IP limiters use the configured store. With the in-memory store and more than one worker, each worker counts requests independently, and the effective limit is multiplied by the worker count. Use the Redis store for any multi-worker pool.
-
A throttled request returns
429. When a limit is exceeded, the server responds with429 Too Many Requestsand aRetry-Afterheader, following the rate-limit status semantics (RFC 6585 §4). HonorRetry-After; do not retry immediately. -
Job results are not infinite. The job store garbage-collects old entries after
NEXTPDF_JOB_GC_MAX_AGE_SECONDS. Fetch results before they age out. -
Sessions cost memory. A session holds an in-progress document. The per-client session cap and idle timeout bound this cost. Do not raise them without sizing memory for the worst case.
Performance
Section titled “Performance”The synchronous path holds a worker for the full render. For large or slow renders, use the async job path. It frees the worker immediately, and the client polls for the result. Size the worker pool against observed render latency and concurrency. Watch the RoadRunner metrics endpoint.
Security notes
Section titled “Security notes”Every endpoint except the health probes requires a valid application programming interface (API) key. The client’s tier controls which operations and payload sizes are allowed. Clients supply idempotency keys. Treat each key as opaque and unique to one logical operation. See /connect/security-and-operations/.
Conformance
Section titled “Conformance”| Claim | Source | reference_id |
|---|---|---|
| Idempotent: repeated requests = one effect | RFC 9110 §9.2.2 | |
| Idempotent requests retryable after failure | RFC 9110 §9.2.2 | |
429 + Retry-After for rate limiting | RFC 6585 §4 |
Commercial context
Section titled “Commercial context”Pro and Enterprise keys get higher per-tier payload and timeout ceilings when those tools are installed. A default deployment uses the core-tier ceilings.
See also
Section titled “See also”- /connect/deployment/ — worker pools, Redis, RoadRunner profiles
- /transports/rest/ — the full middleware pipeline and OpenAPI contract
- /connect/troubleshooting/ — diagnosing 401/403/413/429/5xx and store failures
- /connect/security-and-operations/ — authentication and rate-limit posture