Overview
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 tutorial in Getting Started. The samples below use the same template and the invoice data of Merge Data, saved as data.json. They read your API key from the environment variable REPORTINGCLOUD_API_KEY; API Keys 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/mergeendpoint 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:

Working with ReportingCloud follows the same three steps every time:
- Design the document as it should look, with merge fields and merge blocks as placeholders.
- Name the fields and blocks like the data your application sends, as Merge Fields and Merge Blocks describe.
- Send the data to
document/mergeand 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 |
| Merge blocks | One copy for each element of an array, in any number of nested levels | Merge Blocks, Nested Blocks |
| Merge blocks bound to optional data | The block is kept when the data has values for it and removed when not | Conditional Blocks |
| Image placeholders | An image from Base64 data in the record | Images |
| Merge fields with HTML values | Formatted text, when mergeHtml is set | HTML Content |
The blog article 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 at https://api.reporting.cloud. Every request authenticates with an Authorization header, as Authentication 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 |
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 |
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 explains. When a request fails, the status code says why:
- 400 Bad Request. The body isn't JSON, the
MergeBodycontains no data, no template was sent, the template isn't in the template storage orreturnFormatisn'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
PDFAwas requested without an Extreme plan. - 500 Internal Server Error. The request has no
Authorizationheader or an empty one, the template isn't a valid Base64 string or amergeSettingsproperty 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 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:
# Wrap the records of data.json in a MergeBody
jq '{mergeData: .}' data.json > merge.json
curl POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF&append=true" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@merge.json \
result.json
# The response is an array of Base64 strings; decode the first one
jq '.[0]' result.json | base64 > invoice.pdf
The commands work as follows:
- The
jqfilter{mergeData: .}puts the array of data.json into themergeDataproperty.templateandmergeSettingsare left out, because the template comes from the storage and the default settings apply. --data-binary @merge.jsonsends the file unchanged as the body, and-o result.jsonsaves the response.jq -r '.[0]'takes the first Base64 string of the response, andbase64 -ddecodes it into invoice.pdf.
Uploading templates is described in Managing Templates for the Web API and in Template Storage 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:
# Put the template as a Base64 string next to the data
jq template <(base64 0 invoice.docx) \
'{template: $template, mergeData: .}' data.json > merge.json
curl POST "https://api.reporting.cloud/v1/document/merge?returnFormat=PDF&append=true" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@merge.json \
result.json
jq '.[0]' result.json | base64 > 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 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, send it with append=false and decode every document of the response into a file of its own:
# Rebuild merge.json from the current records of data.json
jq '{mergeData: .}' data.json > merge.json
curl POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF&append=false" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@merge.json \
result.json
# One Base64 string per record
count=$(jq 'length' result.json)
for ((i = 0; i < count; i++)); do
jq ".[$i]" result.json | base64 > "invoice-$((i + 1)).pdf"
done
To see two documents, add a second record to the array in data.json, as 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 shows the .NET and PHP calls, and the SDKs section describes each SDK.
Next Steps
- Merge Data: the structure of the JSON data and how the SDKs create it.
- Merge Fields: name, format and check the fields of a template.
- Merge Blocks: repeat table rows for each element of an array.
- Merge Settings: every option of the
mergeSettingsobject.