Skip to content

NextPDF Connect in production

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.

Terminal window
composer require nextpdf/server

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.

EndpointAuthMeaning
GET /healthznoneThe process is running
GET /readyznoneThe 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.

EndpointMethodPurpose
/api/v1/jobsPOSTSubmit a render job
/api/v1/jobs/{id}GETJob status
/api/v1/jobs/{id}/resultGETJob result (the PDF)
/api/v1/jobs/{id}DELETECancel a job

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.

Submit an async job and poll for the result:

Terminal window
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.pdf

Make a submission safe to retry by sending an idempotency key:

Terminal window
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).

  • 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 with 429 Too Many Requests and a Retry-After header, following the rate-limit status semantics (RFC 6585 §4). Honor Retry-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.

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.

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/.

ClaimSourcereference_id
Idempotent: repeated requests = one effectRFC 9110 §9.2.2
Idempotent requests retryable after failureRFC 9110 §9.2.2
429 + Retry-After for rate limitingRFC 6585 §4

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.

  • /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