Single PDF Async Generation
The POST /file/async/single endpoint generates a single PDF asynchronously from the specified design and parameters. It returns a requestId and file information immediately, so the client never has to wait for rendering.
Endpoint
- URL:
https://api.re-port-flow.com/v1/file/async/single - Method:
POST - Auth:
appkeyheader required - Timeout: none (async processing)
- Request body limit: 50MB (after Base64 encoding, roughly 37MB of binary data)
Example
cURL
curl -X POST https://api.re-port-flow.com/v1/file/async/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
}
}
}'
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
designId | string (UUID) | ✓ | Design ID |
version | integer | ✓ | Design version |
content.fileName | string | ✓ | File name (any character is allowed except `/ \ : * ? " < > |
content.shareType | string | - | Share type on the request side is a numeric code: "01" = workspace (default), "02" = invitee, "03" = public URL. In the response, share.shareType is returned as the human-readable name (workspace / invited / public) |
content.passcodeEnabled | boolean | - | Whether to enable passcode protection (default false) |
content.passthrough | object | - | Arbitrary metadata that will be echoed back in files[].passthrough (e.g. { "pageId": "abc123" }). Top-level strings/numbers are also stored as report-search metadata. |
content.params | object | ✓ | Template parameters. The expected structure is available from the design parameter 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.pdf",
"fileId": "7f3d1a2b-4c5e-6f7a-8b9c-0d1e2f3a4b5c",
"passthrough": { "pageId": "abc123" },
"share": {
"shareType": "workspace",
"url": "https://re-port-flow.com/file/{requestId}/{fileId}",
"passcodeEnabled": false
}
}
]
}
| Field | Type | Description |
|---|---|---|
requestId | string (UUID) | Request ID, used by the download endpoint |
url | string (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 |
files | array | Generated files |
files[].fileName | string | File name |
files[].fileId | string | File ID, used by the per-file download endpoint |
files[].passthrough | object | The content.passthrough value supplied on the request (only when set) |
files[].share.shareType | string | Share type (workspace / invited / public) |
files[].share.url | string | Sharable URL |
files[].share.passcodeEnabled | boolean | Whether passcode protection is enabled |
files[].share.passcode | string | Server-generated passcode (only when passcodeEnabled=true AND immediately after generation) |
passthroughReportFlow 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.
Errors
Errors are the same shape as the synchronous endpoint. See Single PDF Sync Generation — Errors.
Async flow
1. Client → API: send generation request
↓
2. API → Client: returns requestId / url / files immediately (202 Accepted)
↓
3. API: starts background PDF generation
↓
4. API: uploads the result to S3 when done
↓
5. Client: download the PDF via /v1/file/download/{requestId}/{fileId}
(the `url` in the response is an app-screen link and cannot be used
to download the file)
Use cases
Case 1: background generation
Accept the user request immediately and let the rendering happen in the background.
app.post('/api/generate-report', async (req, res) => {
const response = await axios.post(
'https://api.re-port-flow.com/v1/file/async/single',
{
designId: '...',
version: 1,
content: { fileName: 'report.pdf', params: req.body },
},
{ headers: { appkey: process.env.APP_KEY } },
);
const { requestId, url, files } = response.data;
res.status(202).json({
message: 'Report generation started',
requestId,
fileId: files[0].fileId,
// Link to the app screen (output history) where the result can be
// reviewed. Requires a login; it is not a direct file download URL.
outputsUrl: url,
});
});
Fetch the generated file with requestId / fileId via file download. Authenticate with either the appkey header or an OAuth 2.0 access token (Authorization: Bearer) — see Authentication for which to pick.
An appkey is issued per workspace, and an OAuth 2.0 access token is bound to the workspace chosen at consent. Credentials for a different workspace than the one that generated the file cannot retrieve its requestId / fileId.
Keeping the appkey on your server, as above, fits "automating a single workspace": both generation and retrieval stay inside that appkey's workspace.
To let external or third-party users work with their own workspace data, use OAuth 2.0 Authorization Code + PKCE, have the user authorize, and issue both the generation request and the download with that same access token (required scope: pdf:generate). A file generated with the server appkey above cannot be fetched with a token for another workspace.
Case 2: webhook notifications (recommended)
Use ReportFlow's built-in webhook to be notified when generation finishes — no polling required.
See the Webhook guide for details, including HMAC-SHA256 signature verification.
FAQ
Should I use sync or async generation?
Use Single PDF Sync Generation when you need the PDF back immediately. Use this async endpoint when generation takes a long time, or when you want to avoid the 120-second sync timeout.
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
- Multiple PDF Async Generation — generate many PDFs in one async call
- Async Workflows — best practices for high-volume generation
- File Download — how to download the generated files