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

# Merge Files

> Join several documents into one PDF, in the order given.

> [!NOTE]
>
> **Preview.** This endpoint is available to organisations in the Wordsmith MCP pilot. Other organisations receive `403 mcp_not_enabled`. See the [preview overview](/preview).

Joins 2 to 20 documents into one new PDF, in the order you list them. Use it to put an agreement and its schedules back together, or to bundle documents for signing. Each input can be a DOCX, a DOC or a PDF; a DOCX or DOC is converted to PDF first. The same file can appear more than once.

The action runs as an operation of type `document_action`: the response comes back straight away, and the work runs in the background. Wait for it with `wait`, a `callback_url`, or [Get Operation](/api-reference/operations/get-operation). The new files land in your private space. The input files are not changed. Document actions use no credits.

## Authentication

Send an API key, or an OAuth access token with both the `files:write` and `files:read` scopes. `files:write` lets the action create its output; `files:read` lets it read the inputs. A token without either gets `403` with `"error": "insufficient_scope"`.

## Headers

**Idempotency-Key** `string`

A unique key for this request, such as a UUID, up to 255 characters. A repeat with the same key within 30 days returns `200` with the same operation and does the work once. A repeat with a different body returns `409 idempotency_key_reused`.

## Body parameters

**file\_ids** `string[]` *required*

The files to join, 2 to 20, in the order they should appear.

**file\_name** `string`

The merged file's name, e.g. `"Supply Agreement with Schedules.pdf"`. `.pdf` is added when the name does not end with it. Defaults to the first file's name with ` (merged)` added.

**wait** `integer` (default: 0)

Seconds to wait for the action to finish before responding, from `0` to `20`. A few short documents usually merge inside `20`.

**callback\_url** `string`

A public HTTPS URL that receives a signed `operation.succeeded`, `operation.failed` or `operation.cancelled` event when the action finishes. API keys only: an OAuth caller waits or polls instead.

## Response

Returns `202` with an operation of type `document_action`. Its `resource` is the first file in `file_ids`. A repeat with the same `Idempotency-Key` returns `200` with the same operation.

When `status` is `succeeded`, `result` is `{ "action": "merge", "file_ids", "summary" }`. `file_ids` holds one id: the merged PDF. `summary` is `{ "files_merged", "pages" }`: how many files were joined and the merged PDF's page count.

When `status` is `failed`, `error.code` says why:

| `error.code` | When |
| - | - |
| `resource_not_found` | An input was deleted, or your access to it removed, before the work ran. |
| `invalid_document` | An input could not be read: it is damaged, password-protected or not a valid DOCX or PDF. Retrying does not help. |
| `action_failed` | The action failed for another reason. `error.retryable` is `true`: try again. |

**id** `string (uuid)`

The operation's id.

**type** `string`

`document_action`.

**status** `string`

`queued` until a worker starts the action, then `running`, `succeeded`, `failed` or `cancelled`.

**progress** `object | null`

`{ "stage", "completed", "total" }`. `null` until the work starts.

**resource** `object`

`{ "type": "file", "id" }`: the first file in `file_ids`.

**result** `object | null`

Set when `status` is `succeeded`.

**error** `object | null`

`{ "code", "message", "retryable" }`, set when `status` is `failed`.

**poll\_after\_seconds** `integer | null`

When to ask again. `null` once the operation has finished.

**created\_at** `string`

ISO 8601 UTC.

**updated\_at** `string`

ISO 8601 UTC.

**completed\_at** `string | null`

ISO 8601 UTC, once the operation has finished.

```bash cURL theme={null}
curl -X POST "https://api.wordsmith.ai/api/v1/files/merge" \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: e2a9c4f7-1b6d-4e83-9f50-3c8d7a1b6e24" \
  -d '{
    "file_ids": [
      "cf4ba165-c6ee-403e-8d61-64959162ab14",
      "d4570ecd-108a-40e2-8940-77d59b6f6509",
      "3dda8853-45fc-4fd4-81a6-1f5bdc0e4319"
    ],
    "file_name": "Supply Agreement with Schedules.pdf"
  }'
```

```json Running theme={null}
{
  "id": "c2abbfb9-7d88-4dfa-a5b6-fa575730accf",
  "type": "document_action",
  "status": "running",
  "progress": {
    "stage": "merge",
    "completed": 0,
    "total": 1
  },
  "resource": {
    "type": "file",
    "id": "cf4ba165-c6ee-403e-8d61-64959162ab14"
  },
  "result": null,
  "error": null,
  "poll_after_seconds": 5,
  "created_at": "2026-10-13T11:00:00Z",
  "updated_at": "2026-10-13T11:00:01Z",
  "completed_at": null
}
```

```json Succeeded theme={null}
{
  "id": "c2abbfb9-7d88-4dfa-a5b6-fa575730accf",
  "type": "document_action",
  "status": "succeeded",
  "progress": {
    "stage": "merge",
    "completed": 1,
    "total": 1
  },
  "resource": {
    "type": "file",
    "id": "cf4ba165-c6ee-403e-8d61-64959162ab14"
  },
  "result": {
    "action": "merge",
    "file_ids": [
      "d619b748-a7fd-4c91-978e-bb2d835b2c17"
    ],
    "summary": {
      "files_merged": 3,
      "pages": 41
    }
  },
  "error": null,
  "poll_after_seconds": null,
  "created_at": "2026-10-13T11:00:00Z",
  "updated_at": "2026-10-13T11:00:08Z",
  "completed_at": "2026-10-13T11:00:08Z"
}
```

## Errors

| Status | `error_code` | When |
| - | - | - |
| 400 | `invalid_request_body` | The body is not valid JSON, has an unknown field, or `file_ids` has fewer than 2 or more than 20 entries. |
| 400 | `unsupported_file_type` | A file is not a DOCX, DOC or PDF. |
| 400 | `invalid_wait` | `wait` is not from `0` to `20`. |
| 400 | `invalid_callback_url` | `callback_url` is not a public HTTPS URL. |
| 400 | `callback_signing_unavailable` | The API key has no webhook secret to sign the callback with. Create a new API key, or long-poll the operation instead. |
| 400 | `bad_request` | `callback_url` was sent with an OAuth token. |
| 403 | `insufficient_scope` | The OAuth token lacks `files:write` or `files:read`. |
| 403 | `forbidden` | Your user may not upload files, so the output has nowhere to go. |
| 404 | `resource_not_found` | A file does not exist, or you cannot read it. |
| 409 | `scan_in_progress` | A file's malware scan has not finished. Retry in a few seconds. |
| 409 | `idempotency_key_reused` | The `Idempotency-Key` was used within 30 days with a different request. |


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