# Working with files

How to supply inputs — a single file, an ordered array of files for merge, and the second image binary for image watermark — with accepted formats and sizes.

Inputs are sent as binary parts of a `multipart/form-data` request. Most actions
take exactly one PDF in a `file` field, but two actions need more: merge takes an
ordered array of files, and image watermark takes a second binary alongside the
PDF. This page covers all three input shapes.

## A single file

The default. Attach one PDF in the `file` field and add the action's options as
string fields:

```bash title="cURL"
curl https://api.pdfblocks.com/v1/extract_pages \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F pages='1..3' \
  -o extract.pdf
```

The `@` in `-F file=@input.pdf` tells cURL to send the file's contents. Every
single-input action — watermarks, security, page operations, splits — works this
way.

## Multiple files — merge

[Merge documents](/docs/api/merge-pdf-documents) is the one action that accepts an
array. Send the `file` field **more than once**, and the documents are merged in
the order the parts appear in the request. Provide at least one file; you can send
many in a single call.

<Warning>
  Order is positional, so send the parts in the sequence you want them merged.
  When your HTTP client exposes a form object, use its *append* method (not
  *set*) so that repeating `file` adds parts instead of overwriting the previous
  one.
</Warning>

<CodeGroup>

```bash title="cURL"
curl https://api.pdfblocks.com/v1/merge_documents \
  -H 'X-API-Key: your_api_key' \
  -F file=@cover.pdf \
  -F file=@body.pdf \
  -F file=@appendix.pdf \
  -o merged.pdf
```

```python title="Python"
# pip install requests
import requests

files = [
    ('file', ('cover.pdf', open('cover.pdf', 'rb'), 'application/pdf')),
    ('file', ('body.pdf', open('body.pdf', 'rb'), 'application/pdf')),
    ('file', ('appendix.pdf', open('appendix.pdf', 'rb'), 'application/pdf')),
]

response = requests.post(
    'https://api.pdfblocks.com/v1/merge_documents',
    headers={'X-API-Key': 'your_api_key'},
    files=files,
)

response.raise_for_status()
with open('merged.pdf', 'wb') as output:
    output.write(response.content)
```

```javascript title="Node.js"
// Node.js 18+
import { readFile, writeFile } from 'node:fs/promises';

const body = new FormData();
for (const name of ['cover.pdf', 'body.pdf', 'appendix.pdf']) {
  body.append('file', new Blob([await readFile(name)]), name);
}

const response = await fetch('https://api.pdfblocks.com/v1/merge_documents', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('merged.pdf', Buffer.from(await response.arrayBuffer()));
```

</CodeGroup>

<Note>
  If repeating the `file` field is awkward in your HTTP client (PHP's cURL,
  Ruby's form helpers), send numbered `file_1` through `file_10` fields instead —
  they are merged in numeric order. Use the repeated `file` array when you need
  more than ten documents.
</Note>

## An image alongside the PDF — image watermark

[Add an image watermark](/docs/api/add-image-watermark-to-pdf) takes two binary
parts: the PDF in `file` and the watermark image in an `image` field. The image
must be **PNG or JPEG**. Both parts are required.

```bash title="cURL"
curl https://api.pdfblocks.com/v1/add_image_watermark \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F image=@logo.png \
  -o watermarked.pdf
```

The remaining fields — `transparency`, `margin`, `pages` — are ordinary string
options; see the action reference for their ranges and defaults.

## Accepted inputs and size

- The `file` input (and each merged file) must be a readable PDF. A file that
  can't be parsed as a PDF returns a `400` naming the `file` field — see
  [Errors](/docs/api/errors).
- The `image` input for image watermark must be PNG or JPEG.
- Which pages an action touches is a separate concern from how you attach the
  file. Express page selections with the `pages` field documented in
  [Selecting pages](/docs/api/selecting-pages).

For large documents — streaming the upload and download, timeouts, and retries —
see [Working with large files](/docs/api/working-with-large-files).
