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

# Merge Documents

> Concatenate several files into one PDF so page-indexed steps see one continuous document.

`transform.merge-documents` combines a list of files into a single PDF run
output, in the order given. Use it when one logical document arrives as
several uploads (a scan split into one file per page, or a packet sent as
separate PDFs and photos). Parse the merged file once and every downstream
page index (Label Pages, Split, Separate Documents, Vision `pageIndices`)
counts across all sources instead of restarting at 0 for each file.

Downstream file steps take the merged PDF from `file`:
`{{ steps.merge.output.file }}`. The rest of the output describes the pages.

```yaml theme={null}
inputs:
  - name: documents
    type: array
    items:
      type: file

steps:
  - name: merge
    type: transform.merge-documents
    with:
      files: "{{ input.documents }}"
      filename: packet.pdf

  - name: parse
    type: ai.parse-v2
    with:
      input: "{{ steps.merge.output.file }}"

  - name: label_pages
    type: ai.classify-pages
    with:
      input: "{{ steps.parse.output }}"
      labels:
        - name: signature
          description: A page carrying a signature
```

A single file is accepted too, so the same workflow handles one upload or many.

## Accepted files

| Source | How it becomes pages |
| - | - |
| PDF | Pages are copied as they are, text included. A PDF with permission restrictions (owner password) is copied as page images, so Parse reads those pages with OCR or vision. A PDF that needs a password to open fails the step. |
| JPEG, PNG, TIFF, WebP, GIF | One page per image, rotated by its EXIF orientation. Multi-page TIFF gives one page per frame. The page size follows the image DPI, or fits A4 when the image has none. |
| Word, PowerPoint, OpenDocument, RTF | Converted to PDF with LibreOffice first. |

Any other type fails the step with the filename and type in the error.
When a file arrives as `application/octet-stream`, its type is recovered from
the filename extension or the file contents. At most 100 files are merged per
step. All files together can be at most 256 MiB.

## Mapping pages back to files

`sources` lists every input file in merge order with the 0-based, inclusive
page range it occupies in the merged PDF. A page index from Label Pages or
Vision maps back to its file by finding the range that contains it, for
example in a `transform.script` step:

```ts theme={null}
function script(sources: { filename: string; pageRange: [number, number] }[], page: number): string {
  return sources.find((s) => page >= s.pageRange[0] && page <= s.pageRange[1])?.filename ?? '';
}
```

## Configuration

Configuration goes inside the step's `with:` block.

<ParamField path="files" type="string" required>
  Template expression resolving to the files to merge, in order: a file list input such as \{\{ input.documents }}, or a single file. PDF, images (JPEG, PNG, TIFF, WebP, GIF) and Word, PowerPoint, OpenDocument or RTF documents.
</ParamField>

<ParamField path="filename" type="string">
  Filename of the merged PDF. Defaults to merged.pdf; .pdf is appended when missing.
</ParamField>

## Output

<ResponseField path="file" type="object" required>
  The merged PDF. Pass \{\{ steps.\<step>.output.file }} to Parse, Vision or any other file input.

  <Expandable title="file properties">
    <ResponseField path="fileId" type="string" required>
      File ID of the merged PDF
    </ResponseField>

    <ResponseField path="filename" type="string" required>
      Filename of the merged PDF
    </ResponseField>

    <ResponseField path="mimeType" type="string" required>
      Always application/pdf
    </ResponseField>

    <ResponseField path="size" type="integer" required>
      Size of the merged PDF in bytes
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField path="pageCount" type="integer" required>
  Total pages in the merged PDF
</ResponseField>

<ResponseField path="sources" type="array<object>" required>
  One entry per input file, in merge order, with the merged page range it occupies. Use it to map a merged page index back to its source file.

  <Expandable title="sources properties">
    <ResponseField path="filename" type="string" required>
      Filename of the source file
    </ResponseField>

    <ResponseField path="mimeType" type="string" required>
      MIME type of the source file
    </ResponseField>

    <ResponseField path="pageCount" type="integer" required>
      Pages this source contributed
    </ResponseField>

    <ResponseField path="pageRange" type="array<integer>" required>
      \[startIndex, endIndex] inclusive, 0-based page indices in the merged PDF
    </ResponseField>
  </Expandable>
</ResponseField>


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