> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blinkpdf.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Dry-run a fill by name

> Same JSON Base64 `pdf` XOR `templateId` and `values` as fill, or the same multipart field `pdf` or `templateId` plus a `values` JSON object. Does not accept `flatten`. Same `x-api-key` as render. Does not apply plan `bodyBytes` to live `pdf` bytes. Stays request/response and unmetered. Sits on plan `ratePerMin` and `concurrency` (same post-auth limiters as fill). Burst is 429 `rate_limited`. Returns whether the fill would succeed. `written` is the field count that would be written. Empty required names are listed in `missingRequired` as warnings. Fill still writes the PDF. No PDF bytes. Does not spend a unit. `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`. Validate-fill injects the same hosted appearance face as fill. 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 `signed_pdf` (`PdfSignedPdfUnsupportedError`). Fill is not a second verb on `POST /v1/render`.



## OpenAPI

````yaml /openapi.json post /v1/validate-fill
openapi: 3.1.0
info:
  title: Blink PDF API
  description: >-
    Render Markdown into accessible, PDF/UA-conformant PDFs over HTTP. Send
    Markdown plus optional document metadata, fonts, page layout, viewer hints,
    and per-block style overrides to `POST /v1/render`, or use a structured
    template such as `POST /v1/templates/sandwich-document/render`. Fill by name
    is a separate verb: template (PDF bytes or stored id) plus `{ name: value }`
    returns a filled PDF. Inspect the field list at `POST /v1/inspect`, dry-run
    at `POST /v1/validate-fill`, and fill at `POST /v1/fill`. `POST /v1/fill`
    streams the PDF and does not keep the output. Stored templates live at
    `/v1/templates` (store, get, list, update, delete, download). Names are ISO
    fully qualified names, or the unique `/T` when there is only one. Omitted
    names stay unchanged. `false` is a value. Unknown names reject the request.
    The filled PDF never includes `/NeedAppearances`. A PDF with no widgets
    inspects to `fields: []` plus reason `no_widgets`; make it a form in studio
    first. Fill is request/response: plan `bodyBytes` and a 120 second produce
    ceiling. No job id. Fill is not a second verb on `POST /v1/render`.
    Authentication is via an `x-api-key` header. Unknown routes return HTTP 404
    with body `{ "error": "not_found" }`.
  version: 1.5.0
  contact:
    name: Blink PDF Support
    email: support@blinkpdf.io
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
  - url: https://api.blinkpdf.io
    description: Production
security: []
tags:
  - name: Discovery
    description: Machine-readable API entry point
  - name: Health
    description: Liveness probes
  - name: Render
    description: Markdown-to-PDF rendering
  - name: Fonts
    description: Hosted font catalog and Google Fonts capability discovery
  - name: SandwichDocument
    description: >-
      Sandwich documents — a first-page header (logo, professional identity,
      subject/context data) and a last-page footer (signature, name) wrapping a
      Markdown body
  - name: Fill
    description: Fill an AcroForm by name
  - name: Templates
    description: Stored AcroForm template library
paths:
  /v1/validate-fill:
    post:
      tags:
        - Fill
      summary: Dry-run a fill by name
      description: >-
        Same JSON Base64 `pdf` XOR `templateId` and `values` as fill, or the
        same multipart field `pdf` or `templateId` plus a `values` JSON object.
        Does not accept `flatten`. Same `x-api-key` as render. Does not apply
        plan `bodyBytes` to live `pdf` bytes. Stays request/response and
        unmetered. Sits on plan `ratePerMin` and `concurrency` (same post-auth
        limiters as fill). Burst is 429 `rate_limited`. Returns whether the fill
        would succeed. `written` is the field count that would be written. Empty
        required names are listed in `missingRequired` as warnings. Fill still
        writes the PDF. No PDF bytes. Does not spend a unit. `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`.
        Validate-fill injects the same hosted appearance face as fill. 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 `signed_pdf`
        (`PdfSignedPdfUnsupportedError`). Fill is not a second verb on `POST
        /v1/render`.
      operationId: validateFill
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - values
              additionalProperties: false
              properties:
                pdf:
                  type: string
                  format: byte
                  description: >-
                    AcroForm PDF bytes, Base64-encoded. Does not store the PDF.
                    XOR with `templateId`.
                templateId:
                  type: string
                  description: >-
                    Stored template id from `POST /v1/templates`. XOR with
                    `pdf`. Same store as `GET /v1/templates/:id`. Unknown,
                    deleted, or foreign is 404.
                values:
                  type: object
                  additionalProperties: true
                  description: >-
                    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.
            examples:
              byBytes:
                summary: Synthetic intake by bytes
                value:
                  pdf: <Base64>
                  values:
                    givenName: Ada
                    agree: true
              byTemplateId:
                summary: Stored template id
                value:
                  templateId: <id>
                  values:
                    givenName: Ada
                    agree: true
          multipart/form-data:
            schema:
              type: object
              required:
                - values
              additionalProperties: false
              properties:
                pdf:
                  type: string
                  format: binary
                  description: >-
                    AcroForm PDF file part. Does not store the PDF. XOR with
                    `templateId`.
                templateId:
                  type: string
                  description: >-
                    Stored template id from `POST /v1/templates`. XOR with
                    `pdf`. Same store as `GET /v1/templates/:id`. Unknown,
                    deleted, or foreign is 404.
                values:
                  type: object
                  additionalProperties: true
                  description: >-
                    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.
      responses:
        '200':
          description: >-
            The fill body is acceptable. `written` is the field count that would
            be written. Empty required names are listed in `missingRequired` as
            warnings. Fill still writes the PDF. No PDF bytes are returned
          content:
            application/json:
              schema:
                type: object
                required:
                  - written
                  - missingRequired
                properties:
                  written:
                    type: integer
                    minimum: 0
                    description: >-
                      Field count that would be written. Omitted names are not
                      counted.
                  missingRequired:
                    type: array
                    items:
                      type: string
                    description: >-
                      Inspect names with `/Ff` Required that stay empty.
                      Warnings. Fill still writes.
        '400':
          description: >-
            Caller-value fault: `unknown_field_name`, `type_mismatch`,
            `skipped_field_name`, or `appearance_unencodable`. Or missing or
            invalid template bytes or values, or both `pdf` and `templateId`
        '401':
          $ref: '#/components/responses/Responses.Unauthorized'
        '404':
          description: No stored template with that `templateId` for this account
        '413':
          $ref: '#/components/responses/Responses.PayloadTooLarge'
        '422':
          description: >-
            Template rejected: `no_acroform`, `need_appearances`
            (`PdfNeedAppearancesUnsupportedError`), `encrypted_pdf`
            (`PdfEncryptionUnsupportedError`), `xfa_unsupported`
            (`PdfXfaUnsupportedError`), or `signed_pdf`
            (`PdfSignedPdfUnsupportedError`)
        '429':
          $ref: '#/components/responses/Responses.RateLimited'
        '503':
          $ref: '#/components/responses/Responses.ServiceUnavailable'
      security:
        - apiKey: []
components:
  responses:
    Responses.Unauthorized:
      description: >-
        Missing or invalid `x-api-key` (must be a valid, enabled `bp_*` key;
        documentation endpoints and health are exempt)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error.Unauthorized'
          examples:
            unauthorized:
              $ref: '#/components/examples/Error.Unauthorized'
    Responses.PayloadTooLarge:
      description: >-
        Serialized JSON request body exceeds the caller's plan tier limit
        (`getTechnicalLimits`: free 128 KiB, pro 2 MiB, business 5 MiB).
        Enforcement uses the UTF-8 byte length of `JSON.stringify(body)` after
        parse, so a missing or incorrect `Content-Length` header cannot bypass
        the cap.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error.PayloadTooLarge'
          examples:
            payloadTooLarge:
              $ref: '#/components/examples/Error.PayloadTooLarge'
    Responses.RateLimited:
      description: >-
        Rate or concurrency limit exceeded (post-auth per-tier limits from
        `getTechnicalLimits`: free 10/min + 1 concurrent, pro 120/min + 10
        concurrent, business 600/min + 40 concurrent; a high pre-auth per-IP
        flood shield also exists but is sized above every plan rate and never
        binds first for plan traffic). Post-auth tier rate and concurrency
        blocks both return `error: rate_limited` but use different `detail`
        strings; audit rows distinguish `rate_limited` vs `concurrency_limited`.
        Tier-specific responses may include upgrade guidance in `detail`. The
        response carries `Retry-After` and defensive security headers.
      headers:
        Retry-After:
          schema:
            minimum: 1
            type: integer
          description: Seconds remaining until the rate-limit window resets. Always >= 1.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error.RateLimited'
          examples:
            rateLimited:
              $ref: '#/components/examples/Error.RateLimited'
    Responses.ServiceUnavailable:
      description: >-
        Transient outage: a subscription tier lookup failed
        (`service_unavailable`, fail-closed) or the font catalogue could not be
        read (`font_source_unavailable`). Retry shortly.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error.ServiceUnavailable'
          examples:
            serviceUnavailable:
              $ref: '#/components/examples/Error.ServiceUnavailable'
  schemas:
    Error.Unauthorized:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - unauthorized
    Error.PayloadTooLarge:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - payload_too_large
    Error.RateLimited:
      type: object
      required:
        - error
      description: >-
        Post-auth tier rate exhaustion and post-auth concurrency exhaustion both
        use `error: rate_limited`; distinguish them by `detail` (tier rate vs
        concurrency/plan copy). Render audit rows use separate `status` values
        (`rate_limited` vs `concurrency_limited`).
      properties:
        error:
          type: string
          enum:
            - rate_limited
        detail:
          type: string
    Error.ServiceUnavailable:
      type: object
      required:
        - error
      description: >-
        Transient outage shared by every 503. `font_source_unavailable` is a
        font catalogue read failure (`POST /v1/render`, `GET /v1/fonts`);
        `service_unavailable` is a subscription tier-lookup failure, fail-closed
        (`GET /v1/fonts`). Both are retryable. Each route documents which codes
        it can emit.
      properties:
        error:
          type: string
          enum:
            - service_unavailable
            - font_source_unavailable
        detail:
          type: string
  examples:
    Error.Unauthorized:
      summary: Missing or invalid x-api-key (bp_*)
      value:
        error: unauthorized
    Error.PayloadTooLarge:
      summary: Request body exceeds the configured cap
      value:
        error: payload_too_large
    Error.RateLimited:
      summary: >-
        Per-tier rate limit exceeded (concurrency exhaustion uses the same error
        code with a different detail string)
      value:
        error: rate_limited
        detail: >-
          Tier rate limit exceeded. Retry after the Retry-After interval or
          upgrade for higher sustained throughput.
    Error.ServiceUnavailable:
      summary: Transient tier-lookup or font-catalogue outage
      value:
        error: service_unavailable
        detail: >-
          Subscription tier lookup is temporarily unavailable. Retry the
          request.
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        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.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.