diff --git a/src/pages/api/index.md b/src/pages/api/index.md
index 6cc047d..c382e80 100644
--- a/src/pages/api/index.md
+++ b/src/pages/api/index.md
@@ -13,6 +13,7 @@ keywords:
- Remap Links API
- Document Info API
- Convert PDF to InDesign API
+ - Convert InDesign to IDML API
- REST API
- cloud services
- enterprise solutions
diff --git a/src/pages/config.md b/src/pages/config.md
index 20be44e..cbf86da 100644
--- a/src/pages/config.md
+++ b/src/pages/config.md
@@ -33,6 +33,9 @@
- Guides header
- [Working with Custom Scripts API](/guides/working-with-custom-scripts-api/index.md)
- [Working with Data Merge API](/guides/working-with-datamerge-api/index.md)
+ - [Working with Advanced Data Merge API](/guides/working-with-advanced-data-merge-api/index.md)
- [Working with Rendition API](/guides/working-with-rendition-api/index.md)
+ - [Working with the Convert InDesign to IDML API](/guides/working-with-convert-indesign-to-idml-api/index.md)
- [Writing Scripts for Custom Scripts API](/guides/writing-scripts-for-custom-scripts-api/index.md)
- [Tips for PDF to InDesign Conversion](/guides/pdf-to-indesign-conversion-notes/index.md)
+ - [Using Adobe Fonts](/guides/using-adobe-fonts/index.md)
diff --git a/src/pages/contributors.json b/src/pages/contributors.json
index b47b291..b28d602 100644
--- a/src/pages/contributors.json
+++ b/src/pages/contributors.json
@@ -1,35 +1,39 @@
{
- "total": 13,
+ "total": 16,
"offset": 0,
- "limit": 13,
+ "limit": 16,
"data": [
{
"page": "/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/264675027?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4",
"https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/51445330?v=4",
"https://avatars.githubusercontent.com/u/175690214?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4"
],
- "lastUpdated": "3/12/2026"
+ "lastUpdated": "11/2/2026"
},
{
"page": "/api/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/264675027?v=4",
"https://avatars.githubusercontent.com/u/51445330?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4"
],
- "lastUpdated": "2/27/2026"
+ "lastUpdated": "11/2/2026"
},
{
"page": "/config",
"avatars": [
+ "https://avatars.githubusercontent.com/u/264675027?v=4",
+ "https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4"
],
- "lastUpdated": "5/4/2026"
+ "lastUpdated": "11/2/2026"
},
{
"page": "/getting-started/",
@@ -42,37 +46,40 @@
"page": "/getting-started/changelog/",
"avatars": [
"https://avatars.githubusercontent.com/u/66052604?v=4",
- "https://avatars.githubusercontent.com/u/274493592?v=4",
"https://avatars.githubusercontent.com/u/264675027?v=4",
+ "https://avatars.githubusercontent.com/u/274493592?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4"
],
- "lastUpdated": "6/17/2026"
+ "lastUpdated": "11/2/2026"
},
{
"page": "/getting-started/concepts/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/175690214?v=4",
"https://avatars.githubusercontent.com/u/264675027?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4"
],
- "lastUpdated": "3/20/2026"
+ "lastUpdated": "8/27/2026"
},
{
"page": "/getting-started/usage/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/175690214?v=4",
"https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4"
],
- "lastUpdated": "6/17/2026"
+ "lastUpdated": "10/27/2026"
},
{
"page": "/guides/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/264675027?v=4",
+ "https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4",
- "https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/51445330?v=4"
],
- "lastUpdated": "3/26/2026"
+ "lastUpdated": "11/2/2026"
},
{
"page": "/guides/pdf-to-indesign-conversion-notes/",
@@ -82,6 +89,28 @@
],
"lastUpdated": "3/26/2026"
},
+ {
+ "page": "/guides/using-adobe-fonts/",
+ "avatars": [
+ "https://avatars.githubusercontent.com/u/66052604?v=4"
+ ],
+ "lastUpdated": "11/1/2026"
+ },
+ {
+ "page": "/guides/working-with-advanced-data-merge-api/",
+ "avatars": [
+ "https://avatars.githubusercontent.com/u/66052604?v=4",
+ "https://avatars.githubusercontent.com/u/274493592?v=4"
+ ],
+ "lastUpdated": "11/1/2026"
+ },
+ {
+ "page": "/guides/working-with-convert-indesign-to-idml-api/",
+ "avatars": [
+ "https://avatars.githubusercontent.com/u/264675027?v=4"
+ ],
+ "lastUpdated": "11/2/2026"
+ },
{
"page": "/guides/working-with-custom-scripts-api/",
"avatars": [
@@ -96,20 +125,22 @@
{
"page": "/guides/working-with-datamerge-api/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/175690214?v=4",
+ "https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/274493592?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4",
- "https://avatars.githubusercontent.com/u/66052604?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4"
],
- "lastUpdated": "5/5/2026"
+ "lastUpdated": "8/27/2026"
},
{
"page": "/guides/working-with-rendition-api/",
"avatars": [
+ "https://avatars.githubusercontent.com/u/175690214?v=4",
"https://avatars.githubusercontent.com/u/41382203?v=4",
"https://avatars.githubusercontent.com/u/195011431?v=4"
],
- "lastUpdated": "2/25/2026"
+ "lastUpdated": "8/27/2026"
},
{
"page": "/guides/writing-scripts-for-custom-scripts-api/",
diff --git a/src/pages/getting-started/changelog/index.md b/src/pages/getting-started/changelog/index.md
index 1117017..6a3142d 100644
--- a/src/pages/getting-started/changelog/index.md
+++ b/src/pages/getting-started/changelog/index.md
@@ -13,6 +13,7 @@ keywords:
- Custom Scripts API
- Remap Links API
- Convert PDF to InDesign API
+ - Convert InDesign to IDML API
- PDF to InDesign
- REST API
- cloud services
@@ -41,6 +42,27 @@ twitter:
This page contains the release notes and version history for Adobe InDesign APIs. Stay updated with the latest features, improvements, and bug fixes.
+## November 2, 2026
+
+### New Features
+
+*Convert InDesign to IDML API*
+
+- **Convert an InDesign document to IDML:** New `POST /v3/convert-indesign-to-idml` endpoint converts an INDD file to IDML. [View endpoint documentation][22]. See [Working with the Convert InDesign to IDML API][23] for a quickstart.
+
+*Advanced Data Merge*
+
+- **Output Path Structure**: The `POST /v4/merge-data` endpoint no longer nests outputs into `rangeN` batch subfolders. Every output file is written directly into the resolved output folder, and naming collisions between batches or records are resolved with a `(n)` suffix on the filename instead. [Learn more about output path variations.][20]
+- **Parameter Name Change**: The `pagesPerDocument` parameter from the base Data Merge API has been renamed to `recordsPerFile` in the `POST /v4/merge-data` endpoint. The underlying behavior is unchanged. [Learn more about the parameter name change.][21]
+- **Conditional Visibility & Dynamic Styling**: The `POST /v4/merge-data` endpoint now accepts a `rulesFile` parameter, letting a rules JSON file show/hide layers, frames, and placeholders, restyle and recolor content, replace text, and resize or move frames — differently per record. [Learn more about conditional visibility & dynamic styling.][16]
+- **Copyfitting**: New `copyfittingSettings` object in `params` automatically reduces font size within defined limits to resolve overset text after a merge. [Learn more about copyfitting.][17]
+- **Folder Structure & Zipped Output**: The `POST /v4/merge-data` endpoint supports organizing merge outputs into a folder hierarchy via a `~`-prefixed CSV column, plus optional zipped output using `outputCompressMediaType`. [Learn more about folder structure and zipped output.][18]
+- **Pre-signed URL Support in CSV**: A new `preSignedURL` parameter allows image placeholder columns (prefixed with `@`) to contain pre-signed URLs directly in the CSV, fetched during the merge. [Learn more about pre-signed URL support.][19]
+
+*Adobe Fonts Enablement*
+
+- **Adobe Fonts Free library support**: InDesign API can now resolve fonts from the [Adobe Fonts Free library](https://fonts.adobe.com/fonts?library=basic) automatically through your Adobe entitlement, so you no longer need to upload or host those font files. To enable this feature, add a Fonts-enabled product profile to your API credential. [Learn more about using Adobe Fonts.][24]
+
## June 2, 2026
### Enhancements
@@ -145,3 +167,12 @@ This page contains the release notes and version history for Adobe InDesign APIs
[13]: ../concepts/index.md#api-capability-naming-rules
[14]: ../../guides/working-with-datamerge-api/index.md#variable-file-naming-support-in-data-merge-api
[15]: ../usage/index.md#file-size-limits
+[16]: ../../guides/working-with-advanced-data-merge-api/index.md#conditional-visibility--dynamic-styling
+[17]: ../../guides/working-with-advanced-data-merge-api/index.md#copyfitting
+[18]: ../../guides/working-with-advanced-data-merge-api/index.md#folder-structure-and-zipped-output
+[19]: ../../guides/working-with-advanced-data-merge-api/index.md#pre-signed-url-support-in-csv
+[20]: ../../guides/working-with-advanced-data-merge-api/index.md#output-path-variations-in-advanced-data-merge-api
+[21]: ../../guides/working-with-advanced-data-merge-api/index.md#parameter-name-change-in-advanced-data-merge-api
+[22]: ../../api/index.md#tag/Convert-InDesign-to-IDML
+[23]: ../../guides/working-with-convert-indesign-to-idml-api/index.md
+[24]: ../../guides/using-adobe-fonts/index.md
diff --git a/src/pages/getting-started/concepts/index.md b/src/pages/getting-started/concepts/index.md
index f5075fa..a0b7f85 100644
--- a/src/pages/getting-started/concepts/index.md
+++ b/src/pages/getting-started/concepts/index.md
@@ -92,6 +92,25 @@ platform can upload. You can provide this information in the `outputs` array wit
Each storage provider may have its own requirements for creating PUT or POST pre-signed URLs. Please follow the documentation from the individual storage provider creating these URLs.
+## Output file naming convention
+
+When a request produces more than one output file from a single base name (for example, one file per page in the [Rendition API][10], or one file per record in the [Data Merge API][11]), the file names follow InDesign's own native sequential-export naming convention — not an underscore- or hyphen-delimited scheme:
+
+- The first file uses the base name as-is: `{outputFileBaseString}.{ext}`
+- Each subsequent file appends its index directly after the base name, with no separator: `{outputFileBaseString}{index}.{ext}`
+- `{ext}` is derived from the requested `outputMediaType` (for example, `image/png` → `.png`, `image/jpeg` → `.jpg`).
+
+For example, with `outputFileBaseString` set to `banner`:
+
+- `banner.png`
+- `banner2.png`
+- `banner3.png`
+- ...
+
+**Caution:** Because there is no separator, a base string that ends in a digit makes the generated file names ambiguous to parse back into base + index without already knowing the base string. For example, base string `hero9` at index 10 produces `hero910.png`, which is indistinguishable from base string `hero91` at index 0. Avoid base strings that end in a digit if your integration needs to derive the page or record index from the file name, or track expected file names by position/index rather than by parsing the generated name.
+
+If you register per-file destinations using the `outputs` array (see [Output assets](#output-assets)), predict each file's name using this convention when setting its `source` field — a mismatched `source` means that file silently fails to upload to your registered destination.
+
## About custom script bundles
To create a script to use with the Custom Scripts API, you'll need to prepare a script bundle, a ZIP file with a predefined structure.
@@ -436,3 +455,5 @@ Once validation is complete, update your production scripts to use the new app v
[7]: https://learn.microsoft.com/en-us/azure/ai-services/translator/document-translation/how-to-guides/create-sas-tokens?tabs=Containers
[8]: ../../guides/writing-scripts-for-custom-scripts-api/index.md
[9]: https://developer.adobe.com/events/docs/guides/using/indesign-apis/indesign-apis-events-data-stream-setup/
+[10]: ../../guides/working-with-rendition-api/index.md
+[11]: ../../guides/working-with-datamerge-api/index.md
diff --git a/src/pages/getting-started/usage/index.md b/src/pages/getting-started/usage/index.md
index a0252f4..9e34d87 100644
--- a/src/pages/getting-started/usage/index.md
+++ b/src/pages/getting-started/usage/index.md
@@ -34,15 +34,19 @@ For the latest updates, new features, and bug fixes, [check InDesign's changelog
To maintain API stability and fair usage across clients, the following limits are enforced:
-* Soft limit: 250 requests per minute across all endpoints. Once this limit is crossed, you may experience slower responses.
+* General API requests: A hard limit of 250 requests per minute (RPM) applies across all endpoints except the Status API. You can send all 250 requests at once. Once the limit is reached, additional requests within the same one-minute window are throttled.
-* Hard limit: 350 requests per minute. Requests beyond this limit are rejected.
+* Status API requests: These do not count toward the 250 RPM limit and have a separate rate limit of 1,000 RPM.
### File size limits
* Assets: Maximum supported size is 2GB per asset.
* Custom Scripts API: Maximum allowed size for a Custom Script ZIP upload is 5MB.
+### Payload size limit
+
+The total request payload size must not exceed 1 MB.
+
### Assets
The number of assets (input + output) that can be passed in a single payload is 1000.
diff --git a/src/pages/guides/index.md b/src/pages/guides/index.md
index 8c708f8..cf37267 100644
--- a/src/pages/guides/index.md
+++ b/src/pages/guides/index.md
@@ -8,6 +8,7 @@ keywords:
- document processing
- Data Merge API
- Rendition API
+ - Convert InDesign to IDML API
- Custom Scripts API
- Remap Links API
- REST API
@@ -32,8 +33,12 @@ This guide covers advanced scripting techniques for automating InDesign tasks.
- [Working with Custom Scripts API](./working-with-custom-scripts-api/index.md) - Advanced scripting techniques
- [Writing Scripts for Custom Scripts API](./writing-scripts-for-custom-scripts-api/index.md) - Script development and logging
- [Working with Data Merge API](./working-with-datamerge-api/index.md) - Data merge automation
+- [Working with Advanced Data Merge API](./working-with-advanced-data-merge-api/index.md) - Advanced data merge techniques, Conditional Visibility, Styling, Copyfitting and more
- [Working with Rendition API](./working-with-rendition-api/index.md) - Document rendering
+- [Working with the Convert InDesign to IDML API](./working-with-convert-indesign-to-idml-api/index.md) - Convert an InDesign document to IDML
- [Tips for PDF to InDesign Conversion](./pdf-to-indesign-conversion-notes/index.md) - PDF To InDesign Points to note and limitations
+- [Using Adobe Fonts(Free) with InDesign API](./using-adobe-fonts/index.md) - Enable Free Adobe Fonts
+
diff --git a/src/pages/guides/using-adobe-fonts/index.md b/src/pages/guides/using-adobe-fonts/index.md
new file mode 100644
index 0000000..1edf9af
--- /dev/null
+++ b/src/pages/guides/using-adobe-fonts/index.md
@@ -0,0 +1,170 @@
+---
+title: Using Adobe Fonts with InDesign API
+description: Use fonts from the Adobe Fonts Free library with InDesign API without uploading or hosting font files.
+keywords:
+ - Adobe InDesign API
+ - Adobe Fonts
+ - fonts
+ - missing fonts
+ - missingFontStrategy
+ - Admin Console
+ - product profile
+ - custom fonts
+hideBreadcrumbNav: true
+---
+
+# Using Adobe Fonts with InDesign API
+
+InDesign API supports rendering documents that use fonts from the Adobe Fonts Free library. Fonts used in your InDesign documents are resolved automatically through your Adobe entitlement, so you do not need to upload or host those font files yourself.
+
+
+
+**Note:** This feature supports only fonts in the [Adobe Fonts Free library](https://fonts.adobe.com/fonts?library=basic). To use any other font, provide the font file as an asset using a pre-signed URL.
+
+## Prerequisites
+
+- A valid Firefly Services API key and access token. See [Authentication](../../getting-started/index.md).
+- An Adobe entitlement that includes Adobe Fonts access.
+- A font from the [Adobe Fonts Free library](https://fonts.adobe.com/fonts?library=basic).
+- A Fonts product profile configured in the Adobe Admin Console and added to your credential in the Adobe Developer Console.
+
+
+## Admin Console setup
+
+Before you can use fonts from the Free library of Adobe Fonts in API calls, your organization must have a Fonts service enabled on a product profile in the Adobe Admin Console, and that profile must be associated with your API credential.
+
+### Step 1: Create a product profile with Fonts enabled
+
+1. Sign in to the [Adobe Admin Console](https://adminconsole.adobe.com/).
+2. Go to **Products** and select **Firefly Creative Production for Enterprise**.
+3. Click **New profile** and follow the setup steps.
+4. On the **Enable services** step, ensure the **Fonts** toggle is turned on.
+5. Click **Save**.
+
+For detailed instructions on creating product profiles, see [Create product profiles](https://helpx.adobe.com/business/enterprise/products-entitlements/manage-product-profiles/create-product-profiles.html).
+
+### Step 2: Add the product profile to your project in Developer Console
+
+1. Sign in to the [Adobe Developer Console](https://developer.adobe.com/console).
+2. Open your project. You will land on the project overview page showing your products and credentials.
+3. Under **Products & services**, click the **InDesign API - Firefly Services** title to open the API detail page.
+4. On the API detail page, click **Edit product profiles**.
+5. Add the Fonts-enabled profile you created in Step 1 and save.
+
+Once the profile is linked to your project, API calls made with that credential will have access to the fonts in the Adobe Fonts Free library.
+
+## How it works
+
+When InDesign API opens a document, it looks for every font used in the document. Fonts that are not supplied as assets (for example, in a `Document Fonts` folder or a configured font directory) are resolved through Adobe Fonts at processing time. No font file URL is required.
+
+Only fonts from the [Adobe Fonts Free library](https://fonts.adobe.com/fonts?library=basic) can be resolved. If a font cannot be resolved because it is not in the Adobe Fonts Free library, or because it is not provided as input asset, the job will either fail or fallback to a default font, depending on your `missingFontStrategy` setting.
+
+## Request structure
+
+No additional parameters are needed to use Adobe Fonts. Use the `generalSettings.fonts` object in `params` to control how missing fonts are handled.
+
+```json
+{
+ "assets": [
+ {
+ "source": {
+ "url": ""
+ },
+ "destination": "Document.indd"
+ }
+ ],
+ "params": {
+ "generalSettings": {
+ "fonts": {
+ "missingFontStrategy": "fail"
+ }
+ },
+ "targetDocuments": [
+ "Document.indd"
+ ],
+ "outputMediaType": "application/pdf"
+ }
+}
+```
+
+## fonts reference
+
+| Property | Type | Description |
+| --- | --- | --- |
+| `missingFontStrategy` | string | Strategy to use when a font cannot be found. One of `fallback` or `fail`. Defaults to `fallback`. |
+
+
+## Submitting a request
+
+Submit the job:
+
+```curl
+curl -X POST "https://indesign.adobe.io/v3/create-rendition" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
+ -H "x-api-key: YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "assets": [
+ {
+ "source": {
+ "url": ""
+ },
+ "destination": "Document.indd"
+ }
+ ],
+ "params": {
+ "targetDocuments": [
+ "Document.indd"
+ ],
+ "outputMediaType": "application/pdf",
+ "generalSettings": {
+ "fonts": {
+ "missingFontStrategy": "fail"
+ }
+ }
+ }
+ }'
+```
+
+A successful submission returns a `202` response with a `jobId` and `statusUrl`:
+
+```json
+{
+ "jobId": "9b9d00c5-8659-4766-8430-ed0a1c9bd87d",
+ "statusUrl": "https://indesign.adobe.io/v3/status/9b9d00c5-8659-4766-8430-ed0a1c9bd87d"
+}
+```
+
+
+## Error handling
+
+| Scenario | `missingFontStrategy` | Result |
+| --- | --- | --- |
+| Font is not in the Adobe Fonts Free library and not supplied as an asset | `fallback` | The job completes using a default font. The font is reported under `warnings.missingFonts` in the job status. |
+| Font is not in the Adobe Fonts Free library and not supplied as an asset | `fail` | The job fails. |
+| Fonts product profile is not added to your credential | `fallback` / `fail` | Adobe Fonts are not used to resolve any missing fonts. |
+
+## Using custom fonts
+
+If you need a font that is not in the Adobe Fonts Free library, including any Adobe Fonts that are in the Paid library, supply it as an asset. The font file must be accessible via a [pre-signed URL](../../getting-started/concepts/index.md#Pre-signed-URLs). Place it in a `Document Fonts` folder parallel to the document so it is found by default.
+
+```json
+{
+ "assets": [
+ {
+ "source": {
+ "url": ""
+ },
+ "destination": "Document.indd"
+ },
+ {
+ "source": {
+ "url": ""
+ },
+ "destination": "Document Fonts/CustomFont-Regular.otf"
+ }
+ ]
+}
+```
+
+For more details, see [Using custom fonts](../../getting-started/concepts/index.md#using-custom-fonts).
diff --git a/src/pages/guides/working-with-advanced-data-merge-api/index.md b/src/pages/guides/working-with-advanced-data-merge-api/index.md
new file mode 100644
index 0000000..5e29d5e
--- /dev/null
+++ b/src/pages/guides/working-with-advanced-data-merge-api/index.md
@@ -0,0 +1,936 @@
+---
+title: Working with Advanced Data Merge API
+description: >-
+ Advanced Data Merge API techniques for InDesign automation
+ and document processing.
+keywords:
+ - Adobe InDesign API
+ - InDesign automation
+ - document processing
+ - Data Merge API
+ - Rendition API
+ - Custom Scripts API
+ - Remap Links API
+ - REST API
+ - cloud services
+ - enterprise solutions
+ - design automation
+ - creative automation
+ - content delivery
+ - batch processing
+og:
+ title: Working with Advanced Data Merge API
+ description: >-
+ Advanced Data Merge API techniques for InDesign automation
+ and document processing.
+twitter:
+ card: summary
+ title: Working with Advanced Data Merge API
+ description: >-
+ Advanced Data Merge API techniques for InDesign automation
+ and document processing.
+---
+# Working with Advanced Data Merge API
+
+This guide covers advanced techniques for the [Data Merge API](../../api/index.md), building on the basics from [Working with the Data Merge API](../working-with-datamerge-api/index.md), including output path variations, conditional visibility, dynamic styling, copyfitting, zip output and pre-signed URL support in CSV.
+
+## Output Path Variations in Advanced Data Merge API
+
+This section explains where the Advanced Data Merge API writes its output files, and how that location and filename change depending on whether you provide the `outputFolderPath` and `outputFileBaseString` parameters in the request. There are four possible combinations of these two parameters; the table below summarizes all four before the detailed cases and examples that follow.
+
+| | `outputFileBaseString` omitted | `outputFileBaseString` provided |
+|---|---|---|
+| **`outputFolderPath` omitted** | [Case 1](#case-1-both-parameters-missing): temporary folder, filename from source document | [Case 2](#case-2-only-outputfilebasestring-provided): temporary folder, filename from base string |
+| **`outputFolderPath` provided** | [Case 3](#case-3-only-outputfolderpath-provided): `outputFolderPath`, filename from source document | [Case 4](#case-4-both-parameters-provided): `outputFolderPath`, filename from base string |
+
+Unlike the base [Data Merge API](../working-with-datamerge-api/index.md#output-path-variations-in-data-merge-api), the Advanced Data Merge API does **not** nest outputs into `range1`, `range2`, ... subfolders. Every output file for a job is written directly into the resolved output folder (temporary or `outputFolderPath`); any naming collision — between batches or between records — is resolved with a `(n)` suffix on the filename itself instead of a subfolder.
+
+#### Comparing v3 and v4 output structure
+
+To see that difference concretely, here is the same job — `outputFolderPath`: `"ResultFolder"`, `outputFileBaseString`: `"MergedOutput"`, output split into two batches — under each API version:
+
+Base API (v3):
+- `ResultFolder/range1/MergedOutput.pdf`
+- `ResultFolder/range2/MergedOutput.pdf`
+
+Advanced Data Merge API (v4):
+- `ResultFolder/MergedOutput.pdf`
+- `ResultFolder/MergedOutput(1).pdf`
+
+v3 gives each batch its own `rangeN` folder and reuses the same filename inside each one; v4 writes every batch into the same flat folder and disambiguates them with a `(n)` suffix on the filename instead.
+
+#### Case 1: Both Parameters Missing
+
+When neither `outputFolderPath` nor `outputFileBaseString` is provided:
+
+- Output is created in a temporary folder with a random number prefix (e.g. tmp0696)
+- The output filename is derived from the original document filename
+
+Example:
+
+- Source: `Template.indd`
+- Output: `tmp0696/Template.indd`
+- In case of multiple output documents/pdf (e.g. `recordsPerFile` splits the merge into more than one batch):
+ - `tmp0696/Template.indd`
+ - `tmp0696/Template(1).indd`
+ - `tmp0696/Template.pdf`
+ - `tmp0696/Template(1).pdf`
+- For PNG/JPEG outputs (one image per record):
+ - `tmp0696/Template.png`
+ - `tmp0696/Template(1).png`
+ - `tmp0696/Template(2).png`
+
+#### Case 2: Only outputFileBaseString Provided
+
+When only `outputFileBaseString` is specified:
+
+- Output is created in a temporary folder with a random number prefix (e.g. tmp0696)
+- Filename uses the provided base string
+
+Example:
+
+- Source: `Template.indd`
+- `outputFileBaseString`: "MergedOutput"
+- Output: `tmp0696/MergedOutput.indd`
+- In case of multiple output documents/pdf:
+ - `tmp0696/MergedOutput.indd`
+ - `tmp0696/MergedOutput(1).indd`
+ - `tmp0696/MergedOutput.pdf`
+ - `tmp0696/MergedOutput(1).pdf`
+- For PNG/JPEG outputs:
+ - `tmp0696/MergedOutput.png`
+ - `tmp0696/MergedOutput(1).png`
+ - `tmp0696/MergedOutput(2).png`
+
+#### Case 3: Only outputFolderPath Provided
+
+When only `outputFolderPath` is specified:
+
+- Output is created in the specified folder
+- Filename is derived from the original template
+
+Example:
+
+- Source: `Template.indd`
+- `outputFolderPath`: "ResultFolder"
+- Output: `ResultFolder/Template.indd`
+- In case of multiple output documents/pdf:
+ - `ResultFolder/Template.indd`
+ - `ResultFolder/Template(1).indd`
+ - `ResultFolder/Template.pdf`
+ - `ResultFolder/Template(1).pdf`
+- For PNG/JPEG outputs:
+ - `ResultFolder/Template.png`
+ - `ResultFolder/Template(1).png`
+ - `ResultFolder/Template(2).png`
+
+#### Case 4: Both Parameters Provided
+
+When both parameters are specified:
+
+- Output is created in the specified folder
+- Filename uses the provided base string
+
+Example:
+
+- Source: `Template.indd`
+- `outputFileBaseString`: "MergedOutput"
+- `outputFolderPath`: "ResultFolder"
+- Output: `ResultFolder/MergedOutput.indd`
+- In case of multiple output documents/pdf:
+ - `ResultFolder/MergedOutput.indd`
+ - `ResultFolder/MergedOutput(1).indd`
+ - `ResultFolder/MergedOutput.pdf`
+ - `ResultFolder/MergedOutput(1).pdf`
+- For PNG/JPEG outputs:
+ - `ResultFolder/MergedOutput.png`
+ - `ResultFolder/MergedOutput(1).png`
+ - `ResultFolder/MergedOutput(2).png`
+
+#### Note:
+
+- Advanced Data Merge API (v4) never creates a `rangeX` subfolder for batching. All output files for a job are written directly into the resolved output folder — there is no per-batch nesting.
+- Missing-link and overset reports are no longer split per `rangeX` batch folder either. Instead of a separate `MissingLinkReport.txt`/`OversetReport.txt` pair inside each `rangeX` folder, Advanced Data Merge API (v4) writes a single `MissingLinkReport.txt` and a single `OversetReport.txt` at the root of the output folder, with each batch's findings appended as its own "Record Range: ..." section — one global report pair for the whole job instead of one pair per range.
+- Batching is still controlled by `recordsPerFile` (the v4 equivalent of the base API's `pagesPerDocument`): for example, if `recordsPerFile` is 10 and the total record count is 20, the merge still runs as two batches, but both batches write into the same folder. The second (and any later) batch's file is disambiguated with a `(1)`, `(2)`, ... suffix on the base filename — e.g. `Template.pdf`, `Template(1).pdf` — instead of a `range2` folder.
+- For output types where each record maps 1:1 to its own file — PNG, JPEG, PDF with `createSeparateFiles` enabled, or InDesign with `recordsPerFile` set to `1` — every record's output file is named from `outputFileBaseString` (or its resolved `&` filename, when the CSV provides one), and any duplicate names are disambiguated the same way with a `(n)` suffix. This means even a plain CSV with no special columns produces per-record names like `MergedOutput.png`, `MergedOutput(1).png`, `MergedOutput(2).png` — not the sequential `MergedOutput2.png`, `MergedOutput3.png` style used by the base API.
+- If a single record spans multiple pages, an additional `-` suffix is inserted before the `(n)` de-duplication suffix for pages after the first — e.g. `MergedOutput.png`, `MergedOutput-2.png` (page 2 of the first record), `MergedOutput(1).png`, `MergedOutput-2(1).png` (page 2 of the second record).
+- For output types where multiple records are combined into one file (multi-record PDF/InDesign documents, or `allowMultipleRecordsPerPage`), there is no per-record naming — the whole batch's file uses the base filename, disambiguated per batch with a `(n)` suffix only when more than one batch is produced.
+
+## Parameter Name Change in Advanced Data Merge API
+
+The `pagesPerDocument` parameter from the base [Data Merge API](../working-with-datamerge-api/index.md) has been renamed to `recordsPerFile` in the Advanced Data Merge API. The name changed, but the underlying behavior — controlling how many records are merged into each output document/batch — is the same.
+
+- `recordsPerFile` omitted or set to the total record count: All records are merged into a single output document/batch. No batching occurs.
+
+- `recordsPerFile` set to a value smaller than the total record count: Records are split across multiple batches, each containing up to `recordsPerFile` records. For example, with 20 total records and `recordsPerFile` set to 10, the merge produces two batches of 10 records each. As described in [Output Path Variations](#output-path-variations-in-advanced-data-merge-api), each additional batch's file is disambiguated with a `(1)`, `(2)`, ... suffix on the base filename rather than being written into a separate `rangeX` subfolder.
+
+- `recordsPerFile` set to `1`: Each record produces its own output document/batch, one record per file. This is also the mode used to get one file per record for InDesign output; PNG and JPEG outputs always behave this way regardless of `recordsPerFile`.
+
+## Conditional Visibility & Dynamic Styling
+
+Make your Data Merge output react to your data. With a simple rules file, you can show or hide elements, restyle and recolor content, replace text, and resize or move frames, differently for every record, all from a single template and data file.
+
+### Overview
+
+Traditionally, Data Merge drops the text or image from each record into fixed placeholders in your template. The layout stays the same for everyone. Only the placeholder content changes.
+
+This feature adds a third input to a merge job: a rules file (JSON) that travels alongside your template and data.
+
+```
+Template (.indd / .idml) + Data (.csv) + Rules (.json) → Output (INDD / PDF / PNG / JPEG)
+```
+
+For each record, the merge reads your rules and applies whichever actions match that record's data. The result is one job that produces genuinely different-looking documents per record: a VIP badge that appears only for VIP customers, a price that turns red when it exceeds a threshold, a promo layer that shows only for high-spend recipients, and so on.
+
+This feature is optional omitting a rules file leaves merge behavior unchanged from a standard Data Merge job.
+
+### What you can do
+
+| Capability | Description |
+|---|---|
+| Conditional visibility | Show or hide a layer, a frame, or a placeholder per record. |
+| Dynamic styling | Apply a named character or paragraph style, or change fill/stroke color, per record. |
+| Content replacement | Replace the text of a placeholder or tagged text range per record. |
+| Geometry | Resize or move a frame per record. |
+| Business logic | Combine conditions with AND / OR / NOT, ranges, and text matching to decide what happens. |
+
+All decisions are driven by the values in your CSV columns.
+
+### Getting started
+
+1. **Author your template.** Create the Data Merge template, including placeholders. Assign each element you intend to control a reference name: a Data Merge placeholder name, an XML tag, or a layer name (see [Targets](#targets--what-a-rule-acts-on)).
+2. **Prepare your CSV.** Ensure every column referenced by a rule exists in the CSV, even if that column is not placed anywhere in the template.
+3. **Write a rules file.** Define the conditions and actions in a `.json` file (see below).
+4. **Submit the merge job.** Include the `rulesFile` parameter, pointing to the rules file:
+
+```json
+{
+ "params": {
+ "targetDocument": "template.indd",
+ "dataSource": "data.csv",
+ "rulesFile": "rules.json",
+ "outputMediaType": "application/pdf"
+ }
+}
+```
+
+If `rulesFile` is omitted, the merge runs exactly as a standard Data Merge with no rules applied.
+
+### The rules file
+
+A rules file is a JSON document. At the top level it contains an optional `ruleSetName`, an optional `version`, and a list of **rules**.
+
+```json
+{
+ "version": "1.0",
+ "ruleSetName": "Campaign",
+ "rules": [
+ {
+ "cases": [
+ {
+ "condition": {},
+ "then": [
+ { "target": {}, "actions": [] }
+ ]
+ }
+ ],
+ "default": {
+ "then": [ { "target": {}, "actions": [] } ]
+ }
+ }
+ ]
+}
+```
+
+- `version`: optional, defaults to the current version.
+- `ruleSetName`: optional, a label shown in logs/reports.
+- `rules`: required, one or more rules. Each rule contains an ordered list of `cases`. Each case has a `condition` (when this is true...) and a `then` list (...do this). A rule can also define a `default`, which runs only if no case matched.
+
+#### How a rule is evaluated, per record
+
+- Each rule contains an ordered list of **cases**. The engine tests each case's `condition` in order and runs the **first** one that is true, then stops looking at the remaining cases in that rule.
+- If **no** case matches and a `default` is present, the `default` runs. If there's no `default`, the rule simply does nothing for that record.
+- **At most one** case (or the default) fires per rule.
+
+**Multiple rules:** you can list several rules. Every rule is evaluated for every record, in order. Rules are **cumulative**: more than one can fire for the same record. Use `cases`/`default` when you want a single "pick one" outcome; use separate rules for independent effects that can happen together. If two rules change the *same* property of the *same* target, the **last one wins**.
+
+Each entry in a `then` list is a **clause**: one `target` plus an ordered list of `actions` to run on it.
+
+### Targets — what a rule acts on
+
+A target selects the object(s) an action runs on. It always resolves within the current record's page(s).
+
+| type | Selects by | Acts on |
+|---|---|---|
+| `layer` | Layer name | The items on that layer |
+| `xml_tag` | XML tag name | A frame or a tagged text range |
+| `data_merge_tag` | Placeholder name | A Data Merge placeholder (image, QR, or text) |
+
+```json
+{ "type": "layer", "name": "premium_offer" }
+```
+
+#### Referencing a Data Merge placeholder by kind
+
+A `data_merge_tag` target chooses which kind of placeholder to act on using a name prefix:
+
+| Prefix | Kind | Example |
+|---|---|---|
+| `@` | Image placeholder | `"@hero"` → the image placeholder named `hero` |
+| `#` | QR-code placeholder | `"#ticket"` → the QR placeholder named `ticket` |
+| (none) | Text placeholder | `"title"` → the text placeholder named `title` |
+
+```json
+{ "type": "data_merge_tag", "name": "@hero" }
+```
+
+### Actions — what a rule does
+
+Each clause runs an ordered list of actions on its target. Actions apply top-to-bottom; a later action overrides an earlier one on the same target.
+
+| Action `name` | Parameters | Effect |
+|---|---|---|
+| `show` | — | Make the target visible |
+| `hide` | — | Make the target hidden |
+| `replace_text` | `value` (string) | Replace the text content |
+| `set_character_style` | `styleName` (string) | Apply a named character style |
+| `set_paragraph_style` | `styleName` (string) | Apply a named paragraph style |
+| `set_fill_color` | `color` (hex `#RRGGBB` or swatch name) | Change the fill color |
+| `set_stroke_color` | `color` (hex `#RRGGBB` or swatch name) | Change the stroke color |
+| `resize_frame` | `width`, `height` | Resize the frame |
+| `move_frame` | `x`, `y` | Move the frame's top-left origin |
+
+```json
+{ "name": "set_fill_color", "color": "#D4AF37" }
+```
+
+**Notes**
+
+- **Styles and swatches must already exist** in your template. A rule can apply a named style or swatch, but it cannot create one. Referencing a hex color like `#D4AF37` is always fine.
+- For `resize_frame`, values must be **non-negative**. Passing `0` for `width` or `height` leaves **that axis unchanged**.
+- `resize_frame` and `move_frame` apply to frames only.
+
+#### Which actions work on which targets
+
+| Action \ Target | `layer` | `xml_tag` | `data_merge_tag` |
+|---|---|---|---|
+| `show` / `hide` | ✓ | ✓ | ✓ |
+| `replace_text` | — | ✓ | ✓ |
+| `set_character_style` | — | ✓ | ✓ |
+| `set_paragraph_style` | — | ✓ | ✓ |
+| `set_fill_color` | — | ✓ | ✓ |
+| `set_stroke_color` | — | ✓ | ✓ |
+| `resize_frame` | — | ✓ | ✓ |
+| `move_frame` | — | ✓ | ✓ |
+
+Using an action on a target that isn't marked ✓ is rejected when your rules file is checked (see [Errors & Warnings](#errors--warnings)).
+
+### Conditions — deciding when a rule applies
+
+A condition is a small JSON structure, never a text expression to be parsed, so column names with spaces or punctuation (e.g. `Life Time Spend`) are written verbatim with no escaping.
+
+There are three building blocks:
+
+- **Comparison** (a single test on one column)
+- **Group** (`all` = AND, `any` = OR)
+- **Not** (negates any condition)
+
+#### Comparison
+
+```json
+{
+ "column": "Life Time Spend",
+ "operator": ">",
+ "value": 10000,
+ "valueColumn": "cost",
+ "type": "number"
+}
+```
+
+- `column`: required, the CSV column to test.
+- `operator`: required, see the operator list below.
+- `value`: the value to compare against, **or**
+- `valueColumn`: another column (use exactly one of `value` / `valueColumn`).
+- `type`: optional, force `number` | `string` | `boolean` comparison.
+
+**Operators**
+
+| Group | Operators | Notes |
+|---|---|---|
+| Comparison | `==`, `!=`, `>`, `>=`, `<`, `<=` | `>`, `>=`, `<`, `<=` are for numbers (or text, alphabetically), not booleans |
+| Set membership | `in`, `not_in` | `value` must be a non-empty array; `valueColumn` not allowed |
+| Text matching | `contains`, `starts_with`, `ends_with` | String only, case-sensitive |
+
+**Right-hand side:** provide exactly one of:
+
+- `value`: a literal number, string, or boolean (or an array of literals for `in`/`not_in`), or
+- `valueColumn`: the name of another CSV column, to compare column-against-column.
+
+**Value types & how comparisons are made**
+
+- Add `"type": "number"`, `"string"`, or `"boolean"` to force how both sides are compared. If you omit `type`, the type is inferred (a numeric or boolean literal makes the comparison numeric or boolean; otherwise text).
+- **Numbers** must be plain decimals (an optional leading `-` is fine). Thousands separators, currency symbols, and locale decimal commas are **not** recognized: `"10,000"`, `"$10,000"`, and `"1.000,50"` will not parse as numbers. If a value can't be parsed as the required type, that comparison is treated as **false** (it won't stop your job).
+- **Booleans** accept only `true`/`false` (any case). Anything else is treated as false.
+- **Text** comparisons and text-matching operators are **case-sensitive**. Leading/trailing spaces are trimmed before comparing.
+
+#### Group — `all` (AND) and `any` (OR)
+
+```json
+{ "all": [] }
+{ "any": [] }
+```
+
+Groups can nest to any depth, and their children can be comparisons, other groups, or `not` blocks.
+
+#### Not (flipping condition)
+
+Wrap any single condition to negate it:
+
+```json
+{ "not": { "column": "sku", "operator": "contains", "value": "PROMO" } }
+```
+
+This reads as "SKU does not contain PROMO." (For simple "is not one of a set" tests, the `not_in` operator is usually simpler.)
+
+#### Condition examples
+
+`tier` is `VIP`:
+
+```json
+{ "column": "tier", "operator": "==", "value": "VIP" }
+```
+
+`Life Time Spend` greater than `10000`:
+
+```json
+{ "column": "Life Time Spend", "operator": ">", "value": 10000, "type": "number" }
+```
+
+Compare `Life Time Spend` to `cost`:
+
+```json
+{ "column": "Life Time Spend", "operator": ">", "valueColumn": "cost", "type": "number" }
+```
+
+`tier` is `VIP` AND `spend` over `10000`:
+
+```json
+{
+ "all": [
+ { "column": "tier", "operator": "==", "value": "VIP" },
+ { "column": "spend", "operator": ">", "value": 10000, "type": "number" }
+ ]
+}
+```
+
+`region` is not EU or UK:
+
+```json
+{ "column": "region", "operator": "not_in", "value": ["EU", "UK"] }
+```
+
+A nested example combining VIP status, US or UK region, and not blocked:
+
+```json
+{
+ "all": [
+ { "column": "tier", "operator": "==", "value": "VIP" },
+ { "any": [
+ { "column": "country", "operator": "==", "value": "US" },
+ { "column": "country", "operator": "==", "value": "UK" }
+ ] },
+ { "not": { "column": "status", "operator": "==", "value": "Blocked" } }
+ ]
+}
+```
+
+### Worked examples
+
+#### Example 1 — Show a VIP badge only for VIP records
+
+```json
+{
+ "ruleSetName": "VIP Badge Display",
+ "rules": [
+ {
+ "cases": [
+ {
+ "condition": { "column": "tier", "operator": "==", "value": "VIP" },
+ "then": [
+ { "target": { "type": "data_merge_tag", "name": "vip_badge" },
+ "actions": [ { "name": "show" } ] }
+ ]
+ }
+ ],
+ "default": {
+ "then": [
+ { "target": { "type": "data_merge_tag", "name": "vip_badge" },
+ "actions": [ { "name": "hide" } ] }
+ ]
+ }
+ }
+ ]
+}
+```
+
+VIP records show the badge; everyone else hides it.
+
+#### Example 2 — Color a badge by tier (first match wins)
+
+```json
+{
+ "ruleSetName": "Badge tier",
+ "rules": [
+ {
+ "cases": [
+ { "condition": { "column": "tier", "operator": "==", "value": "VIP" },
+ "then": [ { "target": { "type": "data_merge_tag", "name": "badge" },
+ "actions": [ { "name": "set_fill_color", "color": "#D4AF37" } ] } ] },
+
+ { "condition": { "column": "spend", "operator": ">", "value": 10000, "type": "number" },
+ "then": [ { "target": { "type": "data_merge_tag", "name": "badge" },
+ "actions": [ { "name": "set_fill_color", "color": "#C0C0C0" } ] } ] },
+
+ { "condition": { "column": "spend", "operator": ">", "value": 1000, "type": "number" },
+ "then": [ { "target": { "type": "data_merge_tag", "name": "badge" },
+ "actions": [ { "name": "set_fill_color", "color": "#CD7F32" } ] } ] }
+ ],
+ "default": {
+ "then": [ { "target": { "type": "data_merge_tag", "name": "badge" },
+ "actions": [ { "name": "hide" } ] } ]
+ }
+ }
+ ]
+}
+```
+
+Reads as: VIP → gold; else if spend > 10,000 → silver; else if spend > 1,000 → bronze; otherwise hide the badge. Cases are tested top-to-bottom and only the first match applies.
+
+#### Example 3 — Reveal a promo layer for high-spend records
+
+```json
+{
+ "ruleSetName": "Premium Offer",
+ "rules": [
+ {
+ "cases": [
+ {
+ "condition": { "column": "lifetime_spend", "operator": ">", "value": 10000, "type": "number" },
+ "then": [
+ { "target": { "type": "layer", "name": "premium_offer" },
+ "actions": [ { "name": "show" } ] }
+ ]
+ }
+ ]
+ }
+ ]
+}
+```
+
+This assumes the `premium_offer` layer is **hidden** in the template. It stays hidden by default and is shown only for records that match. If the layer were visible in the template instead, add a `default` with a `hide` action to switch it off for non-matching records.
+
+#### Example 4 — Swap disclaimer text by region using an `xml_tag`
+
+```json
+{
+ "ruleSetName": "Regional Disclaimer",
+ "rules": [
+ {
+ "cases": [
+ {
+ "condition": { "column": "region", "operator": "==", "value": "EU" },
+ "then": [
+ { "target": { "type": "xml_tag", "name": "disclaimer" },
+ "actions": [
+ { "name": "replace_text", "value": "This offer is subject to EU consumer protection regulations." },
+ { "name": "set_character_style", "styleName": "Legal-EU" }
+ ] }
+ ]
+ },
+ {
+ "condition": { "column": "region", "operator": "==", "value": "US" },
+ "then": [
+ { "target": { "type": "xml_tag", "name": "disclaimer" },
+ "actions": [
+ { "name": "replace_text", "value": "Void where prohibited. See terms for details." },
+ { "name": "set_character_style", "styleName": "Legal-US" }
+ ] }
+ ]
+ }
+ ],
+ "default": {
+ "then": [
+ { "target": { "type": "xml_tag", "name": "disclaimer" },
+ "actions": [ { "name": "replace_text", "value": "Terms and conditions apply." } ] }
+ ]
+ }
+ }
+ ]
+}
+```
+
+This targets the text range tagged `disclaimer` in the template. EU records get EU-specific wording and legal styling, US records get US-specific wording and styling, and every other region falls back to the generic disclaimer text in the `default` case.
+
+### Constraints
+
+- **Single record per page.** Rules are supported only when each page corresponds to one record (the standard Data Merge layout). Jobs configured for multiple records per page are not supported with rules and will be rejected before processing.
+- **Columns must exist.** A rule can only reference CSV columns that are present in your data file. A missing column is reported when your rules file is checked.
+- **Styles and swatches must exist** in the template before the merge; rules apply them but do not create them.
+- **Layer visibility for non-layer targets.** An element renders only if its layer is visible. If you target a placeholder or XML tag that sits on a layer you authored as *hidden*, a `show` action will not make it appear. Put rule-driven elements on a visible layer, or target the layer itself.
+- **Record ranges.** Contiguous, ascending record ranges (for example `1-50`) are fully supported. Out-of-order or overlapping comma-separated ranges may be restricted; use ascending ranges for rule-driven jobs.
+- **Numeric formatting.** Keep numeric columns as plain numbers (no currency symbols, thousands separators, or locale decimals) so numeric comparisons behave as expected.
+
+### Errors & Warnings
+
+The feature distinguishes two kinds of problems:
+
+**Problems that stop the job** (checked up front, before any output is produced). These are things that are wrong with the job setup or the rules file itself, so the whole job is rejected with a clear message and nothing is produced. Examples:
+
+- the rules file is missing, unreadable, or not valid JSON;
+- an empty rules list;
+- a malformed condition, or a rule/case that isn't shaped correctly;
+- a condition that references a column not in the CSV;
+- an invalid target type or action, or an action used on a target it doesn't support;
+- a rules job submitted with a multiple-records-per-page layout.
+
+Fixing these means correcting the rules file (or the job configuration) and resubmitting.
+
+**Problems that are reported but don't stop the job** (per record). These are situations the engine can safely work around, so the batch continues and the issues are collected in the job's warnings:
+
+- a target name that can't be found for a record;
+- a style or swatch named in an action that doesn't exist;
+- an action that can't apply to the resolved object (for example, resizing something that isn't a frame);
+- a value that can't be read as the required number or boolean; that single comparison is treated as false.
+
+Review the warnings after a run to catch typos in names or unexpected data.
+
+## Copyfitting
+
+The Data Merge API can automatically resize text that overflows its frame after a merge. When a merged record produces overset text, copyfitting reduces the font size - within limits you define - so that the text fits. Copyfitting runs only when you enable it and only when the merged document has overset present.
+
+### Example use cases
+
+Copyfitting is most useful when the length of merged content varies and cannot be predicted at design time:
+
+- **Multi-language data merge:** A single template is merged with a data source that contains rows in different languages, or a template designed for one language is merged with data that includes others. Translations in longer languages (for example, German or Finnish) often overflow frames sized for the original language. Copyfitting shrinks only the overset rows so each language fits, without redesigning the template or hand-editing records.
+
+- **Variable-length content at scale:** In catalogues, price lists, or personalized mailers, fields such as product names, descriptions, or addresses vary in length across thousands of records, and some overflow their frames. Copyfitting fits them automatically so more records export cleanly in a single job.
+
+### How it works
+
+Add a copyfittingSettings object inside params. It accepts the following fields:
+
+- **enabled**
+ - **Type:** boolean
+ - **Default:** `false`
+ - **Description:** Master on/off switch. Copyfitting runs only when set to `true`. If it is `false`, absent, or the whole `copyfittingSettings` block is omitted, copyfitting is off.
+- **unresolvedOversetHandling**
+ - **Type:** string (enum)
+ - **Enum:** `"warn"`, `"omit_records"`
+ - **Default:** `"warn"`
+ - **Description:** What to do when text is still overset after copyfitting. See [Unresolved overset handling](#unresolved-overset-handling) below.
+- **multiFrameSyncScope**
+ - **Type:** string (enum)
+ - **Enum:** `"paragraph_style"`, `"page"`, `"paragraph_style_and_page"`, `"document"`
+ - **Default:** none (omit the key to skip multi-frame sync)
+ - **Description:** After fitting the overset frames, apply the same font-size reduction to matching non-overset frames for visual consistency. See [Multi-frame sync scopes](#multi-frame-sync-scopes) below.
+- **scope.global.constraints.fontSize**
+ - **Type:** object with a numeric `minPercent` field
+ - **Default:** `minPercent` 85
+ - **Description:** Limits for font-size reduction, applied to all text in overset stories. `minPercent` is the floor (text never shrinks below this percentage of its original size; 100 means it never shrinks). Must be between 1 and 100; an out-of-range value fails the job.
+
+Copyfitting is applied after the merge, before export, once per output document. Threaded text across multiple frames is treated as a single story.
+
+> **Note:** Missing template fonts are automatically replaced with the default font, and output generation continues normally. However, copyfitting calculations are then based on the substitute font, not the original, so the output may not appear as expected.
+
+### Example request
+
+Enable copyfitting by adding copyfittingSettings to params:
+
+```curl
+curl --location --request POST https://indesign.adobe.io/v4/merge-data \
+--header "Authorization: Bearer {YOUR_OAUTH_TOKEN}" \
+--header "x-api-key: {YOUR_API_KEY}" \
+--header "Content-Type: application/json" \
+--data-raw '{
+"assets": [
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "dataMergeTemplate.indd"
+ },
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "FileNames.csv"
+ }
+],
+"params": {
+ "targetDocument": "dataMergeTemplate.indd",
+ "outputMediaType": "application/pdf",
+ "outputFolderPath": {OUTPUT_FOLDER_PATH},
+ "outputFileBaseString": "merged",
+ "dataSource": "FileNames.csv",
+ "recordRange": "All",
+ "copyfittingSettings": {
+ "enabled": true,
+ "unresolvedOversetHandling": "warn",
+ "multiFrameSyncScope": "paragraph_style_and_page",
+ "scope": {
+ "global": {
+ "constraints": {
+ "fontSize": { "minPercent": 80}
+ }
+ }
+ }
+ }
+}
+}'
+```
+
+To enable copyfitting with default limits, `copyfittingSettings` can be as small as setting `enabled` to `true` and omitting the rest.
+
+### Multi-frame sync scopes
+
+Multi-frame sync keeps related frames visually consistent by extending a reduction beyond just the overset frame. Only the font-size **reduction** by percentage is synced (not the absolute point size, and no other property). Omit multiFrameSyncScope to skip sync entirely - only the overset frames change. When present, it must be one of the following.
+
+- **paragraph_style** - Frames whose text uses the same paragraph style, across all pages, receive the largest reduction required by any of them.
+ - Example: A "Headline" paragraph style is used in frames throughout the document. If one headline must shrink 12 percent to fit, every frame using the "Headline" style - on every page - is reduced by 12 percent, so all headlines stay consistent.
+
+- **page** - Every text frame on the same page as an overset frame receives the same reduction; paragraph style is ignored.
+ - Example: On a product page, the description frame oversets and shrinks 10 percent. The other text frames on that page (title, price, footnote) are also reduced by 10 percent, keeping the page uniform.
+
+- **paragraph_style_and_page** - Like paragraph_style, but limited to the current page: only same-style frames on the same page are matched.
+ - Example: Two "Callout" frames on page 3 shrink together, but "Callout" frames on page 4 are unaffected.
+
+- **document** - Every text frame in the entire document receives the same reduction; paragraph style is ignored.
+ - Example: If any frame anywhere needs a 15 percent reduction to fit, all text frames across all pages are reduced by 15 percent, giving the whole piece one consistent size.
+
+**Conflict rule:** when frames in a group would need different reductions, the largest (most aggressive) reduction wins for the group, subject to the global minimum: no text shrinks below minPercent of its original size.
+
+### Unresolved overset handling
+
+If text is still overset after copyfitting has reduced text to minPercent of its original size, unresolvedOversetHandling controls the outcome:
+
+- **"warn"** (default) - the output file is still produced; affected records report warnings.oversetText.
+
+- **"omit_records"** - pages for the affected data records are removed from the output and the remaining records still export; affected records report warnings.omittedDataRecordNumbers (and not warnings.oversetText). If every record in the batch would be removed, no file is exported (outputs is empty) and omittedDataRecordNumbers lists the full range.
+
+### Copyfitting in the response
+
+Copyfitting adds no new top-level response field. Results appear per record, inside the existing warnings object.
+
+Still overset with "warn":
+```json
+"warnings": {
+ "oversetText": [
+ { "page": "2",
+ "charactersInOverset": "142",
+ "wordsInOverset": "24",
+ "oversetText": "...overflowing text..."
+ }
+ ]
+}
+```
+Records omitted with "omit_records":
+```json
+"warnings": { "omittedDataRecordNumbers": "5,6" }
+```
+If copyfitting hits a script or engine error, the whole job fails (no output for that job):
+
+```json
+{
+"status": "FAILURE",
+"errorCode": "capability_error",
+"errorString": "Capability error: Copyfitting failed. "
+}
+```
+
+## Folder Structure and Zipped Output
+
+The Data Merge API supports organizing your outputs in a structured folder hierarchy, and a zipped folder containing all the outputs that have been created from the successful data merge.
+
+How it works
+
+- Add a dedicated column in your input CSV for folder names.
+- Prefix the column header with ~ (for example: ~FolderName).
+- Each row value in this column will be used as the folder hierarchy for the output file of that record.
+- Users can opt in for zipped output by setting `outputCompressMediaType`; only `ZIP` is supported for now.
+- Add three input parameters:
+ - **outputCompressMediaType**
+ - **Type:** String
+ - **ENUM:** ["application/zip"]
+ - **Meaning:** The type of compression the user wants (e.g. ZIP, RAR, etc.).
+ - If the user opts for zipped output, the response contains only the zipped output, not individual assets and their links.
+ - If the user does not opt for zipped output, the response is unchanged except that the output path reflects the desired folder hierarchy.
+ - **outputCompressName**
+ - **Type:** String
+ - **Default:** `"Result"`
+ - **Meaning:** Use this value to name the resulting zip.
+ - **outputFolderBaseString**
+ - **Type:** String
+ - **Default:** `mergedFiles`
+ - **Meaning:** Specifies which folder merged files go into and the name of the merged folder; multi-record output files or outputs from empty CSV column values are placed in this folder.
+
+Note:
+- Only one folder name column is allowed. If multiple columns have a ‘~’ prefix, the job will fail.
+- Local or absolute paths (for example, `C:\F1\F2`) are not supported in the `~` column. Provide relative folder hierarchy values (for example, `F1` or `F1\F2`) only. The job will fail if a row uses a local or absolute path.
+
+### Folder Name Constraints
+
+Certain special characters or words are not supported by the platform and are automatically normalized.
+
+- Consecutive unsupported characters (e.g., <, >, :, ", /, \, |, ?, *) are replaced with a single underscore (e.g., `Ab5<>;d` → `Ab5_d`)
+- Windows reserved names (e.g., CON, PRN, AUX, NUL as well as device names like COM1–COM9 and LPT1–LPT9) are wrapped with underscores (e.g., `CON` → `_CON_`)
+- File names (including extension) are limited to 255 characters, with longer names truncated automatically
+
+Here is a sample CSV file demonstrating a column header with prefix ‘~’.
+
+
+Example of input payload which is same as it is currently.
+
+```curl
+curl --location --request POST 'https://indesign.adobe.io/v4/merge-data' \
+--header 'Authorization: Bearer {YOUR_OAUTH_TOKEN}' \
+--header 'x-api-key: {YOUR_API_KEY}' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "assets": [
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "dataMergeTemplate.indd"
+ },
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "FolderNames.csv"
+ }
+ ],
+ "params": {
+ "targetDocument": "dataMergeTemplate.indd",
+ "outputMediaType": "image/png",
+ "outputFolderPath": {OUTPUT_FOLDER_PATH},
+ "outputFileBaseString": "merged",
+ "dataSource": "FolderNames.csv",
+ "recordRange": "All",
+ "outputCompressMediaType": "application/zip",
+ "outputCompressName": "Works only if outputCompressMediaType is provided",
+ "outputFolderBaseString": "Merged folder name; multi-record outputs and empty ~ values go here. Default: mergedFiles",
+ "hyphenationSettings": {
+ "afterFirst": 3,
+ "beforeLast": 3,
+ "wordsLongerThan": 6,
+ "ladderLimit": 2,
+ "zone": 0.15,
+ "capitalizedWords": false,
+ "lastWord": true,
+ "acrossColumns": false,
+ "dictionarySettings": [
+ {
+ "language": "English: USA",
+ "wordList": ["~word1", "ex~word2"]
+ },
+ {
+ "language": "English: UK",
+ "wordList": ["~word3", "~word4"]
+ }
+ ]
+ }
+ },
+ "outputs": [
+ {
+ "destination": {
+ "url": "{PUT-SIGNED_URL}"
+ },
+ "source": "{OUTPUT_FOLDER_PATH}/{outputs}"
+ }
+ ]
+}'
+```
+
+### When folder structuring is not supported, and output files will move to ‘outputFolderBaseString’
+| outputMediaType | params |
+|----------------------------------|--------|
+| JPEG (image/jpeg) | allowMultipleRecordsPerPage set to true |
+| PNG (image/png) | allowMultipleRecordsPerPage set to true |
+| PDF (application/pdf) | recordsPerFile ≠ 1 and recordRange = "All" |
+| | recordsPerFile ≠ 1 and recordRange = "1-2, 5" |
+| | allowMultipleRecordsPerPage set to true |
+| InDesign (application/x-indesign)| recordsPerFile ≠ 1 and recordRange = "All" |
+| | recordsPerFile ≠ 1 and recordRange = "1-2, 5" |
+| | allowMultipleRecordsPerPage set to true |
+
+**Why:** Folder structuring via the `~` column applies only when the merge job has a clear one-to-one mapping between each data row and its output. In that case, each row’s `~` value defines the folder hierarchy for that record’s output file. If `allowMultipleRecordsPerPage` is true, multiple records can share a page, so per-row folder paths are ambiguous. If `recordsPerFile` is not 1, records are combined into multi-page output documents, so many rows contribute to the same file and per-row folder paths are no longer meaningful. In those situations, folder structuring via the `~` column is not supported for the affected output types, and output files are placed under `outputFolderBaseString` instead.
+
+## Pre-signed URL Support in CSV
+
+The Data Merge API now supports pre-signed URLs for image assets directly in the CSV, instead of requiring them in the input request. In the Image column (prefixed with "@"), a pre-signed URL of the image asset can be provided for each row; the images will be fetched from the URL and made available for use. Only existing [DAM](../../getting-started/usage/index.md#supported-storage-types) assets are supported.
+
+How it works
+
+- Pre-signed URLs of image assets can now be provided directly in the Image column (prefixed with @) of the input CSV, for each row
+- In addition, providing pre-signed URLs of image assets in the input request continues to be supported as before; this feature does not remove or restrict that option.
+- The image will be fetched from the pre-signed URL and made available for use in the data merge.
+- If a URL cannot be fetched or has expired, that row's image asset will be reported in warnings as a failed download, and the rest of the merge will proceed unaffected.
+ - These failures are reported under a `failedAssets` key in the response's `warnings` object — an array of `{ columnIndex, rows: [{ row, url }, ...] }` entries, one per Image column that had at least one invalid pre-signed URL, listing every affected row number and the URL that failed.
+- Add a new input parameter
+ - **presignedUrlsInDataSource**
+ - **Type:** Boolean
+ - **Meaning:** Whether the user wants to enable fetching image assets via pre-signed URLs provided in the CSV.
+ - If the user sets this to true, the Image column values in the CSV can be pre-signed URLs, and these will be fetched and used in the data merge.
+ - If the user doesn't set this (or sets it to false), there is no change in behavior. The Image column will be treated as before, and pre-signed URLs can still only be provided in the input request.
+ - If a pre-signed URL is included in the Image column but the presignedUrlsInDataSource parameter is not set to true, this enhancement will not take effect. The Image column value will be handled just as it always has been, without any change in behavior. Since the value is a URL and not a valid asset reference, the image for that record will show up as a missing link in the data merge.
+
+Example of input CSV having an Image column value (prefixed with ‘@’) containing a pre-signed URL
+
+
+Example of input payload
+```curl
+curl --location --request POST 'https://indesign.adobe.io/v3/merge-data' \
+--header 'Authorization: Bearer {YOUR_OAUTH_TOKEN}' \
+--header 'x-api-key: {YOUR_API_KEY}' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "assets": [
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "dataMergeTemplate.indd"
+ },
+ {
+ "source": {
+ "url": "{PRE-SIGNED_URL}",
+ "storageType": "Azure"
+ },
+ "destination": "Directory_Names.csv"
+ }
+ ],
+ "params": {
+ "targetDocument": "dataMergeTemplate.indd",
+ "outputMediaType": "application/x-indesign",
+ "outputFolderPath": {OUTPUT_FOLDER_PATH},
+ "outputFileBaseString": "merged",
+ "dataSource": "Directory_Names.csv",
+ "presignedUrlsInDataSource": true
+ },
+ "outputs": [
+ {
+ "destination": {
+ "url": "{PUT-SIGNED_URL}"
+ },
+ "source": "{OUTPUT_FOLDER_PATH}/merged-1.pdf"
+ }
+ ]
+}'
+```
\ No newline at end of file
diff --git a/src/pages/guides/working-with-advanced-data-merge-api/records-foldercsv.png b/src/pages/guides/working-with-advanced-data-merge-api/records-foldercsv.png
new file mode 100644
index 0000000..a4a7b9b
Binary files /dev/null and b/src/pages/guides/working-with-advanced-data-merge-api/records-foldercsv.png differ
diff --git a/src/pages/guides/working-with-advanced-data-merge-api/records-urlcsv.png b/src/pages/guides/working-with-advanced-data-merge-api/records-urlcsv.png
new file mode 100644
index 0000000..8e6e50d
Binary files /dev/null and b/src/pages/guides/working-with-advanced-data-merge-api/records-urlcsv.png differ
diff --git a/src/pages/guides/working-with-convert-indesign-to-idml-api/index.md b/src/pages/guides/working-with-convert-indesign-to-idml-api/index.md
new file mode 100644
index 0000000..1259d4b
--- /dev/null
+++ b/src/pages/guides/working-with-convert-indesign-to-idml-api/index.md
@@ -0,0 +1,54 @@
+---
+title: Working with the Convert InDesign to IDML API
+description: Convert an InDesign document to IDML using the Convert InDesign to IDML API.
+keywords:
+ - Adobe InDesign API
+ - Convert InDesign to IDML API
+ - IDML
+ - INDD
+ - document conversion
+---
+
+# Working with the Convert InDesign to IDML API
+
+Use the Convert InDesign to IDML API to convert an INDD file to IDML.
+
+## Submit a conversion
+
+Send a `POST` request to `/v3/convert-indesign-to-idml`. Include a pre-signed URL for the document and its destination file name. Currently, only one document can be converted per request.
+
+The output file takes the name from the input asset's `destination`, replacing its extension with `.idml`. For example, `example.indd` produces `example.idml`.
+
+```curl
+curl --request POST \
+ --url https://indesign.adobe.io/v3/convert-indesign-to-idml \
+ --header 'Authorization: Bearer {YOUR_OAUTH_TOKEN}' \
+ --header 'x-api-key: {YOUR_API_KEY}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "assets": [
+ {
+ "source": {
+ "url": "{PRESIGNED_URL}"
+ },
+ "destination": "example.indd"
+ }
+ ],
+ "params": {
+ "targetDocuments": ["example.indd"]
+ }
+ }'
+```
+
+An accepted request returns a `jobId` and `statusUrl`. Poll the status endpoint using the job ID to retrieve the conversion status and output.
+
+```json
+{
+ "jobId": "{JOB_ID}",
+ "statusUrl": "https://indesign.adobe.io/v3/status/{JOB_ID}"
+}
+```
+
+## Links and fonts
+
+If linked assets in the document are not included with the request, they are reported as missing links. Fonts unavailable are reported as missing fonts unless supplied using a pre-signed URL.
diff --git a/src/pages/guides/working-with-datamerge-api/index.md b/src/pages/guides/working-with-datamerge-api/index.md
index 1bd147d..2ec160a 100644
--- a/src/pages/guides/working-with-datamerge-api/index.md
+++ b/src/pages/guides/working-with-datamerge-api/index.md
@@ -37,7 +37,7 @@ twitter:
Data merge generates variations of a template document
from data in a provided CSV file.
-The Data Merge API supports UTF-16BE encoding for CSV files, which is necessary for languages or characters requiring multi-byte representation. For plain English characters, the CSV will function correctly even without this encoding.
+The Data Merge API supports UTF-8 and UTF-16BE encoding for CSV files, which is necessary for languages or characters requiring multi-byte representation. For plain English characters, the CSV will function correctly even without this encoding.
The [Data Merge API](../../api/index.md) includes two components to complete the task: the data merge and the data merge tags.
@@ -116,7 +116,7 @@ parts:
- **assets** - Input assets for the request.
- **params** - Information about what to do with the input assets.
- **outputs** - Specify locations where the output assets are uploaded. Without an `outputs` parameter, the output assets are stored in a temporary
-repository, and a [pre-signed URL](../../getting-started/concepts/index.md#pre-signed-urls) will be shared for those assets, which will be valid for 24hrs.
+repository, and a [pre-signed URL](../../getting-started/concepts/index.md#pre-signed-urls) will be shared for those assets, which will be valid for 24hrs. For multi-record PNG/JPEG output, see [Output Path Variations in Data Merge API](#output-path-variations-in-data-merge-api) below to predict each file's name when setting `source`.
Consult this skeleton [cURL request](https://developer.adobe.com/commerce/webapi/get-started/gs-curl/) for more details.
@@ -269,6 +269,8 @@ When you upload this UTF-8 encoded CSV to the Data Merge API, the merged documen
When using the Data Merge API, the output file paths are determined by the `outputFolderPath` and `outputFileBaseString` parameters in the request. Here are the different scenarios and their corresponding output paths:
+For PNG/JPEG outputs, the per-record file names below follow the platform's [output file naming convention](../../getting-started/concepts/index.md#output-file-naming-convention).
+
#### Case 1: Both Parameters Missing
When neither `outputFolderPath` nor `outputFileBaseString` is provided:
diff --git a/src/pages/guides/working-with-datamerge-api/records-csv.png b/src/pages/guides/working-with-datamerge-api/records-csv.png
index 5fa3a2c..b894a53 100644
Binary files a/src/pages/guides/working-with-datamerge-api/records-csv.png and b/src/pages/guides/working-with-datamerge-api/records-csv.png differ
diff --git a/src/pages/guides/working-with-rendition-api/index.md b/src/pages/guides/working-with-rendition-api/index.md
index 24c50d3..35083c9 100644
--- a/src/pages/guides/working-with-rendition-api/index.md
+++ b/src/pages/guides/working-with-rendition-api/index.md
@@ -75,10 +75,15 @@ parts:
- **assets** - Input assets for the request.
- **params** - Information about what to do with the input assets.
- **outputs** - Specify locations where the output assets are uploaded. Without an `outputs` parameter, the output assets are stored in a temporary
-repository, and a [pre-signed URL][2] will be shared for those assets, which will be valid for 24hrs.
+repository, and a [pre-signed URL][2] will be shared for those assets, which will be valid for 24hrs. For multi-page exports, see [Output file naming for multi-page renditions](#output-file-naming-for-multi-page-renditions) below to predict each page's file name when setting `source`.
Consult this skeleton [cURL request][3] for more details.
+### Output file naming for multi-page renditions
+
+When `pageRange` spans more than one page or spread (for example, with `createSeparateFiles: true`), the Rendition API generates one output file per page, following the platform's [output file naming convention][4].
+
[1]: ../../getting-started/concepts/index.md#Pre-signed-URLs
[2]: ../../getting-started/concepts/index.md#Pre-signed-URLs
[3]: https://developer.adobe.com/commerce/webapi/get-started/gs-curl/
+[4]: ../../getting-started/concepts/index.md#output-file-naming-convention
diff --git a/src/pages/index.md b/src/pages/index.md
index 9b7e2b0..fa00606 100644
--- a/src/pages/index.md
+++ b/src/pages/index.md
@@ -56,9 +56,16 @@ Retrieve information from INDD / IDML documents including layers, links and font
Convert PDF documents to editable InDesign format. Output includes all converted files and assets in a ZIP archive.
+
+
+[Convert InDesign to IDML API][7]
+
+Convert an INDD document to IDML.
+
[1]: /api/#tag/Data-Merge
[2]: /api/#tag/Rendition
[3]: /api/#tag/Custom-Scripts
[4]: /api/#tag/Job-Status
[5]: /api/#tag/Document-Info
[6]: /api/#tag/Convert-PDF-to-InDesign
+[7]: /api/#tag/Convert-InDesign-to-IDML
diff --git a/static/indesignapi.json b/static/indesignapi.json
index 2ddee1c..e7d32aa 100644
--- a/static/indesignapi.json
+++ b/static/indesignapi.json
@@ -22,8 +22,12 @@
],
"tags": [
{
- "name": "Data Merge",
- "description": "Create document variations from CSV data and InDesign templates. Supports UTF-16BE encoding for CSV files, which is necessary for languages or characters requiring multi-byte representation. For plain English characters, the CSV will function correctly even without this encoding."
+ "name": "Data Merge (V4)",
+ "description": "Create document variations from CSV data and InDesign templates. Supports UTF-8 and UTF-16BE encoded CSV files, which is necessary for languages or characters requiring multi-byte representation. For plain English characters, the CSV will function correctly even without this encoding. Adds advanced capabilities on top of standard data merge: a rules file (`rulesFile`) for conditional visibility, dynamic styling, content replacement, and frame size per record; `copyfittingSettings` to automatically shrink overset text within defined limits; folder structure and zipped output via a `~`-prefixed CSV column and `outputCompressMediaType`; and pre-signed image URLs supplied directly in the CSV via the `presignedUrlsInDataSource` parameter."
+ },
+ {
+ "name": "Data Merge (V3)",
+ "description": "Create document variations from CSV data and InDesign templates. Supports UTF-8 and UTF-16BE encoded CSV files, which is necessary for languages or characters requiring multi-byte representation. For plain English characters, the CSV will function correctly even without this encoding."
},
{
"name": "Remap Links",
@@ -45,19 +49,68 @@
"name": "Convert PDF to InDesign",
"description": "Convert PDF documents to InDesign (INDD or IDML) format. The output is a ZIP file containing the converted documents and all associated assets."
},
+ {
+ "name": "Convert InDesign to IDML",
+ "description": "Convert an InDesign (INDD) document to IDML."
+ },
{
"name": "Job Status",
"description": "Track job execution status and lifecycle events. Retrieves the most recent status event for jobs across different execution stages: `not_started` (job creation), `running` (execution begins), `succeeded` (complete), `partial_success` (complete with non-critical errors), `failed` (execution failure)."
}
],
"paths": {
+ "/v4/merge-data": {
+ "post": {
+ "summary": "Perform advanced data merge",
+ "description": "Creates InDesign documents or PDFs by merging CSV data with InDesign templates. Supports multiple output formats: JPEG (`image/jpeg`), PNG (`image/png`), PDF (`application/pdf`), and InDesign (`application/x-indesign`). Adds advanced capabilities on top of standard data merge: a `rulesFile` for per-record conditional visibility, dynamic styling, content replacement, and frame size; `copyfittingSettings` to automatically shrink overset text within defined limits; folder structure and zipped output via a `~`-prefixed CSV column and `outputCompressMediaType`; and pre-signed image URLs supplied directly in the CSV via the `presignedUrlsInDataSource` parameter.",
+ "operationId": "dataMergeV4",
+ "tags": [
+ "Data Merge (V4)"
+ ],
+ "parameters": [],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/MergeDataRequestV4"
+ }
+ }
+ },
+ "description": "This job request object specifies parameters for merging the data with the given template.",
+ "required": true
+ },
+ "responses": {
+ "202": {
+ "$ref": "#/components/responses/Accepted"
+ },
+ "400": {
+ "$ref": "#/components/responses/BadParams"
+ },
+ "401": {
+ "$ref": "#/components/responses/Unauthorized"
+ },
+ "403": {
+ "$ref": "#/components/responses/Forbidden"
+ },
+ "404": {
+ "$ref": "#/components/responses/NotFound"
+ },
+ "429": {
+ "$ref": "#/components/responses/TooManyRequests"
+ },
+ "500": {
+ "$ref": "#/components/responses/InternalServerError"
+ }
+ }
+ }
+ },
"/v3/merge-data": {
"post": {
"summary": "Perform a data merge",
"description": "Creates InDesign documents or PDFs by merging CSV data with InDesign templates. Supports multiple output formats: JPEG (`image/jpeg`), PNG (`image/png`), PDF (`application/pdf`), and InDesign (`application/x-indesign`).",
"operationId": "dataMerge",
"tags": [
- "Data Merge"
+ "Data Merge (V3)"
],
"parameters": [],
"requestBody": {
@@ -102,7 +155,7 @@
"description": "Retrieves the data merge tags from a document.",
"operationId": "dataMergeTags",
"tags": [
- "Data Merge"
+ "Data Merge (V3)"
],
"parameters": [],
"requestBody": {
@@ -1039,6 +1092,100 @@
}
}
},
+ "/v3/convert-indesign-to-idml": {
+ "post": {
+ "summary": "Convert InDesign to IDML",
+ "description": "Converts an INDD document to IDML. The completed job's status includes a download URL for the converted document and any warnings.",
+ "operationId": "convertIndesignToIdml",
+ "tags": [
+ "Convert InDesign to IDML"
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConvertIndesignToIdmlRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "202": {
+ "$ref": "#/components/responses/Accepted"
+ },
+ "400": {
+ "$ref": "#/components/responses/BadParams"
+ },
+ "401": {
+ "$ref": "#/components/responses/Unauthorized"
+ },
+ "403": {
+ "$ref": "#/components/responses/Forbidden"
+ },
+ "404": {
+ "$ref": "#/components/responses/NotFound"
+ },
+ "429": {
+ "$ref": "#/components/responses/TooManyRequests"
+ },
+ "500": {
+ "$ref": "#/components/responses/InternalServerError"
+ }
+ }
+ }
+ },
+ "/v3/status/{convert-indesign-to-idml_job_id}": {
+ "get": {
+ "operationId": "getConvertIndesignToIdmlJobStatus",
+ "summary": "Get status - Convert InDesign to IDML API",
+ "description": "Returns the latest status of a Convert InDesign to IDML job.",
+ "tags": [
+ "Convert InDesign to IDML"
+ ],
+ "parameters": [
+ {
+ "name": "convert-indesign-to-idml_job_id",
+ "in": "path",
+ "description": "The job ID returned by the Convert InDesign to IDML request.",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "The current job status, including any output details or warnings.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConvertIndesignToIdmlJobStatus"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/BadParams"
+ },
+ "401": {
+ "$ref": "#/components/responses/Unauthorized"
+ },
+ "403": {
+ "$ref": "#/components/responses/Forbidden"
+ },
+ "404": {
+ "$ref": "#/components/responses/NotFound"
+ },
+ "429": {
+ "$ref": "#/components/responses/TooManyRequests"
+ },
+ "500": {
+ "$ref": "#/components/responses/InternalServerError"
+ }
+ }
+ }
+ },
"/v3/status/{id}": {
"get": {
"operationId": "getJobStatus",
@@ -1287,6 +1434,15 @@
"type": "string",
"description": "This provides a path to a directory relative to a temporary base directory (working directory) where the fonts can be found. It cannot go up using '..' or '/'. Should be a valid path. For specifying a working directory, mention '.'."
}
+ },
+ "missingFontStrategy": {
+ "description": "This specifies the strategy to be used when a font is missing. One of: `fallback`, `fail`. Defaults to `fallback`.",
+ "type": "string",
+ "enum": [
+ "fallback",
+ "fail"
+ ],
+ "default": "fallback"
}
}
},
@@ -1405,6 +1561,335 @@
}
]
},
+ "MergeDataRequestV4": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/BaseJobRequestWithOutput"
+ },
+ {
+ "description": "Inputs for the data merge request.",
+ "type": "object",
+ "required": [
+ "params"
+ ],
+ "properties": {
+ "params": {
+ "type": "object",
+ "required": [
+ "targetDocument",
+ "dataSource"
+ ],
+ "properties": {
+ "targetDocument": {
+ "description": "The tagged document to be used as the template for merging.",
+ "type": "string"
+ },
+ "dataSource": {
+ "description": "The data source files to be used.",
+ "type": "string"
+ },
+ "outputMediaType": {
+ "description": "The type of output.",
+ "type": "string",
+ "enum": [
+ "image/jpeg",
+ "image/png",
+ "application/pdf",
+ "application/x-indesign"
+ ],
+ "default": "application/x-indesign"
+ },
+ "rulesFile": {
+ "description": "The rule json file having all the conditions and actions.",
+ "type": "string"
+ },
+ "copyfittingSettings": {
+ "type": "object",
+ "required": [
+ "enabled"
+ ],
+ "description": "Enables automatic copyfitting (font-size reduction) to resolve overset text after a merge. Copyfitting runs only when `enabled` is true; if the object is omitted, copyfitting is off.",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "description": "Master switch. Copyfitting runs only when true. If false, absent, or the object is omitted, copyfitting is off. Required to turn the feature on.",
+ "default": false
+ },
+ "unresolvedOversetHandling": {
+ "type": "string",
+ "description": "Behavior when text is still overset after copyfitting. One of: `warn`, `omit_records`.",
+ "default": "warn",
+ "enum": [
+ "warn",
+ "omit_records"
+ ]
+ },
+ "multiFrameSyncScope": {
+ "type": "string",
+ "description": "Applies the same font-size reduction to matching non-overset frames. One of: `paragraph_style`, `page`, `paragraph_style_and_page`, `document`. Omit to skip multi-frame sync.",
+ "enum": [
+ "paragraph_style",
+ "page",
+ "paragraph_style_and_page",
+ "document"
+ ]
+ },
+ "scope": {
+ "type": "object",
+ "properties": {
+ "global": {
+ "type": "object",
+ "properties": {
+ "constraints": {
+ "type": "object",
+ "properties": {
+ "fontSize": {
+ "type": "object",
+ "properties": {
+ "minPercent": {
+ "type": "number",
+ "description": "Floor for font-size reduction, as a percentage of the original size. Must be between 1 and 100; 100 means the text never shrinks.",
+ "default": 85
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ "exportSettings": {
+ "type": "object",
+ "description": "The settings corresponding to the output format.",
+ "properties": {
+ "jobOptionsFile": {
+ "type": "string",
+ "description": "File path reference to a `.joboptions` file (Adobe PDF preset file) containing custom PDF export settings. This file must be included as part of the input assets. It defines detailed PDF output configurations such as compression, color management, and security settings. When provided, this takes precedence over the `pdfPreset` attribute. Only applicable when generating PDF output.",
+ "default": "PDF preset `High Quality Print` will be used if not provided."
+ },
+ "pdfPreset": {
+ "type": "string",
+ "description": "The PDF export style to be used. This is relevant if `outputMediaType` is `application/pdf`.",
+ "default": "High Quality Print",
+ "enum": [
+ "High Quality Print",
+ "PDF/X-1a:2001",
+ "PDF/X-3:2002",
+ "PDF/X-4:2008",
+ "Press Quality",
+ "Smallest File Size"
+ ]
+ },
+ "quality": {
+ "type": "string",
+ "description": "Defines the quality of the output for JPEG and PNG formats.",
+ "default": "medium",
+ "enum": [
+ "low",
+ "medium",
+ "high",
+ "maximum"
+ ]
+ },
+ "linkImages": {
+ "description": "If `true`, links images to the target document. If `false`, embeds linked images already referred in the target document. Only relevant if `outputMediaType` is `application/x-indesign`.",
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "recordRange": {
+ "description": "The ranges of records to process for this job. Value can be `All`, along with numeral ranges. For example, '1-2, 5'.",
+ "type": "string",
+ "default": "All"
+ },
+ "allowMultipleRecordsPerPage": {
+ "description": "If `true`, will show as many records as will fit on a page.",
+ "type": "boolean",
+ "default": false
+ },
+ "multipleRecordLayoutOptions": {
+ "description": "The options to be used when `allowMultipleRecordsPerPage` is set to `true`.",
+ "type": "object",
+ "properties": {
+ "arrangeBy": {
+ "description": "The order that records will be arranged in the target document.\n* `rows_first` - Arranges records by row.\n* `columns_first` - Arranges records by column.\n",
+ "type": "string",
+ "default": "rows_first",
+ "enum": [
+ "rows_first",
+ "columns_first"
+ ]
+ },
+ "bottomMargin": {
+ "description": "The offset value of the bottom margin in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ },
+ "topMargin": {
+ "description": "The offset value of the top margin in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ },
+ "leftMargin": {
+ "description": "The offset value of the left margin in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ },
+ "rightMargin": {
+ "description": "The offset value of the right margin in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ },
+ "columnSpacing": {
+ "description": "The amount of spacing between columns of records in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ },
+ "rowSpacing": {
+ "description": "The amount of spacing between rows of records in the target document. The values can be specified like `1 pt`, `1 pica`, `1`, etc. If a number is mentioned in the string, it will be used as a value in pica.",
+ "type": "string"
+ }
+ }
+ },
+ "imagePlacementOptions": {
+ "description": "These are the options for image placement which will be used while merging images in the document.",
+ "type": "object",
+ "properties": {
+ "centerImage": {
+ "description": "If true, this centers the image in the frame while preserving the frame size as content size and proportions. If the content is larger than the frame, content around the edges is obscured by the bounding box of the frame.
This won't work when `fittingOption` is `Content_Aware_Fit`.",
+ "type": "boolean",
+ "default": false
+ },
+ "fittingOption": {
+ "description": "The method of fitting content in a frame.\n* `content_aware_fit` - Selects best crop region of the content for the frame based on Adobe Sensei. This preserves frame size but it might scale the content size. If this fitting is set, the `centerImage` property is turned-off.\n* `fill_proportional` - Resizes content to fill the frame while preserving the proportions of the content. If the content and frame have different proportions, some of the content is obscured by the bounding box of the frame.\n* `fit_content_to_frame` - Resizes content to fit the frame. Content that is a different size than the frame appears stretched or squeezed.\n* `fit_frame_to_content` - Resizes the frame so it fits the content.\n* `honor_existing_style` - Applies the frame fitting based on existing settings applied on the original frame.\n* `preserve_sizes` - Preserves the original sizes of the frame and the content. Content that is larger than the frame is obscured around the edges.\n* `proportional` - Resizes content to fit the frame while preserving content proportions. If the content and frame have different proportions, an empty space occurs in the frame.\n",
+ "type": "string",
+ "default": "proportional",
+ "enum": [
+ "content_aware_fit",
+ "fill_proportional",
+ "fit_content_to_frame",
+ "fit_frame_to_content",
+ "honor_existing_style",
+ "preserve_sizes",
+ "proportional"
+ ]
+ },
+ "linkImages": {
+ "description": "This applies to the images being brought in the document while merging. If true, this links images to the target document. If false, it embeds images in the target document.",
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "hyphenationSettings": {
+ "description": "Hyphenation settings to control word breaking and hyphenation behavior during merge.",
+ "type": "object",
+ "properties": {
+ "afterFirst": {
+ "type": "integer",
+ "description": "Minimum number of characters at the start of a word before a hyphen may be inserted."
+ },
+ "beforeLast": {
+ "type": "integer",
+ "description": "Minimum number of characters at the end of a word after a hyphen."
+ },
+ "wordsLongerThan": {
+ "type": "integer",
+ "description": "Minimum word length for hyphenation to apply."
+ },
+ "ladderLimit": {
+ "type": "integer",
+ "description": "Maximum allowed consecutive hyphenated lines."
+ },
+ "zone": {
+ "type": "number",
+ "description": "Whitespace ratio allowed at the end of a line before hyphenation begins (0\u20131)."
+ },
+ "capitalizedWords": {
+ "type": "boolean",
+ "description": "If true, allows hyphenation of capitalized words."
+ },
+ "lastWord": {
+ "type": "boolean",
+ "description": "If true, allows hyphenation of the last word in a paragraph."
+ },
+ "acrossColumns": {
+ "type": "boolean",
+ "description": "If true, allows hyphenation across columns."
+ },
+ "dictionarySettings": {
+ "type": "array",
+ "description": "Special hyphenation definitions by language.",
+ "items": {
+ "type": "object",
+ "required": [
+ "language",
+ "wordList"
+ ],
+ "properties": {
+ "language": {
+ "$ref": "#/components/schemas/HyphenationLanguage"
+ },
+ "wordList": {
+ "type": "array",
+ "description": "List of special hyphenation definitions (use `~` to mark break points, e.g., `Know~how`, `check~in`. Put `~` at the beginning of the word to exclude it from hyphenation, e.g., `~Wallstreet`, `~Starbucks`).",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "recordsPerFile": {
+ "description": "The maximum number of records per output file.",
+ "type": "integer",
+ "default": "By default this would not be applicable."
+ },
+ "removeBlankLines": {
+ "description": "If true, removes blank lines caused by empty fields.",
+ "type": "boolean",
+ "default": false
+ },
+ "convertUrlToHyperlink": {
+ "description": "If true, all URLs in the merged document are converted into hyperlinks.",
+ "type": "boolean",
+ "default": true
+ },
+ "outputFileBaseString": {
+ "type": "string",
+ "description": "The name of the output file.",
+ "default": "It is derived from the original document filename."
+ },
+ "outputFolderPath": {
+ "type": "string",
+ "description": "The path of the output folder.",
+ "default": "A unique temporary folder name would be created."
+ },
+ "presignedUrlsInDataSource": {
+ "description": "If true, fetches images from pre-signed URLs in the datasource `Image` column.",
+ "type": "boolean",
+ "default": false
+ },
+ "outputCompressMediaType": {
+ "type": "string",
+ "description": "The compression type for the output, if compressed output is desired.",
+ "enum": [
+ "application/zip"
+ ]
+ },
+ "outputCompressName": {
+ "type": "string",
+ "description": "The name of the resulting compressed output file.",
+ "default": "Result"
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
"MergeDataRequest": {
"allOf": [
{
@@ -1865,6 +2350,124 @@
}
]
},
+ "ConvertIndesignToIdmlRequest": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/BaseJobRequestWithOutput"
+ },
+ {
+ "description": "Inputs for converting an InDesign document to IDML.",
+ "type": "object",
+ "required": [
+ "params"
+ ],
+ "properties": {
+ "params": {
+ "type": "object",
+ "required": [
+ "targetDocuments"
+ ],
+ "properties": {
+ "targetDocuments": {
+ "type": "array",
+ "description": "The InDesign document to convert to IDML. Provide exactly one document in the array.",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "maxItems": 1
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "ConvertIndesignToIdmlJobStatus": {
+ "type": "object",
+ "description": "Status and output details for a Convert InDesign to IDML job.",
+ "properties": {
+ "jobId": {
+ "type": "string",
+ "description": "The unique job identifier."
+ },
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The time when the job reached this status."
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "not_started",
+ "running",
+ "succeeded",
+ "partial_success",
+ "failed"
+ ]
+ },
+ "outputs": {
+ "type": "array",
+ "description": "The result for the input document.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "input": {
+ "type": "string",
+ "description": "The submitted input file name."
+ },
+ "output": {
+ "type": "object",
+ "description": "The generated IDML file location.",
+ "properties": {
+ "url": {
+ "type": "string",
+ "description": "A pre-signed URL to download the IDML file."
+ }
+ }
+ },
+ "warnings": {
+ "type": "object",
+ "properties": {
+ "missingLinks": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "missingFonts": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "otherWarnings": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "errors": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "error_code": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
"ConvertToInDesignRequest": {
"allOf": [
{
@@ -2008,12 +2611,12 @@
"exportingSpread": {
"type": "boolean",
"default": false,
- "description": "Specify `true` if you consider range as spread numbers. Use `false` if you treat range as pages."
+ "description": "Specify `true` to export pages as spreads. Use `false` to export pages individually. This does not change how `pageRange` is interpreted."
},
"pageRange": {
"type": "string",
"default": "All",
- "description": "The page ranges, based on the index of the page within the document. The value can be 'All', as well as numeral ranges. If `exportingSpread` is true, this range would represent spread indices in the document."
+ "description": "The page ranges, based on the index of the page within the document. The value can be 'All', as well as numeral ranges. This always refers to the absolute page range in the document, regardless of the value of `exportingSpread`."
},
"quality": {
"type": "string",