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
| Field | Type | Required | Description |
|---|---|---|---|
designId | string (UUID) | ✓ | Design ID |
version | integer | ✓ | Version number |
content.fileName | string | ✓ | File name (alphanumeric, Japanese, -, _, . only) |
content.params | object | ✓ | Parameters 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"
}
| Field | Type | Description |
|---|---|---|
url | string (URI) | Generated PDF file URL |
fileId | string | File 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);
Case 3: Using Webhook Notifications (Recommended)
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.
Case 4: Custom Polling Implementation (Not Recommended)
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
- Async Multiple PDF Generation - Bulk async PDF generation
- Async Workflows - Best practices for bulk generation
- File Download - How to download generated files