ReportingCloud

Overview

Topic

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/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

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 and Merge Blocks 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 elementFilled withDescribed in
Merge fieldsA value of the record, or of the current array element inside a blockMerge Fields
Merge blocksOne copy for each element of an array, in any number of nested levelsMerge Blocks, Nested Blocks
Merge blocks bound to optional dataThe block is kept when the data has values for it and removed when notConditional Blocks
Image placeholdersAn image from Base64 data in the recordImages
Merge fields with HTML valuesFormatted text, when mergeHtml is setHTML 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:

ParameterContent
templateNameThe name of a template in your template storage, such as sample_invoice.tx. Without it, the request body must contain the template
returnFormatThe 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
appendWith more than one record, true appends all documents to one document, and false returns one document per record
testtrue 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:

PropertyContent
mergeDataRequired. The data as a JSON array of records, or a single record as a JSON object, described in Merge Data
templateOptional. The template as a Base64 string, in the format RTF, DOC, DOCX, TX or HTML
mergeSettingsOptional. 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 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 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 -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 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 --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 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 -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 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:

SDKMethodWithout an append argument
.NET, NuGet package TXTextControl.ReportingCloudMergeDocument(mergeBody, templateName, returnFormat, append, test)Sends append=True: one document
PHP, Composer package textcontrol/textcontrol-reportingcloudmergeDocument($mergeData, $returnFormat, $templateName, $templateFilename, $append, $mergeSettings)Uses false and leaves the parameter out of the request: one document
JavamergeDocument(mergeBody, templateName, returnFormat, append, test)Sends append=false: one document per record
Rubymerge_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 mergeSettings object.