Skip to main content

Sync Single PDF Generation

The POST /file/sync/single endpoint generates a single PDF file synchronously from the specified design and parameters.

Endpoint Information

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

Usage Examples

cURL

curl -X POST https://api.re-port-flow.com/v1/file/sync/single \
-H "appkey: your-application-key" \
-H "Content-Type: application/json" \
-d '{
"designId": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"content": {
"fileName": "invoice.pdf",
"shareType": "01",
"passcodeEnabled": false,
"params": {
"customerName": "John Doe",
"invoiceNumber": "INV-2024-001",
"amount": 10000
}
}
}' \
--output invoice.pdf

JavaScript (Node.js)

import axios from 'axios';
import fs from 'fs';

async function generatePDF(params) {
try {
const response = await axios.post(
'https://api.re-port-flow.com/v1/file/sync/single',
{
designId: params.designId,
version: params.version,
content: {
fileName: params.fileName,
shareType: params.shareType ?? '01',
passcodeEnabled: params.passcodeEnabled ?? false,
params: params.data
}
},
{
headers: {
'appkey': process.env.APP_KEY,
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
}
);

fs.writeFileSync(params.fileName, response.data);

// X-File-Mapping is URL-encoded JSON. Decode with decodeURIComponent → JSON.parse.
const requestId = response.headers['request-id'];
const fileUrl = response.headers['file-url'];
const fileMapping = JSON.parse(decodeURIComponent(response.headers['x-file-mapping']));

console.log('PDF generated:', { requestId, fileUrl, fileMapping });
return { data: response.data, requestId, fileUrl, fileMapping };
} catch (error) {
console.error('PDF generation error:', error.response?.data || error.message);
throw error;
}
}

generatePDF({
designId: '550e8400-e29b-41d4-a716-446655440000',
version: 1,
fileName: 'invoice.pdf',
shareType: '01',
passcodeEnabled: false,
data: {
customerName: 'John Doe',
invoiceNumber: 'INV-2024-001',
amount: 10000
}
});

Python

import requests
import json
from urllib.parse import unquote

def generate_pdf(params):
url = "https://api.re-port-flow.com/v1/file/sync/single"
headers = {
'appkey': params['app_key'],
'Content-Type': 'application/json'
}
data = {
'designId': params['design_id'],
'version': params['version'],
'content': {
'fileName': params['file_name'],
'shareType': params.get('share_type', '01'),
'passcodeEnabled': params.get('passcode_enabled', False),
'params': params['data']
}
}

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

with open(params['file_name'], 'wb') as f:
f.write(response.content)

# X-File-Mapping is URL-encoded JSON; decode with unquote → json.loads.
request_id = response.headers.get('request-id')
file_url = response.headers.get('file-url')
file_mapping = json.loads(unquote(response.headers.get('x-file-mapping', '[]')))

return {'request_id': request_id, 'file_url': file_url, 'file_mapping': file_mapping}

result = generate_pdf({
'app_key': 'your-application-key',
'design_id': '550e8400-e29b-41d4-a716-446655440000',
'version': 1,
'file_name': 'invoice.pdf',
'share_type': '01',
'passcode_enabled': False,
'data': {
'customerName': 'John Doe',
'invoiceNumber': 'INV-2024-001',
'amount': 10000
}
})

Request Parameters

FieldTypeRequiredDescription
designIdstring (UUID)Design ID
versionintegerVersion number
content.fileNamestringFile name (anything except / \\ : * ? " < > | and control characters is allowed)
content.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 (workspace / invited / public).
content.passcodeEnabledboolean-Enable passcode protection (default: false). When true, the response share.passcode returns a server-generated passcode exactly once.
content.passthroughobject-Arbitrary string KV that is echoed back in the response X-File-Mapping[].passthrough. Useful for tracking with webhooks (e.g. { "orderId": "...", "userId": "..." }).
content.paramsobjectParameters embedded into the template (check structure with the Design Parameters API)

Response

Success (200 OK)

Response Body: PDF file (binary)

Response Headers:

HeaderDescriptionExample
Content-TypeContent typeapplication/pdf
Content-LengthFile size in bytes102400
Content-DispositionFile nameattachment; filename="invoice.pdf"
File-URLURL of the workspace download endpointhttps://api.re-port-flow.com/v1/file/download/{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

X-File-Mapping structure (after decoding):

[
{
"fileId": "7f3d1a2b-4c5e-6f7a-8b9c-0d1e2f3a4b5c",
"fileName": "invoice.pdf",
"passthrough": { "orderId": "ORD-2024-001" },
"share": {
"shareType": "workspace",
"url": "https://app.re-port-flow.com/file/{requestId}/{fileId}",
"passcodeEnabled": false
}
}
]

passthrough is included only when content.passthrough was specified in the request.

Errors

412 Precondition Failed

{
"statusCode": 412,
"message": "認証方式ヘッダーが存在しません"
}

Cause: appkey header is missing.

400 Bad Request

{
"statusCode": 400,
"message": [
"designId must be a UUID",
"ファイル名に使用できない文字が含まれています(/ \\ : * ? \" < > | および制御文字は使用不可)"
],
"error": "Bad Request"
}

Cause: Invalid request parameters.

401 Unauthorized

{
"statusCode": 401,
"message": "認証情報が不正です",
"error": "Unauthorized"
}

(The server returns the message in Japanese; it translates to "Invalid credentials".)

Cause: Authentication failure.

Solution:

  • Verify the value of the appkey header is correct.

500 Internal Server Error

{
"statusCode": 500,
"message": "Internal server error",
"error": "Internal Server Error"
}

Best Practices

1. Timeout Handling

The sync API times out after 120 seconds. For large PDFs or complex designs, consider using the async API.

const response = await axios.post(url, data, {
timeout: 120000 // 120 seconds
});

2. Retry Logic

For transient 5xx errors, retry with exponential backoff.

async function generatePDFWithRetry(params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await generatePDF(params);
} catch (error) {
if (error.response?.status === 500 && i < maxRetries - 1) {
const delay = 1000 * Math.pow(2, i);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}

3. File Name Sanitization

function sanitizeFileName(fileName) {
// Remove / \ : * ? " < > | and control characters
return fileName.replace(/[\/\\:*?"<>|\x00-\x1F]/g, '_');
}

Use Cases

Case 1: Instant Invoice Generation

Generate and download a PDF immediately when the user clicks the "Download Invoice" button.

app.get('/api/invoices/:id/download', async (req, res) => {
const invoice = await getInvoice(req.params.id);

const pdf = await generatePDF({
designId: 'invoice-template-id',
version: 1,
fileName: `invoice_${invoice.number}.pdf`,
data: invoice
});

res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="invoice_${invoice.number}.pdf"`);
res.send(pdf.data);
});

Case 2: Preview Generation

Generate a PDF in real time when the user clicks the preview button in the design editor.

async function showPreview(designId, params) {
const pdf = await generatePDF({
designId,
version: 1,
fileName: 'preview.pdf',
data: params
});

const blob = new Blob([pdf.data], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
window.open(url, '_blank');
}

Next Steps