Templates and Merging
A merge request goes wrong in one of two ways. The Web API refuses it with 400 Bad Request because the template or the data is missing, or it returns a document that isn't what you expected: values are missing, a table is gone, an amount shows the wrong currency or HTML tags aren't applied. In both cases the cause lies in the request, in the template name, the JSON data or the mergeSettings. Most problems below can be traced by comparing the template with the data, so start there.
Compare the Template With Your Data
A merge field gets its value from the key of the same name in a record of mergeData, and a merge block repeats once for each item of the array of the same name. GET /v1/templates/info lists the fields and blocks of a stored template, with their nesting and formats:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/info?templateName=sample_invoice.tx"
The response holds the top-level fields in mergeFields and the blocks in mergeBlocks, each block with its own fields and nested blocks. Compare these names with the keys of your JSON: Check the Field Names of a Template shows the response for the demo template, and The Structure of the Data the data that matches it.
The Request Returns 400 Bad Request
A document or template request returns 400 Bad Request. The reference names three kinds of causes: a template that isn't in the template storage, a body without data and a document or template that isn't valid. Bad Request lists the causes of each endpoint.
The sections below cover the three cases you meet most often: a template name the storage doesn't know, a body without data and an upload that is refused.
The Template Isn't Found
A merge request with templateName, or a request to GET /v1/templates/info or another template endpoint, returns 400, and the template name looks right.
The name has to match the file name in the template storage, extension included, such as sample_invoice.tx. Only the letter case may differ: Sample_Invoice.TX names the same template. The template may also have been deleted, or never uploaded to this account. A new trial account has the demo template sample_invoice.tx in its storage.
Check whether the storage has a template of this name with GET /v1/templates/exists. It returns
trueorfalse:curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \ "https://api.reporting.cloud/v1/templates/exists?templateName=sample_invoice.tx"If it returns
false, list the names in the storage with GET /v1/templates/list or under My Templates in the portal. Correct the name in your request.If the template isn't in the list, upload it under that name with POST /v1/templates/upload, or send it with the request in the
templatefield of theMergeBody, as a Base64 string.
The Request Has No Data
A merge request returns 400 although the template exists.
The service found no data in the MergeBody, or no template. The body is a JSON object whose mergeData holds the records as a JSON array, and the template comes from the query parameter templateName or from the template field of the body.
Send the body as JSON, with the header
Content-Type: application/json.Check the structure of the body. Save it as merge.json, for example:
{ "mergeData": [ { "invoice_no": "778723", "billto_name": "Joey Montana", "item": [ { "qty": "1", "item_no": "1", "item_description": "Item description 1", "item_total": "2130.40" } ] } ] }Send it with the template name and the return format in the query string:
curl POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF" \ "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \ "Content-Type: application/json" \ @merge.json
The option --data @merge.json reads the body from the file. Merge Data describes the format of mergeData in full.
A Template Upload Returns 400
POST /v1/templates/upload returns 400.
The service couldn't read the template: its format isn't supported, or the file arrived damaged. The endpoint accepts DOC, DOCX, RTF and TX files, sent as a Base64 string in a JSON string.
- Check that the file is a DOC, DOCX, RTF or TX document.
- Encode the whole file as one Base64 string without line breaks, for example with
base64 -w 0 invoice.docx. - Send the string in quotes as the body, as Upload a Template shows.
Fields Are Empty in the Document
The merged document lacks values where the template has merge fields, and the text of the fields is gone.
A field without data is removed, because removeEmptyFields is true unless you set it to false. A field has no data when the record has no key of its name: the name is spelled differently, the key is on another level or the value is missing. The merge matches names regardless of letter case, so only a different spelling counts: invoice_no and invoiceNo are different names.
- Get the field names with
GET /v1/templates/info, as Compare the Template With Your Data shows, and compare them with the keys of your JSON. - Put the keys of top-level fields into the record itself, and the keys of fields inside a block into the objects of the array that carries the block's name.
- When an SDK creates the JSON from your objects, compare the names it sends. The .NET SDK writes property names in camel case, so a property
InvoiceNumberbecomes the keyinvoiceNumber, which still fills a fieldInvoiceNumber; a propertyInvoiceNodoesn't fill a fieldinvoice_no. Name Fields After the Data describes the rules.
Empty Lines Remain Where Fields Had No Data
The document has blank lines where a line of the template held only merge fields without data, such as a second address line.
removeEmptyLines is false unless you set it, so a line that held only empty fields stays as an empty line. Remove such lines with the setting:
Add
removeEmptyLinesto themergeSettingsof the request:{ "mergeData": [ { "invoice_no": "778723" } ], "mergeSettings": { "removeEmptyLines": true } }Merge again. Lines with other content besides the empty fields stay.
Of the SDKs, only the .NET SDK offers the setting, as the RemoveEmptyLines property of MergeSettings. With the PHP, Java or Ruby SDK, send the request to the Web API directly. Merge Settings lists the settings of each SDK.
A Merge Block Is Missing
A table row or a section that should repeat for each item is missing from the document.
A block without data is removed, because removeEmptyBlocks is true unless you set it to false. This is also how conditional blocks work. A block has no data when the record has no array with the block's name, when the array is empty or when the array of a nested block isn't inside the items of the outer block.
- Get the block names and their nesting with
GET /v1/templates/info, inmergeBlocks. - Name the array exactly like the block, on the level of the block: a top-level block is a key of the record, and a nested block is a key of each item of the outer block's array.
- To keep a block in the document when it has no data, set
removeEmptyBlockstofalsein themergeSettings.
Merge Blocks, Nested Blocks and Conditional Blocks describe the data each kind of block needs.
A Merged Image Is Missing
An image placeholder of the template doesn't show the image from your data.
The record has no value under the name of the column the placeholder is bound to, or the value isn't the Base64 string of a JPG, PNG, BMP or GIF image. removeEmptyImages is false unless you set it, so a placeholder without data stays in the document.
- In the template editor, right-click the image and check under Select Object Data Source which column it is bound to.
- Check that the record has a key of that name, and that its value is the Base64 string of a JPG, PNG, BMP or GIF image.
- To remove placeholders that have no data, set
removeEmptyImagestotrue.
Images walks through a template with an image placeholder.
Dates and Currency Values Have the Wrong Format
A price shows the dollar sign where you expect the euro, or a long date appears in English.
The merge formats dates and currency values for a culture, and the culture is en-US unless you set another one. The culture shows in the fields that the template formats: with a numeric format such as C for currency, or with a date format.
Set the culture in the
mergeSettingsto a language culture name, such asde-DEfor German orfr-FRfor French:{ "mergeSettings": { "culture": "de-DE" } }Check the formats of the fields:
GET /v1/templates/inforeturns them innumericFormatanddateTimeFormat. An empty value means that the template sets no format for the field. Set one in the template editor, in the options of the merge field.
The Java and Ruby SDKs have no culture setting; send a merge with another culture to the Web API directly. Culture shows the field options and the effect of each culture.
HTML Formatting Isn't Applied
Field data that contains HTML, such as <strong> or <em>, isn't merged as formatted text.
HTML in field data is only interpreted when mergeHtml is true in the mergeSettings, the complete value is enclosed in an <html> element and the request goes to POST /v1/document/merge. mergeHtml is false unless you set it, and the font name, size and colors come from the field in the template, not from the HTML.
Set
mergeHtmltotrueand enclose the value in<html>and</html>:{ "mergeData": [ { "comments": "<html><strong>Delivery</strong> within <em>five</em> business days</html>" } ], "mergeSettings": { "mergeHtml": true } }Send the request to
document/merge.Set the font, size and color of the text on the merge field in the template, not in the HTML.
HTML Content shows a template with a comments field and the merged result.
The Number of Documents Isn't What You Expect
You get one document for several records, or several documents where you expected one.
The merge creates one document for each record of mergeData when the request sends append=false. With append=true, or with no append at all, it appends them to one document instead. The SDKs don't share a default: MergeDocument of the .NET SDK appends unless you pass false, mergeDocument of the Java SDK and merge_document of the Ruby gem send false unless you pass true, and mergeDocument of the PHP SDK sends append only when it is true, so the service appends whatever you pass.
- Pass
appendwith every request, so that the result doesn't depend on a default:append=trueorappend=falsein the query string, or theappendargument of the SDK method. With the PHP SDK, which can't sendfalse, merge one record per request. - Read every element of the result: the response is an array with one document per element.
The Saved Document Doesn't Open
You saved the response of a merge request as invoice.pdf, and the file doesn't open as a PDF.
The Web API doesn't return the PDF itself. The response body is a JSON array that holds each created document as a Base64 string. The .NET, Java and PHP SDKs decode it for you; the Ruby SDK returns the Base64 strings, which you decode yourself.
Save the response to a file:
curl POST "https://api.reporting.cloud/v1/document/merge?templateName=sample_invoice.tx&returnFormat=PDF" \ "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \ "Content-Type: application/json" \ @merge.json \ response.jsonTake the first element of the array and decode it, for example with jq:
jq '.[0]' response.json | base64 > invoice.pdf
Web API in Getting Started walks through this request from the start.