Skip to main content

Sync Multiple PDF Generation (ZIP)

The POST /file/sync/multiple endpoint generates multiple PDF files synchronously from the specified design and multiple parameters, and returns them as a ZIP file.

Endpoint Information

  • URL: https://api.re-port-flow.com/v1/file/sync/multiple
  • Method: POST
  • Authentication: appkey header required
  • Timeout: 120 seconds (depends on file count)
  • Request Size Limit: 50MB (Base64-encoded; ~37MB raw equivalent)

Usage Examples

cURL

curl -X POST https://api.re-port-flow.com/v1/file/sync/multiple \
-H "appkey: your-application-key" \
-H "Content-Type: application/json" \
-d '{
"designId": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"contents": [
{
"fileName": "invoice_001.pdf",
"shareType": "01",
"passcodeEnabled": false,
"params": {
"customerName": "John Doe",
"invoiceNumber": "INV-001"
}
},
{
"fileName": "invoice_002.pdf",
"shareType": "02",
"passcodeEnabled": false,
"params": {
"customerName": "Jane Smith",
"invoiceNumber": "INV-002"
}
}
]
}' \
--output invoices.zip

JavaScript

const axios = require('axios');
const fs = require('fs');

async function generateMultiplePDFs(designId, contents) {
const response = await axios.post(
`https://api.re-port-flow.com/v1/file/sync/multiple`,
{
designId,
version: 1,
contents
},
{
headers: {
'appkey': process.env.APP_KEY
},
responseType: 'arraybuffer'
}
);

// Get file mapping from X-File-Mapping header
// X-File-Mapping is URL-encoded JSON; decode with decodeURIComponent → JSON.parse.
const fileMapping = JSON.parse(decodeURIComponent(response.headers['x-file-mapping']));
console.log('Generated files:', fileMapping);

return response.data; // ZIP binary
}

// Usage example
const contents = [
{
fileName: 'invoice_001.pdf',
params: { customerName: 'John Doe', invoiceNumber: 'INV-001' }
},
{
fileName: 'invoice_002.pdf',
params: { customerName: 'Jane Smith', invoiceNumber: 'INV-002' }
}
];

const zipData = await generateMultiplePDFs('550e8400-...', contents);
fs.writeFileSync('invoices.zip', zipData);

Request Parameters

FieldTypeRequiredDescription
designIdstring (UUID)Design ID
versionintegerVersion number
contentsarrayArray of ContentDto (minimum 1 item)
contents[].fileNamestringFile name (anything except / \ : * ? " < > | and control characters is allowed; must be unique within the array, case-insensitive)
contents[].shareTypestring-Share type (request side uses numeric codes). "01" = workspace share (default) / "02" = invited-only / "03" = public URL share. The response share.shareType returns the human-readable name.
contents[].passcodeEnabledboolean-Enable passcode protection (default: false).
contents[].passthroughobject-Per-file string KV echoed back in the response X-File-Mapping[].passthrough. Top-level strings/numbers are also stored as report-search metadata.
contents[].paramsobjectParameters (check structure via Design Parameters API)

Response

Success (200 OK)

Response Body: ZIP file (binary)

Response Headers:

HeaderDescriptionExample
Content-TypeContent typeapplication/zip
Content-LengthFile size in bytes307200
Content-DispositionFile nameattachment; filename="files.zip"
File-URLURL of the app screen (output history) where the generated result can be reviewed. This is not a direct file download URLhttps://re-port-flow.com/{workspaceId}/design/{designId}/outputs?requestId={requestId}
Request-IdRequest ID550e8400-e29b-41d4-a716-446655440000
X-File-MappingFile metadata and share info (JSON array). URL-encoded, so clients must call decodeURIComponent before JSON.parse.See below
File-URL is not a download URL

File-URL points to the app screen (output history) where the generated result can be reviewed, and opening it requires signing in to Re:port Flow. To fetch files programmatically, use the file download endpoints instead (requestId for a ZIP of the whole request, requestId + fileId for a single PDF).

This header was previously documented as a "ZIP download URL", which did not match what the implementation returns. The documentation has been corrected to match the implementation; the response behaviour itself is unchanged.

Structure of X-File-Mapping:

[
{
"fileId": "aaa111",
"fileName": "invoice_001.pdf",
"passthrough": { "pageId": "abc123" },
"share": {
"shareType": "workspace",
"url": "https://re-port-flow.com/file/{requestId}/aaa111",
"passcodeEnabled": false
}
},
{
"fileId": "bbb222",
"fileName": "invoice_002.pdf",
"share": {
"shareType": "invited",
"url": "https://re-port-flow.com/file/{requestId}/bbb222",
"passcodeEnabled": false
}
}
]

The passthrough field is included only on entries where contents[].passthrough was set on the request.

When to use passthrough

ReportFlow does not echo back params (the data used to render the PDF) on responses or webhooks, both for payload size and to avoid leaking business data.

If you need to know which business record each PDF corresponds to, put your own DB id (or any opaque token) into passthrough on the request. The exact value comes back unchanged on responses and webhooks.

{
"fileName": "invoice.pdf",
"passthrough": { "invoiceId": "INV-001", "tenantId": "acme" },
"params": { "customerName": "John Doe", "amount": 10000 }
}

When the webhook arrives, look up your DB by invoiceId to find the record to update. params (the customer name, amount, etc.) is never sent off-server.

Top-level string/number values in passthrough are also stored as report-search metadata (both in the generated PDF's XMP metadata and in the Re:port Flow app's report-search index). See passthrough and report-search metadata for which values are indexed, the limits, and why personal data doesn't belong there.

Errors

In addition to the same error responses as Single PDF Sync Generation — Errors, the following error may be returned:

400 Bad Request (duplicate fileName)

{
"statusCode": 400,
"message": [
"Duplicate fileName in contents (case-insensitive). Each file must have a unique name."
],
"error": "Bad Request"
}

Cause: two or more entries in contents share the same fileName (case-insensitive).

Use Cases

Bulk Monthly Invoice Generation

async function generateMonthlyInvoices(month) {
// Get invoice data for the month
const invoices = await getInvoicesByMonth(month);

// Create ContentDto array
const contents = invoices.map(invoice => ({
fileName: `invoice_${invoice.number}.pdf`,
params: invoice
}));

// Bulk generation
const zipData = await generateMultiplePDFs('invoice-template-id', contents);

// Save ZIP file
fs.writeFileSync(`invoices_${month}.zip`, zipData);
}

FAQ

How many PDFs can one request generate?

The contents array has no explicitly documented item limit, but the request must stay within the request size cap (50MB after Base64 encoding) and the rate limit (30 requests/min for sync endpoints). For large runs, consider Multiple PDF Async Generation instead.

Should I use sync or async generation?

Use the sync endpoint when you need the ZIP back immediately. When the batch is large and the 120-second timeout is a concern, use Multiple PDF Async Generation.

Next Steps