---
title: "Merge PDFs"
method: POST
path: "/v1/pdf-tools/merge"
tags: ["PDF tools"]
---

# Merge PDFs

`POST /v1/pdf-tools/merge`

## Request

- Base URL: `https://api-eu.dynamicdocumentapi.com`
- URL: `https://api-eu.dynamicdocumentapi.com/v1/pdf-tools/merge`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Merge 2-200 PDFs into one document. Answers a Render object with `input_type: "pdf_tool"`; `delivery`, `mode`, `webhook`, `reference`, `metadata` and `test` behave as on `POST /v1/renders`.

## Headers

- `Idempotency-Key` string

## Request body

- MergeRequest
  - `bookmarks` 'filenames' | 'none'
  - `delivery` DeliverySpec
    - `email` union: Email rules (Growth plan and up). Absent or `null`: the template's enabled rules; `false`: none; a list: only those rules, optionally with literal `to`/`cc`/`bcc`. Template renders only (not previews, signed links, PDF tools or zero-retention renders).
      - false
      - EmailTargetSpec[]
        - `bcc` string[], nullable: Replaces the rule's `bcc` (`[]`: none).
        - `cc` string[], nullable: Replaces the rule's `cc` (`[]`: none).
        - `rule_id` string, required: An enabled email rule (`emr_…`) of the render's template.
        - `to` string[], nullable: Literal recipients instead of the rule's `to`: each entry one address or `Name <address>`.
    - `expires_in` integer
    - `hosted` boolean, nullable: Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one.
    - `retention` 'none' | 'default', nullable
    - `retention_days` integer, nullable
    - `storage` StorageTargetSpec[], nullable
      - `destination_id` string, required
      - `path` string, nullable
    - `type` 'url' | 'binary' | 'base64' | 'none', nullable: `url`: signed file URLs in the response; `binary` / `base64`: the file itself (sync only); `none`: no file in the response (storage destinations, email). Absent or `null`: `url` when the render keeps a hosted copy, else `none`.
  - `filename` string, nullable
  - `metadata` object, nullable
  - `mode` 'sync' | 'async'
  - `priority` 'normal' | 'low'
  - `reference` string, nullable
  - `sources` PdfSourceSpec[], required
    - `data_uri` string, nullable
    - `file_id` string, nullable
    - `render_id` string, nullable
    - `upload_id` string, nullable
    - `url` string, nullable
  - `test` boolean, nullable
  - `timeout_behavior` 'continue' | 'cancel'
  - `webhook` WebhookSpec
    - `events` string[]
    - `format` 'standard'
    - `url` string, required: Where to send the events: https (or http in test mode) with a public host and no credentials, on port 443, 80, 8080 or 8443.

## Response `200`

Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.

- Render
  - `batch_id` string, nullable
  - `billed_renders` integer: Renders billed for this request (0 for test renders, previews, failed and canceled renders).
  - `completed_at` string, date-time, nullable
  - `created_at` string, date-time, required
  - `email` RenderEmail[]: The render's email sends in creation order. They are created when the render's result is processed, so a render still running (or a sync response) lists none yet; `render.succeeded` shows them as created: `pending`, or `skipped` / `failed`.
    - `error` EmailSendError, required: Why a send failed or waits: never message bodies or addresses.
      - `code` string, required: `email_template_error`, `email_too_large`, `email_recipient_missing`, `email_address_invalid`, `email_too_many_recipients`, `email_attachment_too_large`, `email_attachment_type_not_allowed`, `email_needs_hosted_file`, `email_provider_rejected`, `email_provider_auth_failed`, `email_provider_unavailable`, `email_ip_not_authorized`, `email_rate_limited`, `email_outcome_unknown`, `email_daily_cap_reached`, `email_disabled`, `email_credentials_removed`, `email_send_expired`, `internal_error`
      - `column` integer
      - `field` string: `email_template_error`, `email_too_large`: the rule field, e.g. `subject`.
      - `line` integer: `email_template_error`: where in the field.
      - `message` string, required
      - `provider_code` string, nullable: The provider's own error code.
      - `provider_status` integer, nullable: The provider's HTTP or SMTP status.
    - `id` string, required
    - `provider_message_id` string, nullable, required
    - `rule_id` string, required
    - `sent_at` string, date-time, nullable, required
    - `status` 'pending' | 'sending' | 'retrying' | 'sent' | 'sandboxed' | 'skipped' | 'failed' | 'unknown' | 'canceled', required
    - `to` string[], required: The `to` addresses.
  - `engine` string
  - `engine_version` string, nullable
  - `error` RenderError
    - `code` string
    - `column` integer
    - `detail` string
    - `excerpt` string
    - `line` integer
    - `message` string
  - `expires_at` string, date-time, nullable
  - `files` RenderFile[], required
    - `bytes` integer, required
    - `content_base64` string: Only with `delivery.type=base64`.
    - `content_type` string
    - `filename` string, required
    - `format` 'pdf' | 'png' | 'jpeg' | 'webp' | 'html' | 'zip' | 'xml', required
    - `height` integer, nullable
    - `id` string, required
    - `pages` integer, nullable
    - `sha256` string
    - `url` string, uri: Signed URL (omitted when not hosted).
    - `url_expires_at` string, date-time
    - `variant` string, nullable
    - `width` integer, nullable
  - `id` string, required
  - `input_type` 'template' | 'html' | 'url' | 'markdown' | 'pdf_tool' | 'einvoice'
  - `kind` string
  - `metadata` object
  - `mode` 'sync' | 'async', required
  - `object` 'render', required
  - `output_format` 'pdf' | 'png' | 'jpeg' | 'webp' | 'html' | 'zip' | 'xml'
  - `pages` integer, nullable
  - `reference` string, nullable
  - `region` string, required
  - `result` RenderResult: Structured result, `null` for most renders. PDF/A, PDF/UA, tagged and e-invoice renders carry their conformance report here — succeeded **and** failed ones; `pdf-tools/metadata` without `set` returns the document information (`pages`, `page_sizes`, `encrypted`, `metadata`).
    - `conformance` ConformanceReport: Validation of the delivered file against the standards it claims.
      - `einvoice` EInvoiceConformance
        - `errors` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
        - `profile` 'MINIMUM' | 'BASIC_WL' | 'BASIC' | 'EN16931' | 'EXTENDED' | 'XRECHNUNG', required
        - `scenario` string, nullable, required: The validator scenario that matched; `null` when it did not run.
        - `status` 'passed' | 'failed' | 'unavailable', required: `unavailable`: the validator was not configured or did not answer in time; the file was delivered unvalidated (warning `einvoice_validation_unavailable`).
        - `syntax` 'cii' | 'ubl', required
        - `validator` string, nullable, required: `null` when the validator did not run (`einvoice_invalid`: the model broke a rule before any XML was written, or unavailable).
        - `warnings` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
      - `pdfa` PdfaConformance
        - `errors` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
        - `level` '2b' | '3b', required
        - `profile` string, nullable, required: veraPDF validation profile; `null` when veraPDF did not run.
        - `status` 'passed' | 'failed' | 'unavailable', required: `unavailable`: the validator was not configured or did not answer in time; the file was delivered unvalidated (warning `pdfa_validation_unavailable`).
        - `validator` string, nullable, required: `null` when veraPDF did not run (conversion failed, or unavailable).
        - `warnings` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
      - `pdfua` PdfuaConformance: veraPDF's PDF/UA-1 check of a render with `pdf.pdfua` or `pdf.tagged`. With `pdfua`, `failed` fails the render (`pdfua_validation_failed`); with `tagged` alone, and in previews, the report is information. The machine checks don't judge whether alt text is meaningful or the reading order right.
        - `errors` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
        - `profile` string, nullable, required: veraPDF validation profile; `null` when veraPDF did not run.
        - `standard` 'PDF/UA-1', required
        - `status` 'passed' | 'failed' | 'unavailable', required: `unavailable`: the validator was not configured or did not answer in time; the file was delivered unvalidated (warning `pdfua_validation_unavailable`).
        - `validator` string, nullable, required: `null` when veraPDF did not run (the title or language was missing, or unavailable).
        - `warnings` ConformanceFinding[], required
          - `count` integer, required
          - `location` string, required: JSON path into the invoice for model issues found before the XML was written, else the validator's XPath or veraPDF context; empty when the finding concerns the whole document (e.g. a PDF/A `conversion` error).
          - `message` string, required
          - `rule` string, required: Business rule (EN 16931 `BR-…`, XRechnung `BR-DE-…`), schema rule, or PDF/A or PDF/UA clause and test number (`6.2.4.3-2`, `7.3-1`).
  - `source` string
  - `status` 'queued' | 'processing' | 'succeeded' | 'failed' | 'canceled' | 'expired', required
  - `storage` StorageResult[]
    - `destination_id` string
    - `error` string, nullable
    - `location` string, nullable
    - `status` 'pending' | 'succeeded' | 'failed' | 'skipped'
  - `template` object, nullable
    - `id` string
    - `version` union
      - integer
      - string
    - `version_id` string, nullable
  - `test` boolean, required
  - `timings` object
  - `warnings` object[]: Non-fatal: `slow_asset`, `asset_failed`, `wait_timeout` (the wait condition timed out and `wait.strict` is off, so the page was rendered as it was), `header_footer_overlap` (a header or footer is taller than its margin and may cover the body), `locale_unsupported` (the engine doesn't support `locale`), `feature_unavailable` (something in the request or template was ignored; the message names it), `font_fallback_used` (canvas templates: an unavailable font was replaced by Noto Sans; HTML renders fall back silently), `data_coerced` (canvas templates: a data value couldn't be used as given), `text_overflow` (canvas templates: text was cut off or overflows its box), `storage_upload_failed`, `einvoice_validation_warning`, `einvoice_validation_unavailable`, `pdfa_validation_unavailable`, `pdfua_validation_unavailable` (veraPDF was not reachable: the PDF/UA file is delivered unvalidated), `accessibility_validation_unavailable` (`tagged` without `pdfua`: no PDF/UA report, veraPDF was not reachable), `einvoice_skipped_plan`, `storage_skipped_plan`, `email_skipped_plan` (the template's email rules need the Growth plan or higher; no email was sent), `email_skipped_zero_retention` (zero-retention renders have no file to email), `invoice_totals_unavailable`.
    - `code` string
    - `message` string

## Other responses

- `202`: Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400`: Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401`: Missing, invalid, expired or revoked credentials.
- `402`: Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403`: Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404`: Template or version not found.
- `408`: Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409`: A request with this Idempotency-Key is still in progress.
- `410`: Template deleted.
- `413`: Payload or output too large.
- `422`: Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429`: Rate limited (`Retry-After`).
- `503`: Region degraded (`Retry-After`).

---

[API](https://skmtc.dev/dynamicdocumentapi/apis/dynamic-document-api.md) · [All operations](https://skmtc.dev/dynamicdocumentapi/apis/dynamic-document-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dynamicdocumentapi/apis/dynamic-document-api/revisions/0f14bc0000f4?raw)
