Fill an AcroForm by name
JSON Base64 pdf plus a values map and optional flatten, or multipart field pdf plus a values JSON object (same shape). Or templateId XOR pdf for a stored blank template (same store as GET /v1/templates/:id). Inspect and validate-fill accept the same XOR. Same x-api-key as render. Returns a filled PDF with written appearances. Streams the PDF on the response and does not keep the output. Does not accept persist. Preview and print show the values without a viewer repair pass. Omit flatten or set it false. Widgets stay interactive with written /AP. flatten: true stamps appearances and strips the form. Not the default. Password fields still do not flatten in the clear. Never /NeedAppearances. Overlay advisories (overflow.clipped, overflow.autosized, font.substituted, widget.tiny) ride X-Fill-Warnings (base64url JSON). Always present. Empty when every appearance fit. The PDF still returns. Silent clip is not a 200 with no note. A successful fill records one unit. Inspect and validate-fill do not. A caller at the hard cap receives the same 402 spend_cap_reached as POST /v1/render. Optional x-idempotency-key retries the same body without a second unit. Reusing the key with a different values object or flatten returns 409 idempotency_conflict. Request/response only: no job id and no poll. Fill-by-bytes (JSON or multipart pdf) uses the plan bodyBytes ceiling (oversize is 413 payload_too_large). A templateId fill does not re-check stored PDF bytes against bodyBytes. Produce must finish within 120 seconds; an overrun or aborted produce is 504 service_unavailable. Inspect and validate-fill spend no unit; they still sit on plan ratePerMin and concurrency. A successful fill sets Content-Disposition to {PDF /Title or form}-filled.pdf. Title-less templates download as form-filled.pdf. Safe ASCII filename=. Optional RFC 5987 filename* when /Title is not ASCII. Not download. Not a uuid. The client does not send a filename field. Inspect and validate-fill stay JSON. values keys are ISO fully qualified names (or the unique /T when there is only one). Omitted names stay unchanged. false is a value. Unknown names are unknown_field_name with close-match suggestions. A type mismatch is type_mismatch. A skipped import name is skipped_field_name. Fill injects the hosted appearance face. The client does not send a TTF or a font field. A value that face cannot encode is appearance_unencodable (PdfPreserveFieldAppearanceError). One bad key fails the whole request. An empty required field is not a 400. A template with /NeedAppearances is rejected as need_appearances (PdfNeedAppearancesUnsupportedError). Password, XFA, and signed or certified templates are rejected as encrypted_pdf (PdfEncryptionUnsupportedError), xfa_unsupported (PdfXfaUnsupportedError), or . Fill is not a second verb on POST /v1/render.
curl --request POST \
--url https://api.blinkpdf.io/v1/fill \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"pdf": "<Base64>",
"values": {
"givenName": "Ada",
"agree": true
}
}
'"<string>"{
"error": "unauthorized"
}{
"error": "spend_cap_reached",
"detail": "The monthly spend cap for this plan has been reached. Usage that exceeds the included volume is paused until the next billing period. Raise the spend cap or upgrade the plan to continue."
}{
"error": "idempotency_conflict",
"detail": "The idempotency key was already used with a different render request."
}{
"error": "payload_too_large"
}{
"error": "rate_limited",
"detail": "Tier rate limit exceeded. Retry after the Retry-After interval or upgrade for higher sustained throughput."
}{
"error": "service_unavailable",
"detail": "Subscription tier lookup is temporarily unavailable. Retry the request."
}{
"error": "service_unavailable",
"detail": "<string>"
}Authorizations
API key issued from your Blink PDF account, prefixed bp_. Send it in the x-api-key header on every request. The documentation and health endpoints are exempt.
Headers
Optional client-supplied idempotency token. When present, usage metering deduplicates on (key, user_id) so retries with the same body do not double-count. Reusing the key with a different request body returns 409 idempotency_conflict (no PDF, no usage headers).
Body
Fill-by-name map. Keys are inspect names. Tx and Ch are strings, checkbox is boolean, radio is string or null. Omitted names stay unchanged. false is a value.
AcroForm PDF bytes, Base64-encoded. Does not store the PDF. XOR with templateId.
Stored template id from POST /v1/templates. XOR with pdf. Same store as GET /v1/templates/:id. Unknown, deleted, or foreign is 404.
Omit flatten or set it false. Widgets stay interactive with written /AP. flatten: true stamps appearances and strips the form. Not the default. Password fields still do not flatten in the clear.
Response
Filled PDF. Appearances are written. Preview and print show the values. Streams the bytes and does not keep the output. Default keeps /AcroForm and widgets. flatten: true stamps appearances, strips widgets, and still shows the values. Overlay warnings ride X-Fill-Warnings (empty when every appearance fit). Content-Disposition is {PDF /Title or form}-filled.pdf. Records one unit
The response is of type file.
curl --request POST \
--url https://api.blinkpdf.io/v1/fill \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"pdf": "<Base64>",
"values": {
"givenName": "Ada",
"agree": true
}
}
'"<string>"{
"error": "unauthorized"
}{
"error": "spend_cap_reached",
"detail": "The monthly spend cap for this plan has been reached. Usage that exceeds the included volume is paused until the next billing period. Raise the spend cap or upgrade the plan to continue."
}{
"error": "idempotency_conflict",
"detail": "The idempotency key was already used with a different render request."
}{
"error": "payload_too_large"
}{
"error": "rate_limited",
"detail": "Tier rate limit exceeded. Retry after the Retry-After interval or upgrade for higher sustained throughput."
}{
"error": "service_unavailable",
"detail": "Subscription tier lookup is temporarily unavailable. Retry the request."
}{
"error": "service_unavailable",
"detail": "<string>"
}