# Overview

> Build the POST /v1/document/merge request: templateName, returnFormat, append and test, the JSON MergeBody, status codes, stored or sent templates and SDKs.

- **Product:** ReportingCloud
- **Section:** Documentation
- **Kind:** Topic
- **Path:** ReportingCloud > Mail Merge > Overview
- **3179 words**
- **Web URL:** https://docs.textcontrol.com/reporting-cloud/mail-merge/overview/
- **LLMs URL:** https://docs.textcontrol.com/reporting-cloud/mail-merge/overview/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/reporting-cloud/mail-merge/overview/llms-full.txt

---

What happens to a template and its JSON data between your request and the PDF that comes back? A merge in ReportingCloud is one call of the `POST /v1/document/merge` endpoint, and its parameters decide where the template comes from, how many documents you get and in which format. Knowing them lets you build the request your application needs, whatever language it is written in.

The first request with the demo template *sample\_invoice.tx* is the subject of the [Web API](https://docs.textcontrol.com/reporting-cloud/getting-started/web-api/llms-full.txt) tutorial in Getting Started. The samples below use the same template and the invoice data of [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/llms-full.txt), saved as *data.json*. They read your API key from the environment variable `REPORTINGCLOUD_API_KEY`; [API Keys](https://docs.textcontrol.com/reporting-cloud/installation/api-keys/llms-full.txt) describes how to create one.

### How Merging Works

A merge brings a template and data together:

- **The template** is an MS Word compatible document, designed in the template editor of the ReportingCloud portal or in a word processor that saves DOCX, DOC or RTF. Its placeholders are *merge fields*, which receive single values, and *merge blocks*, sections that are repeated for each element of an array, such as the rows of an order.
- **The data** is a JSON array of records. Its names match the names of the fields and blocks of the template.
- **The `POST /v1/document/merge` endpoint** fills the template with each record and returns the created documents as Base64 strings, in PDF or another format.

The following animation shows a letter template with the merge fields `FIRSTNAME`, `NAME` and `TOTAL` and a block with `ARTICLE_NAME` and `PRICE`, filled with the data of one customer and three ordered articles:

![Letter template whose merge fields are filled and whose order row is repeated](https://docs.textcontrol.com/assets/img/reporting-cloud/merging-template.4c87ca41.webp)

Working with ReportingCloud follows the same three steps every time:

1. Design the document as it should look, with merge fields and merge blocks as placeholders.
2. Name the fields and blocks like the data your application sends, as [Merge Fields](https://docs.textcontrol.com/reporting-cloud/mail-merge/fields/llms-full.txt) and [Merge Blocks](https://docs.textcontrol.com/reporting-cloud/mail-merge/blocks/llms-full.txt) describe.
3. Send the data to `document/merge` and save the documents of the response.

Layout and formatting stay in the template, so a designer can change them without a change to your code.

### What a Merge Fills

| Template element | Filled with | Described in |
|---|---|---|
| Merge fields | A value of the record, or of the current array element inside a block | [Merge Fields](https://docs.textcontrol.com/reporting-cloud/mail-merge/fields/llms-full.txt) |
| Merge blocks | One copy for each element of an array, in any number of nested levels | [Merge Blocks](https://docs.textcontrol.com/reporting-cloud/mail-merge/blocks/llms-full.txt), [Nested Blocks](https://docs.textcontrol.com/reporting-cloud/mail-merge/nested-blocks/llms-full.txt) |
| Merge blocks bound to optional data | The block is kept when the data has values for it and removed when not | [Conditional Blocks](https://docs.textcontrol.com/reporting-cloud/mail-merge/conditional-content/llms-full.txt) |
| Image placeholders | An image from Base64 data in the record | [Images](https://docs.textcontrol.com/reporting-cloud/mail-merge/images/llms-full.txt) |
| Merge fields with HTML values | Formatted text, when `mergeHtml` is set | [HTML Content](https://docs.textcontrol.com/reporting-cloud/mail-merge/html-content/llms-full.txt) |

The blog article [What Can You Do with the ReportingCloud RESTful Service?](https://www.textcontrol.com/blog/2016/08/06/what-can-you-do-with-the-reportingcloud-restful-service/) adds barcodes, which are named like merge fields and encode the matching value, and charts, whose series are filled from the JSON data.

### The Merge Request

The endpoint is [POST /v1/document/merge](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/merge/post/llms-full.txt) at `https://api.reporting.cloud`. Every request authenticates with an `Authorization` header, as [Authentication](https://docs.textcontrol.com/reporting-cloud/document-processing/authentication/llms-full.txt) explains. Four query parameters control the merge:

| Parameter | Content |
|---|---|
| `templateName` | The name of a template in your template storage, such as `sample_invoice.tx`. Without it, the request body must contain the template |
| `returnFormat` | The format of the created documents: `PDF`, `PDFA`, `RTF`, `DOC`, `DOCX`, `HTML`, `TX` or `TXT`, in any letter case. Without it, the documents are PDF. `PDFA` requires the Extreme plan |
| `append` | With more than one record, `true` appends all documents to one document, and `false` returns one document per record |
| `test` | `true` makes the request a test run, whose documents carry a "TEST MODE" watermark. Not possible with a Free account; on a trial account, a test run of merge is counted against the document quota |

The body is a JSON object, the `MergeBody`:

| Property | Content |
|---|---|
| `mergeData` | Required. The data as a JSON array of records, or a single record as a JSON object, described in [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/llms-full.txt) |
| `template` | Optional. The template as a Base64 string, in the format RTF, DOC, DOCX, TX or HTML |
| `mergeSettings` | Optional. Options such as the removal of empty fields and blocks, the culture and the document properties, listed in [Merge Settings](https://docs.textcontrol.com/reporting-cloud/mail-merge/settings/llms-full.txt) |

The response is a JSON array of Base64 strings, one for each created document. Each successful request counts 1 against the document quota of your plan, as [Plans and Licensing](https://docs.textcontrol.com/reporting-cloud/overview/licensing/llms-full.txt) explains. When a request fails, the status code says why:

- **400 Bad Request.** The body isn't JSON, the `MergeBody` contains no data, no template was sent, the template isn't in the template storage or `returnFormat` isn't one of the values above.
- **403 Forbidden.** The API key or the user name and password aren't valid, the document quota is used up, more than two requests of the same account came in at the same time or `PDFA` was requested without an Extreme plan.
- **500 Internal Server Error.** The request has no `Authorization` header or an empty one, the template isn't a valid Base64 string or a `mergeSettings` property has a value of the wrong type.

The processing time of a request is limited to 60 seconds, after which the merge is canceled. [Errors and Status Codes](https://docs.textcontrol.com/reporting-cloud/document-processing/errors/llms-full.txt) covers the responses and the time limit in detail.

### Merge a Template From the Template Storage

Templates that you upload in the portal or with the Web API are kept in your *template storage*, and a merge names them in `templateName`. Every trial account starts with *sample\_invoice.tx* in its storage. The following commands wrap the records of *data.json* in a `MergeBody`, merge them into the template and save the PDF:

```bash
# Wrap the records of data.json in a MergeBody
jq '{mergeData: .}' data.json > merge.json

curl -X POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF&append=true" \
  -H "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @merge.json \
  -o result.json

# The response is an array of Base64 strings; decode the first one
jq -r '.[0]' result.json | base64 -d > invoice.pdf
```

The commands work as follows:

- The `jq` filter `{mergeData: .}` puts the array of *data.json* into the `mergeData` property. `template` and `mergeSettings` are left out, because the template comes from the storage and the default settings apply.
- `--data-binary @merge.json` sends the file unchanged as the body, and `-o result.json` saves the response.
- `jq -r '.[0]'` takes the first Base64 string of the response, and `base64 -d` decodes it into *invoice.pdf*.

Uploading templates is described in [Managing Templates](https://docs.textcontrol.com/reporting-cloud/document-processing/templates/llms-full.txt) for the Web API and in [Template Storage](https://docs.textcontrol.com/reporting-cloud/portal/templates/llms-full.txt) for the portal.

### Send the Template With the Request

Instead of naming a stored template, you can send the template in the `template` property of the `MergeBody`. Leave out `templateName` then. The following commands merge a template of your own, *invoice.docx*, whose fields have the names of *data.json*:

```bash
# Put the template as a Base64 string next to the data
jq --rawfile template <(base64 -w 0 invoice.docx) \
  '{template: $template, mergeData: .}' data.json > merge.json

curl -X POST "https://api.reporting.cloud/v1/document/merge?returnFormat=PDF&append=true" \
  -H "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @merge.json \
  -o result.json

jq -r '.[0]' result.json | base64 -d > invoice.pdf
```

`base64 -w 0` encodes the template without line breaks, and `--rawfile` reads that string into the `jq` variable `$template`.

Which of the two to choose:

- **Store templates you merge often.** A stored template doesn't travel with every request, so the merge is faster.
- **Send templates that change with each request** or that you don't want to keep in ReportingCloud. A template sent this way is held in memory for the merge and deleted afterward; [Data Security and Privacy](https://docs.textcontrol.com/reporting-cloud/overview/security/llms-full.txt) describes what ReportingCloud stores.

> Warning
>
> **Stored or Sent, Not Both.** Use one of the two in a request. When a request has both, the Web API merges the stored template and ignores the one in the body, and the Java and Ruby SDKs refuse to send such a request.

### Create One Document or One per Record

Each record of `mergeData` merges the whole template once. With `append=true`, the documents of all records are appended to one document, and the response array holds one string. With `append=false`, each record becomes a document of its own, which suits letters you send to each customer separately. A request without `append` is appended as with `append=true`, so pass `append=false` for one document per record.

The following commands build *merge.json* from *data.json* again, as in [Merge a Template From the Template Storage](#merge-a-template-from-the-template-storage), send it with `append=false` and decode every document of the response into a file of its own:

```bash
# Rebuild merge.json from the current records of data.json
jq '{mergeData: .}' data.json > merge.json

curl -X POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF&append=false" \
  -H "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @merge.json \
  -o result.json

# One Base64 string per record
count=$(jq 'length' result.json)

for ((i = 0; i < count; i++)); do
  jq -r ".[$i]" result.json | base64 -d > "invoice-$((i + 1)).pdf"
done
```

To see two documents, add a second record to the array in *data.json*, as [One Record per Document](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/#one-record-per-document) shows.

### Merge With an SDK

The SDKs send the same request. The .NET, PHP and Java SDKs decode the Base64 strings for you; the Ruby SDK returns them as Base64 strings, which you decode with `Base64.strict_decode64`. Their merge methods differ in what they do when you don't pass `append`:

| SDK | Method | Without an `append` argument |
|---|---|---|
| .NET, NuGet package `TXTextControl.ReportingCloud` | `MergeDocument(mergeBody, templateName, returnFormat, append, test)` | Sends `append=True`: one document |
| PHP, Composer package `textcontrol/textcontrol-reportingcloud` | `mergeDocument($mergeData, $returnFormat, $templateName, $templateFilename, $append, $mergeSettings)` | Uses `false` and leaves the parameter out of the request: one document |
| Java | `mergeDocument(mergeBody, templateName, returnFormat, append, test)` | Sends `append=false`: one document per record |
| Ruby | `merge_document(merge_body, template_name, return_format, append, test)` | Sends `append=false`: one document per record |

The .NET, Java and Ruby methods create PDF when you don't pass a return format; the PHP method requires one. [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/#merge-objects-with-the-net-sdk) shows the .NET and PHP calls, and the [SDKs](https://docs.textcontrol.com/reporting-cloud/sdks/llms-full.txt) section describes each SDK.

### Next Steps

- [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/llms-full.txt): the structure of the JSON data and how the SDKs create it.
- [Merge Fields](https://docs.textcontrol.com/reporting-cloud/mail-merge/fields/llms-full.txt): name, format and check the fields of a template.
- [Merge Blocks](https://docs.textcontrol.com/reporting-cloud/mail-merge/blocks/llms-full.txt): repeat table rows for each element of an array.
- [Merge Settings](https://docs.textcontrol.com/reporting-cloud/mail-merge/settings/llms-full.txt): every option of the `mergeSettings` object.

---

## Nearby

- **Previous:** [Mail Merge](https://docs.textcontrol.com/reporting-cloud/mail-merge/llms-full.txt)
- **Next:** [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/llms-full.txt)
