Skip to main content

Async Single PDF Generation

The POST /file/async/single endpoint generates a single PDF file asynchronously from the specified design and parameters. It returns the file URL and ID immediately, avoiding timeout issues.

Endpoint Information

  • URL: https://{workspaceId}.re-port-flow.com/v1/file/async/single
  • Method: POST
  • Authentication: Requires AppKey and SecretKey
  • Timeout: None (async processing)
  • Request Size Limit: 20MB

Usage Examples

cURL

curl -X POST https://your-workspace-id.re-port-flow.com/v1/file/async/single \
-H "AppKey: your-app-key" \
-H "SecretKey: your-secret-key" \
-H "Content-Type: application/json" \
-d '{
"designId": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"content": {
"fileName": "invoice.pdf",
"params": {
"customerName": "John Doe",
"invoiceNumber": "INV-2024-001",
"amount": 10000
}
}
}'

Response example:

{
"url": "https://re-port-flow.com/workspace-id/design/550e8400-e29b-41d4-a716-446655440000/files/file-uuid",
"fileId": "file_abc123"
}

JavaScript (Node.js)

const axios = require('axios');

async function generatePDFAsync(params) {
try {
// 1. Async generation request
const response = await axios.post(
`https://${process.env.WORKSPACE_ID}.re-port-flow.com/v1/file/async/single`,
{
designId: params.designId,
version: params.version,
content: {
fileName: params.fileName,
params: params.data
}
},
{
headers: {
'AppKey': process.env.APP_KEY,
'SecretKey': process.env.SECRET_KEY,
'Content-Type': 'application/json'
}
}
);

const { url, fileId } = response.data;
console.log('PDF generation started:', { url, fileId });

// 2. Download PDF from URL (optional)
const pdfResponse = await axios.get(url, {
responseType: 'arraybuffer'
});

return {
data: pdfResponse.data,
url,
fileId
};
} catch (error) {
console.error('PDF generation error:', error.response?.data || error.message);
throw error;
}
}

// Usage example
generatePDFAsync({
designId: '550e8400-e29b-41d4-a716-446655440000',
version: 1,
fileName: 'invoice.pdf',
data: {
customerName: 'John Doe',
invoiceNumber: 'INV-2024-001',
amount: 10000
}
}).then(result => {
console.log('PDF generation complete:', result.url);
});

Python

import requests
import time

def generate_pdf_async(params):
# 1. Async generation request
url = f"https://{params['workspace_id']}.re-port-flow.com/v1/file/async/single"
headers = {
'AppKey': params['app_key'],
'SecretKey': params['secret_key'],
'Content-Type': 'application/json'
}
data = {
'designId': params['design_id'],
'version': params['version'],
'content': {
'fileName': params['file_name'],
'params': params['data']
}
}

response = requests.post(url, headers=headers, json=data)
response.raise_for_status()

result = response.json()
pdf_url = result['url']
file_id = result['fileId']

print(f'PDF generation started: {pdf_url}')

# 2. Download PDF
pdf_response = requests.get(pdf_url)
pdf_response.raise_for_status()

# Save to file
with open(params['file_name'], 'wb') as f:
f.write(pdf_response.content)

return {'url': pdf_url, 'file_id': file_id}

# Usage example
result = generate_pdf_async({
'workspace_id': 'your-workspace-id',
'app_key': 'your-app-key',
'secret_key': 'your-secret-key',
'design_id': '550e8400-e29b-41d4-a716-446655440000',
'version': 1,
'file_name': 'invoice.pdf',
'data': {
'customerName': 'John Doe',
'invoiceNumber': 'INV-2024-001',
'amount': 10000
}
})

Request Parameters

FieldTypeRequiredDescription
designIdstring (UUID)Design ID
versionintegerVersion number
content.fileNamestringFile name (alphanumeric, Japanese, -, _, . only)
content.paramsobjectParameters to embed in template (check structure via Design Parameters API)

Response

Success (202 Accepted)

{
"url": "https://re-port-flow.com/workspace-id/design/550e8400-e29b-41d4-a716-446655440000/files/file-uuid",
"fileId": "file_abc123"
}
FieldTypeDescription
urlstring (URI)Generated PDF file URL
fileIdstringFile ID (can be used with download endpoint)

Errors

Same error responses as the sync generation endpoint. See Sync Single PDF Generation for details.

Async Processing Flow

1. Client → API: Send generation request

2. API → Client: Return URL and fileId immediately (202 Accepted)

3. API: Start PDF generation in background

4. API: Upload to S3 after generation completes

5. Client: Download PDF from returned URL

Use Cases

Case 1: Background PDF Generation

Accept user requests immediately and process in the background.

app.post('/api/generate-report', async (req, res) => {
try {
// Start async PDF generation
const { url, fileId } = await startPDFGeneration(req.body);

// Respond immediately
res.status(202).json({
message: 'Report generation started',
downloadUrl: url,
fileId
});

// Send email notification when complete (background)
notifyWhenComplete(fileId, req.user.email);
} catch (error) {
res.status(500).json({ error: error.message });
}
});

Case 2: Parallel Bulk PDF Generation

Generate multiple PDFs in parallel.

async function generateBulkPDFs(items) {
// Start async generation for all items
const promises = items.map(item =>
generatePDFAsync({
designId: 'template-id',
version: 1,
fileName: `${item.id}.pdf`,
data: item
})
);

// Wait for all to complete
const results = await Promise.all(promises);

console.log(`${results.length} PDFs generated`);
return results;
}

// Usage example: Generate 100 PDFs in parallel
const invoices = [/* 100 data items */];
const results = await generateBulkPDFs(invoices);

Using ReportFlow's built-in webhook feature allows you to receive real-time completion notifications without polling.

// 1. Pre-configure Webhook URL in workspace settings
// Example: https://your-service.com/webhooks/pdf-completed

// 2. Request async PDF generation
const { url, fileId } = await generatePDFAsync({
designId: '550e8400-e29b-41d4-a716-446655440000',
version: 1,
fileName: 'invoice.pdf',
data: {
customerName: 'John Doe',
invoiceNumber: 'INV-2024-001',
amount: 10000
}
});

// 3. ReportFlow automatically sends webhook notification (on completion)
// Notification payload:
// {
// "event": "file.completed",
// "timestamp": "2026-02-15T10:30:45.123Z",
// "workspaceId": "ws_abc123",
// "designId": "550e8400-e29b-41d4-a716-446655440000",
// "version": 1,
// "files": [
// {
// "fileId": "file_xyz",
// "uuid": "uuid_456",
// "fileName": "invoice.pdf",
// "params": { ... }
// }
// ]
// }

// 4. Download file in webhook endpoint
app.post('/webhooks/pdf-completed', async (req, res) => {
const { files, workspaceId, designId } = req.body;

for (const file of files) {
const downloadUrl = `https://${workspaceId}.re-port-flow.com/v1/file/download/${file.uuid}/${file.fileId}`;
const pdfBuffer = await downloadPDF(downloadUrl);
await sendEmail(file.params.email, pdfBuffer);
}

res.status(200).json({ received: true });
});

See Webhook Notification Guide for details.

Only consider custom polling implementation if webhook functionality is unavailable.

// PDF generation request
async function generateWithWebhook(params, webhookUrl) {
const { url, fileId } = await generatePDFAsync(params);

// Save job info to your database
await saveJob({
fileId,
url,
status: 'processing',
webhookUrl
});

// Poll status in background
pollJobStatus(fileId, webhookUrl);

return { fileId, url };
}

// Polling process
async function pollJobStatus(fileId, webhookUrl) {
const maxAttempts = 60; // Max 5 minutes (5 second intervals)

for (let i = 0; i < maxAttempts; i++) {
await sleep(5000); // Wait 5 seconds

try {
// Check if file exists by accessing URL
const response = await axios.head(url);

if (response.status === 200) {
// Send completion notification
await axios.post(webhookUrl, {
status: 'completed',
fileId,
url
});
break;
}
} catch (error) {
// Still generating
continue;
}
}
}

Best Practices

1. File Retention Period

Generated files are accessible for a limited period. Download immediately if long-term storage is needed.

2. Retry Logic

async function generateWithRetry(params, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await generatePDFAsync(params);
} catch (error) {
if (error.response?.status >= 500 && attempt < maxRetries - 1) {
const delay = 1000 * Math.pow(2, attempt);
await sleep(delay);
continue;
}
throw error;
}
}
}

3. Error Handling

Errors can occur during async PDF generation. Contact support if the returned URL is inaccessible.

Next Steps