API documentation
Base URL https://api.pagesmith.eu/api · every request is processed in memory and
shredded. Nothing is stored.
Authentication
All requests to the pagesmith API require an API key passed via the Authorization header:
Authorization: Bearer psk_live_...
Generate your API key in the dashboard. Keys require an active subscription.
POST /v1/fill
Fill AcroForm fields in a PDF from JSON data. Fields are optional; missing fields are skipped. Optionally flatten the form to bake the values into the page and remove the interactive fields.
Parameters
| Name | Type | Description |
|---|---|---|
file |
PDF file | The PDF to fill (multipart/form-data) |
data |
JSON object | Field names and values, e.g. {"name":"Jesper","subscribed":true} |
flatten |
boolean (optional) | Bake field values into the page and remove the interactive form. Default: false |
Flattening renders each field's value into the page content and removes the interactive form. The result has no fillable fields left. It cannot be un-flattened, so keep your source PDF if you need to edit the fields again.
Example
curl -s https://api.pagesmith.example/api/v1/fill \
-H "Authorization: Bearer psk_live_..." \
-F file=@contract.pdf \
-F 'data={"name":"Jesper","subscribed":true}' \
-F flatten=true -o filled.pdf
Response
HTTP 200 with the filled PDF file as binary content. Content-Type: application/pdf
POST /v1/pdfa/validate
Validate a PDF against PDF/A compliance standards using the veraPDF engine. Returns detailed rule-level results for archival readiness assessment.
Parameters
| Name | Type | Description |
|---|---|---|
file |
PDF file | The PDF to validate (multipart/form-data) |
profile |
string (optional) | PDF/A profile: 2b (default) or 3b |
Example
curl -s https://api.pagesmith.example/api/v1/pdfa/validate \
-H "Authorization: Bearer psk_live_..." \
-F file=@archive.pdf -F profile=2b
Response
HTTP 200 with JSON:
{
"compliant": true,
"profile": "2b",
"passedRules": 58,
"failedRules": 0,
"ruleSummaries": [
{
"ruleId": "6.1.2-1",
"specification": "ISO 19005-1:2005",
"description": "Font program embedded",
"status": "failed",
"failedChecks": 3
}
]
}
POST /v1/pdfa/convert
Convert any PDF to archival PDF/A using Ghostscript. The output must pass pagesmith's own PDF/A-validate engine for the requested profile before it's ever returned.
Parameters
| Name | Type | Description |
|---|---|---|
file |
PDF file | The PDF to convert (multipart/form-data) |
profile |
string (optional) | Target PDF/A profile: 2b (default) or 3b |
Example
curl -s https://api.pagesmith.example/api/v1/pdfa/convert \
-H "Authorization: Bearer psk_live_..." \
-F file=@scan.pdf -F profile=2b -o converted.pdf
Response
HTTP 200 with the converted PDF as binary content. Content-Type: application/pdf,
X-Pagesmith-Units: 3 (3 units per call).
Unparseable or otherwise unconvertible input returns 422 pdfa.not_convertible,
not pdf.corrupt. Convert's engine (Ghostscript) and validate's engine
(veraPDF) fail on different inputs in different ways; this is the one place that distinction
surfaces as a different error code.
POST /v1/seal
Apply a PAdES digital signature with your own PKCS#12 certificate. No signing authority, no pagesmith-issued identity. An invisible signature field is added to the PDF automatically, so it works on any PDF, not just one with an existing signature field.
Parameters
| Name | Type | Description |
|---|---|---|
file |
PDF file | The PDF to seal (multipart/form-data) |
certificate |
PKCS#12 file | Your signing certificate (.p12/.pfx). Provide this
or certificate_id, never both. |
certificate_id |
integer | A certificate previously uploaded to your dashboard
vault. Provide this or certificate, never both. |
passphrase |
string | Required. The certificate's PKCS#12 passphrase. Never stored, never logged, never passed on a command line. |
tsa_url |
string (optional) | RFC 3161 timestamp authority URL, for a timestamped signature |
reason |
string (optional) | Signing reason embedded in the signature, 120 characters or fewer |
Upload a PKCS#12 certificate once in the dashboard (it's
stored encrypted at rest) and reference it by certificate_id on every call instead of
re-uploading the file with every request. Passphrases are never stored, either way.
Example
curl -s https://api.pagesmith.example/api/v1/seal \
-H "Authorization: Bearer psk_live_..." \
-F file=@contract.pdf \
-F certificate_id=4 \
-F passphrase="correct horse battery staple" \
-F reason="Approved by finance" -o sealed.pdf
Response
HTTP 200 with the sealed PDF as binary content. Content-Type: application/pdf,
X-Pagesmith-Units: 3 (3 units per call).
POST /v1/merge
Merge 2–10 PDFs into a single document, in the order submitted.
Parameters
| Name | Type | Description |
|---|---|---|
files[] |
PDF files (2–10) | The PDFs to merge, in order (multipart/form-data) |
Example
curl -s https://api.pagesmith.example/api/v1/merge \
-H "Authorization: Bearer psk_live_..." \
-F files[]=@cover.pdf -F files[]=@contract.pdf -F files[]=@appendix.pdf \
-o merged.pdf
Response
HTTP 200 with the merged PDF as binary content. Content-Type: application/pdf,
X-Pagesmith-Units: 1 (1 unit per call, regardless of file count).
POST /v1/stamp
Stamp text onto every page of a PDF: page numbers, watermarks, draft marks.
Parameters
| Name | Type | Description |
|---|---|---|
file |
PDF file | The PDF to stamp (multipart/form-data) |
text |
string | Required. Stamp text, 200 characters or fewer |
position |
string (optional) | One of center, top, bottom. Default:
bottom |
opacity |
float (optional) | 0.05–1. Default: 0.3 |
Example
curl -s https://api.pagesmith.example/api/v1/stamp \
-H "Authorization: Bearer psk_live_..." \
-F file=@draft.pdf -F text="DRAFT internal review" -F position=top -F opacity=0.4 \
-o stamped.pdf
Response
HTTP 200 with the stamped PDF as binary content. Content-Type: application/pdf,
X-Pagesmith-Units: 1 (1 unit per call).
Async processing
Add async=1 to any of /v1/fill, /v1/pdfa/convert,
/v1/seal, /v1/merge, or /v1/stamp to run the same operation as a
background job instead of waiting for the response inline. Useful for large files or slower operations
like convert and seal.
Parameters
| Name | Type | Description |
|---|---|---|
async |
boolean | Set to 1 to run the operation asynchronously |
webhook_url |
string (optional) | URL pagesmith POSTs {"id": "...", "status": "..."} to once the job reaches a
terminal state (done or failed). Best-effort; never retried. |
Example
curl -s https://api.pagesmith.example/api/v1/seal \
-H "Authorization: Bearer psk_live_..." \
-F file=@contract.pdf -F certificate_id=4 -F passphrase="..." \
-F async=1 -F webhook_url=https://example.com/hooks/pagesmith
{"id": "01j...", "status": "queued", "status_url": "https://api.pagesmith.example/api/v1/jobs/01j..."}
GET /v1/jobs/{id}
Poll (or wait for the webhook, then call) the job's status_url:
- HTTP 200
{"id": "...", "status": "queued"}or"status": "processing"while the job is still running. application/problem+json, at the operation's original error status, if the jobfailed: the same body the synchronous call would have returned.- HTTP 200 with the result file as binary content (
Content-Type: application/pdf) once the job isdone. - HTTP 404
job.not_foundfor an unknown job id, or one belonging to another account.
Async inputs and results are encrypted at rest and expire after 1 hour. A
done result is deleted the instant you fetch it via GET /v1/jobs/{id};
you can only collect it once. Nothing else about a document is ever persisted: job rows carry no
filenames.
Error responses
All errors are returned as application/problem+json with a stable code field for
programmatic handling.
Error codes
| Code | Status | Meaning |
|---|---|---|
auth.invalid_key | 401 | API key is missing or invalid |
subscription.required | 402 | Account has no active subscription |
subscription.past_due | 402 | Subscription payment is past due |
request.too_large | 413 | File exceeds maximum size (20 MB) |
request.unsupported_media_type | 415 | Request content type is not supported |
request.validation | 422 | Request validation failed (missing or invalid parameters) |
form.no_acroform | 422 | PDF has no form fields (AcroForm) |
form.field_unknown | 422 | A requested field does not exist in the PDF |
pdf.encrypted | 422 | PDF is password-protected or encrypted |
pdf.corrupt | 422 | PDF structure is invalid or corrupt |
pdfa.not_convertible | 422 | PDF could not be converted to PDF/A |
seal.cert_invalid | 422 | Certificate could not be read, or the passphrase is wrong |
seal.cert_expired | 422 | Certificate has expired |
seal.tsa_unreachable | 422 | Timestamp authority could not be reached |
job.not_found | 404 | Async job does not exist, or belongs to another account |
rate_limit.exceeded | 429 | Too many requests; rate limit exceeded |
internal.engine_timeout | 504 | Processing engine timed out (try again) |
internal.engine_failure | 500 | the validation engine returned no usable result (rare; retry or contact support) |
internal.error | 500 | Unexpected server error |
Example error response
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"type": "https://pagesmith.example/problems/form.field_unknown",
"title": "Field not found",
"status": 422,
"detail": "Field 'employer' does not exist in this PDF",
"code": "form.field_unknown"
}