POST /v1/document/merge
POST https://api.reporting.cloud/v1/document/merge
Description
Merges JSON data into a template and returns the created documents. The template is a stored one, named in templateName, or one sent in the body as a Base64 string. The data is an array of records, or a single record: the members of a record fill the merge fields and merge blocks of the same names, without regard to case. By default, the documents of all records are appended into one; with append=false, every record becomes a document of its own. The response is an array of Base64 strings, in the format returnFormat names, PDF by default. See Mail Merge.
Warning
Document Quota. Each successful request counts 1 against the document quota. It counts 1 also when it returns one document per record. On a trial account, a test run (
test=true) counts as well. Plans and Licensing lists the quota of each plan.
Examples
Request:
curl username:password \
"Content-Type: application/json" \
\
"
{
\"mergeData\": [
{
\"OrderNumber\": \"O2787346623\",
\"Name\": \"JackJohnson\",
\"Articles\": [
{
\"Name\": \"Article1\"
},
{
\"Name\": \"Article2\"
}
]
},
{
\"OrderNumber\": \"O2787346623\",
\"Name\": \"Jack2Johnson2\",
\"Articles\": [
{
\"Name\": \"Article1\"
},
{
\"Name\": \"Article2\"
}
]
}
],
\"template\": null,
\"mergeSettings\": null
}
" \
POST "https://api.reporting.cloud/v1/document/merge?templateName=test_invoice.tx&returnFormat=PDF"
Results:
["JVBERi0xLjQNJeLjz9MNMSAwIG9iago8PAovVH..."]
Request:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using TXTextControl.ReportingCloud;
class RCSamples
{
public static void MergeDocument(string templateName)
{
ReportingCloud rc = new ReportingCloud(
"username",
"password",
new Uri("https://api.reporting.cloud"));
try
{
// create dummy data
Invoice invoice = new Invoice();
invoice.yourcompany_companyname = "Text Control, LLC";
invoice.invoice_no = "Test_R667663";
// create a new MergeBody object
MergeBody body = new MergeBody();
body.MergeData = invoice;
// merge the document
List<byte[]> results = rc.MergeDocument(body, templateName, ReturnFormat.PDF);
foreach (byte[] document in results)
{
string sFilename = Guid.NewGuid().ToString() + ".pdf";
File.WriteAllBytes(sFilename, document);
Console.WriteLine(sFilename + " has been written.");
}
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
}
public class Invoice
{
public string yourcompany_companyname { get; set; }
public string invoice_no { get; set; }
}
}
Results:
67e86845-9b85-4f67-83b5-49151e23b37b.pdf has been written.
Request:
import com.textcontrol.reportingcloud.MergeBody;
import com.textcontrol.reportingcloud.MergeSettings;
import com.textcontrol.reportingcloud.ReportingCloud;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
class NestedItem {
public final int item_no;
public final String item_description;
public final double item_total;
public NestedItem(int item_no, String item_description, double item_total) {
this.item_no = item_no;
this.item_description = item_description;
this.item_total = item_total;
}
}
class MasterItem {
public final ArrayList<NestedItem> item;
public final String recipient_name;
public final String billto_name;
public MasterItem(String recipient_name, String billto_name) {
this.item = new ArrayList<>();
this.recipient_name = recipient_name;
this.billto_name = billto_name;
}
}
public class ReportingCloudSample {
public static void main(String[] args) throws IOException {
// Generate two rows of dummy data:
MasterItem[] mergeData = {
new MasterItem("Will Ferrell", "Colin Farrell"),
new MasterItem("Morgan Freeman", "Martin Freeman")
};
mergeData[0].item.add(new NestedItem(23, "An Item.", 234.56));
mergeData[0].item.add(new NestedItem(34, "Another item.", 345.67));
mergeData[1].item.add(new NestedItem(45, "Yet another item.", 456.78));
mergeData[1].item.add(new NestedItem(56, "And another one.", 567.89));
// Prepare merge settings and merge body objects
MergeSettings mergeSettings = new MergeSettings();
mergeSettings.setAuthor("John Doe");
mergeSettings.setDocumentTitle("A document merged by Text Control ReportingCloud.");
MergeBody mergeBody = new MergeBody(mergeData, mergeSettings);
// Merge the document
ReportingCloud r = new ReportingCloud("username", "password");
List<byte[]> mergeResult = r.mergeDocument(mergeBody, "sample_invoice.tx");
for (int i = 0; i < mergeResult.size(); ++i) {
String fileName = "merge_result_" + String.format("%02d", i) + ".pdf";
Files.write(Paths.get(fileName), mergeResult.get(i));
System.out.println("Merge result written to " + fileName + ".");
}
}
}
Results:
Merge result written to merge_result_00.pdf.
Merge result written to merge_result_01.pdf.
Request:
#!/usr/bin/env ruby
require "txtextcontrol/reportingcloud"
require "txtextcontrol/reportingcloud/merge_body"
require "txtextcontrol/reportingcloud/merge_settings"
require "base64"
reporting_cloud = TXTextControl::ReportingCloud::ReportingCloud.new("username", "password")
# Create two "rows" of dummy merge data
merge_data = [
{
"billto_name" => "Will Ferrell",
"recipient_name" => "Colin Farrell",
"item" => [
{
"item_no" => 23,
"item_description" => "An Item.",
"item_total" => 234.56
},
{
"item_no" => 34,
"item_description" => "Another Item.",
"item_total" => 345.67
}
]
},
{
"billto_name" => "Morgan Freeman",
"recipient_name" => "Martin Freeman",
"item" => [
{
"item_no" => 45,
"item_description" => "Yet another item.",
"item_total" => 456.78
},
{
"item_no" => 56,
"item_description" => "And another one.",
"item_total" => 567.89
}
]
}
]
merge_settings = TXTextControl::ReportingCloud::MergeSettings.new
merge_settings.document_title = "Merged document."
merge_settings.author = "John Doe"
merge_body = TXTextControl::ReportingCloud::MergeBody.new(merge_data, merge_settings)
merge_results = reporting_cloud.merge_document(merge_body, "sample_invoice.tx")
i = 0
while i < merge_results.length do
file_name = "merge_result_#{i.to_s.rjust(2, "0")}.pdf"
File.open(File.dirname(__FILE__) + "/#{file_name}", 'wb') do |f|
f.write(Base64.strict_decode64(merge_results[i]))
end
puts "Merge result written to #{file_name}."
i += 1
end
Results:
Merge result written to merge_result_00.pdf.
Merge result written to merge_result_01.pdf.
Request:
require_once __DIR__ . '/vendor/autoload.php';
use TextControl\ReportingCloud\ReportingCloud;
$reportingCloud = new ReportingCloud([
'api_key' => (string) getenv('REPORTINGCLOUD_API_KEY'),
]);
$mergeData = [
0 => [
'yourcompany_companyname' => 'Text Control, LLC',
'yourcompany_zip' => '28226',
'yourcompany_city' => 'Charlotte',
'yourcompany_street' => '6926 Shannon Willow Rd, Suite 400',
'yourcompany_phone' => '704 544 7445',
'yourcompany_fax' => '704-542-0936',
'yourcompany_url' => 'www.textcontrol.com',
'yourcompany_email' => 'sales@textcontrol.com',
'invoice_no' => '778723',
'billto_name' => 'Joey Montana',
'billto_companyname' => 'Montana, LLC',
'billto_customerid' => '123',
'billto_zip' => '27878',
'billto_city' => 'Charlotte',
'billto_street' => '1 Washington Dr',
'billto_phone' => '887 267 3356',
'payment_due' => '20/1/2016',
'payment_terms' => 'NET 30',
'salesperson_name' => 'Mark Frontier',
'delivery_date' => '20/1/2016',
'delivery_method' => 'Ground',
'delivery_method_terms' => 'NET 30',
'recipient_name' => 'Joey Montana',
'recipient_companyname' => 'Montana, LLC',
'recipient_zip' => '27878',
'recipient_city' => 'Charlotte',
'recipient_street' => '1 Washington Dr',
'recipient_phone' => '887 267 3356',
'item' => [
0 => [
'qty' => '1',
'item_no' => '1',
'item_description' => 'Item description 1',
'item_unitprice' => '2663',
'item_discount' => '20',
'item_total' => '2130.40',
],
1 => [
'qty' => '1',
'item_no' => '2',
'item_description' => 'Item description 2',
'item_unitprice' => '5543',
'item_discount' => '0',
'item_total' => '5543',
],
],
'total_discount' => '532.60',
'total_sub' => '7673.4',
'total_tax' => '537.138',
'total' => '8210.538',
],
];
// copy data 4 times
// total record sets = 5
for ($i = 0; $i < 4; $i++) {
array_push($mergeData, $mergeData[0]);
}
$mergeSettings = [
'creation_date' => time(),
'last_modification_date' => time(),
'remove_empty_blocks' => true,
'remove_empty_fields' => true,
'remove_empty_images' => true,
'remove_trailing_whitespace' => true,
'author' => 'James Henry Trotter',
'creator_application' => 'The Giant Peach',
'document_subject' => 'The Old Green Grasshopper',
'document_title' => 'James and the Giant Peach',
'user_password' => '123456789',
];
$templateName = 'test_template.tx';
$arrayOfBinaryData = $reportingCloud->mergeDocument($mergeData, 'PDF', $templateName, '', false, $mergeSettings);
foreach ($arrayOfBinaryData as $index => $binaryData) {
$destinationFile = sprintf('test_document_%d.pdf', $index);
$destinationFilename = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $destinationFile;
file_put_contents($destinationFilename, $binaryData);
var_dump("Merged {$templateName} was written to {$destinationFilename}");
}
Results:
string(63) "Merged test_template.tx was written to /tmp/test_document_0.pdf"
The five records come back as one PDF of five invoices: the service appends the records when a request leaves append out, and PHP SDK 4.0.5 sends append only when it is true. With the SDK, one document per record takes one request per record.
Authorization
This endpoint requires a "ReportingCloud-APIKey" or a "Basic" user authorization to access the user account, data and templates. Only one of these two methods is required.
API Keys describes how to create an API key, and Authentication explains both header forms.
ReportingCloud-APIKey
| Header field | Description |
|---|---|
| Authorization | Required. A valid ReportingCloud account is required. The Authorization field is constructed as follows: An API key needs to be generated in the portal or with PUT /v1/account/apikey. The authorization method and a space, "ReportingCloud-APIKey ", is then put before the actual API key string. For example: Authorization: ReportingCloud-APIKey oMDM4MrAqL9QEOpyzupnQW5NjvCNtvE5cVDaaLqxI |
Basic
| Header field | Description |
|---|---|
| Authorization | Required. A valid ReportingCloud account is required. The Authorization field is constructed as follows: The user name and password are combined into a string separated by a colon, for example username:password. The resulting string is encoded using the RFC2045-MIME variant of Base64, except not limited to 76 char/line. The authorization method and a space, "Basic ", is then put before the encoded string. For example: Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l |
Request Parameters
| Name | Type | Value | Optional |
|---|---|---|---|
| returnFormat | String | A string that specifies the format of the created document. Possible values are: PDF, PDFA, RTF, DOC, DOCX, HTML, TXT and TX, in any letter case. The default value is PDF. PDFA requires an Extreme license. | yes |
| templateName | String | The name of the template in the template storage, in any letter case. If no template is specified, the template must be uploaded in the MergeBody object of this request. An empty value counts as no template name. If both are given, the template from the template storage is merged and the uploaded one is ignored. | yes |
| append | Boolean | Specifies whether the documents should be appended to one resulting document when more than 1 data row is passed. Left out, or given a value that is not a Boolean, they are appended, as with true. | yes |
| test | Boolean | Specifies whether it is a test run or not. Created documents contain a "TEST MODE" watermark. A test run of this endpoint is counted against the document quota of a trial account. Not possible using the Free license. The default value is false. | yes |
Request Payload
| Type | Value |
|---|---|
| MergeBody | The MergeBody object contains the data source as a JSON data object and optionally, a template encoded as a Base64 string and a ReportingCloud MergeSettings object. |
MergeBody
| Name | Type | Value | Optional |
|---|---|---|---|
| mergeData | JSON array or JSON object | The data source for the merge process: an array of data rows, or one data row as an object. Merge field and merge block names are matched without regard to letter case. | no |
| template | Base64 encoded string | The template encoded as a Base64 string. Supported formats are RTF, DOC, DOCX, TX and HTML. | yes |
| mergeSettings | ReportingCloud MergeSettings object | Optional merge settings to specify merge properties and document properties such as title and author. A property that is null or left out takes its default value. | yes |
MergeSettings
| Name | Type | Value | Optional |
|---|---|---|---|
| removeEmptyFields | Boolean | Specifies whether empty fields should be removed from the template or not. The default value is true. | yes |
| removeEmptyBlocks | Boolean | Specifies whether the content of empty merge blocks should be removed from the template or not. A block is empty when its array is empty or missing. The default value is true. | yes |
| removeEmptyImages | Boolean | Specifies whether images which don't have merge data should be removed from the template or not. The default value is false. | yes |
| removeEmptyLines | Boolean | Specifies whether lines should be removed that contain only empty fields and no other content. The default value is false. | yes |
| removeTrailingWhitespace | Boolean | Specifies whether trailing whitespace should be removed before saving a document. The default value is true. | yes |
| mergeHtml | Boolean | Specifies whether field data can contain formatted HTML content or not. The default value is false. HTML content must be enclosed in an <html> tag element. Only active in the Merge endpoint. | yes |
| author | String | Sets the document's author. | yes |
| creationDate | DateTime (String) | Sets the document's creation date which will be saved in the document. | yes |
| lastModificationDate | DateTime (String) | Sets the date the document is last modified. | yes |
| creatorApplication | String | Sets the application, which has created the document. | yes |
| documentSubject | String | Sets the document's subject string which will be saved in the document. | yes |
| documentTitle | String | Sets the document's title that will be saved in the document. | yes |
| userPassword | String | Specifies the password for the user to open the document. A PDF is encrypted with it, while a DOCX is returned without a password. | yes |
| culture | String | Specifies the culture for the merge process for date and currency values. It must be a Language Culture Name of Microsoft's Table of Language Culture Names, Codes, and ISO Values. For French use "fr-FR", for German "de-DE". Default is English "en-US". The data is read in this culture as well: with "de-DE", the value "1234.5" is not taken as a number and is merged as it is. | yes |
Success Response
| Status | Description |
|---|---|
| 200 | On success, the HTTP status code in the response header is 200 (OK). The response body contains an array of the created documents encoded as Base64 encoded strings. |
Error Response
| Status | Description |
|---|---|
| 400 | A 400 (Bad Request) is returned, if the request body is empty or isn't JSON, the MergeBody object has no mergeData, no template is uploaded and the template is not found in the template storage, or returnFormat is not one of the possible values. |
| 403 | A 403 (Forbidden) is returned, if the user is not authorized, the document quota is exceeded, more than 2 concurrent requests came in from the same account or the return format PDFA is requested without an Extreme license. |
| 405 | A 405 (Method Not Allowed) is returned, if the request uses another HTTP method than POST. The Allow header of the response names POST. |
| 411 | A 411 (Length Required) is returned, if the request has neither a body nor a Content-Length header. |
| 415 | A 415 (Unsupported Media Type) is returned, if the request has a body but no Content-Type header, or a Content-Type such as text/plain that the endpoint doesn't read. Send Content-Type: application/json. |
| 500 | A 500 (Internal Server Error) is returned, if the request has no Authorization header, an empty one or one that is not the authorization method, a space and the credentials, or if returnFormat is empty, the template is not a valid Base64 string or a MergeSettings property has a value of the wrong type. |
Timeout Limitation. The pure processing time is limited to a maximum of 60 seconds. After this period of time, the task is canceled.
A typical document should not take more than 5 seconds. If your request takes longer, decrease the number of data rows and reduce the template size.