Skip to main content

Async Multiple PDF Generation (ZIP)

The POST /file/async/multiple endpoint generates multiple PDF files asynchronously from the specified design and multiple parameters, and saves them as a ZIP file.

Endpoint Information

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

Usage Examples

cURL

curl -X POST https://api.re-port-flow.com/v1/file/async/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": "01",
"passcodeEnabled": false,
"params": { "customerName": "Jane Smith", "invoiceNumber": "INV-002" }
}
]
}'

JavaScript

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

const { requestId, url, files } = response.data;
console.log('ZIP generation started:', { requestId, url, files });

return { requestId, url, files };
}

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 arbitrary metadata echoed back in files[].passthrough. Top-level strings/numbers are also stored as report-search metadata.
contents[].paramsobjectParameters (check structure via Design Parameters API)

Response

Success (202 Accepted)

{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://re-port-flow.com/{workspaceId}/design/{designId}/outputs?requestId={requestId}",
"files": [
{
"fileName": "invoice_001.pdf",
"fileId": "aaa111",
"share": {
"shareType": "workspace",
"url": "https://re-port-flow.com/file/{requestId}/aaa111",
"passcodeEnabled": false
}
},
{
"fileName": "invoice_002.pdf",
"fileId": "bbb222",
"share": {
"shareType": "workspace",
"url": "https://re-port-flow.com/file/{requestId}/bbb222",
"passcodeEnabled": false
}
}
]
}
FieldTypeDescription
requestIdstring (UUID)Request ID (used with the download endpoint)
urlstring (URI)URL of the app screen (output history) where the generated result can be reviewed. Not a direct file download URL — use file download to fetch files
filesarrayInformation for each generated PDF file
files[].fileNamestringPDF file name
files[].fileIdstringIndividual file ID (used with individual download endpoint)
files[].passthroughobjectValue of contents[].passthrough from the request (only when specified)
files[].share.shareTypestringShare type (workspace / invited / public)
files[].share.urlstringFile view URL
files[].share.passcodeEnabledbooleanPasscode enabled flag
files[].share.passcodestringServer-generated passcode (only when passcodeEnabled=true, immediately after generation)
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 to webhook endpoints.

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

{
"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.

Error Responses

Same error responses as Sync Single PDF Generation, plus the following:

400 Bad Request (duplicate fileName)

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

Cause: Multiple entries in contents share the same fileName (including case-insensitive matches).

Use Cases

Bulk Invoice Generation

async function generateBulkInvoices(invoices) {
const batchSize = 100;
const batches = chunkArray(invoices, batchSize);
const results = [];

for (const [index, batch] of batches.entries()) {
console.log(`Processing batch ${index + 1}/${batches.length}...`);

const contents = batch.map(invoice => ({
fileName: `invoice_${invoice.number}.pdf`,
shareType: '01',
passcodeEnabled: false,
params: invoice
}));

const result = await generateMultiplePDFsAsync('template-id', contents);
results.push(result);

// Rate limiting
if (index < batches.length - 1) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}

return results;
}

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 (100 requests/min for async endpoints). For large runs, split the work across several requests and batch them inside the rate limit.

How do I know when generation has finished?

Set up a webhook and you receive completion in real time with no polling — see the Webhook guide. Without a webhook, take the requestId from the response and poll the download endpoint.

Next Steps