Report export webhooks
This page documents webhook events related to report exports. These events notify you when a report export starts and when the report file has been generated successfully.
For the common webhook envelope fields (id, attemptId, livemode, created, event), see Webhook structure.
Report exports
Emitted when a report export is processed.
| Trigger | Event name | When |
|---|---|---|
| Export job begins processing | report.export.started |
After the worker confirms the message will not be re-queued due to record-count splitting; immediately before reading report data |
| Report file generation succeeds | report.export.completed |
After the CSV is generated and uploaded to S3; before optional email delivery. Does not indicate that an email was sent or received |
Behavior notes
report.export.completedis emitted only when report generation and S3 upload succeed. If processing fails afterreport.export.started,report.export.completedis not emitted.- If the export is split into multiple parts (large reports),
report.export.startedis not emitted for the invocation that triggers the split; each resulting part emitsreport.export.startedwhen it is individually processed. report.export.completedindicates successful report generation, not successful email delivery. Email is sent after this webhook whendeliveryMethodisEmail.- For standard (non-custom) reports, several fields in
datamay beundefined:reportTypeName,customReportId,bucket,filters,reportTypeId,deliveryMethod. reportIdandreportTypeNameare resolved by Betterez when the export is requested; they are not necessarily provided by the original caller.columnscontains only column IDs. Entries without anidare omitted.createdAtindatais the UTC timestamp when the webhook is emitted (BzDate:valueandoffset), not a report date filter.- Sensitive fields such as API keys are not included in
data.
Payload example – started
The data object for report.export.started contains export context from the export request (subset of fields).
{
"attemptId": "d42c1225-9917-410c-950e-0383162d416b",
"created": 1779974953,
"data": {
"accountId": "52a377ec430c7d4e220001fc",
"reportId": "transaction-report-list",
"reportTypeName": "transactions",
"customReportId": "6a0ded79deaedd05c5fa32b6",
"bucket": {},
"filters": {
"status": "paid",
"agencyId": "all",
"stationId": "all",
"providerIds": null
},
"columns": [
"transactionNumber",
"customerNumber",
"customerName",
"status",
"total"
],
"reportTypeId": "5af353ef8d4d7e8551000001",
"emails": ["test@example.com"],
"format": "csv",
"deliveryMethod": "Email",
"createdAt": {
"value": "2026-05-20T17:24:50.130Z",
"offset": 0
},
"createdBy": "62179884ebb34d07f9a14cdc"
},
"event": "report.export.started",
"id": "7ec09d11-974e-4828-8373-c09fc9f9e738",
"livemode": true
}
Payload example – completed
The data object for report.export.completed has the same shape as report.export.started, plus fileName (generated CSV file name).
{
"attemptId": "ca8dfe73-029c-4c74-b43c-2706aae4d92a",
"created": 1779975021,
"data": {
"accountId": "52a377ec430c7d4e220001fc",
"reportId": "transaction-report-list",
"reportTypeName": "transactions",
"customReportId": "6a0ded79deaedd05c5fa32b6",
"bucket": {},
"filters": {
"status": "paid",
"agencyId": "all",
"stationId": "all",
"providerIds": null
},
"columns": [
"transactionNumber",
"customerNumber",
"customerName",
"status",
"total"
],
"reportTypeId": "5af353ef8d4d7e8551000001",
"emails": ["test@example.com"],
"format": "csv",
"deliveryMethod": "Email",
"createdAt": {
"value": "2026-05-20T17:25:12.456Z",
"offset": 0
},
"createdBy": "62179884ebb34d07f9a14cdc",
"fileName": "a1b2c3d4-e5f6-7890-abcd-ef1234567890.csv"
},
"event": "report.export.completed",
"id": "c1945aa8-2982-4974-9494-9f37db44244e",
"livemode": true
}
fileName is {prefixForFile}{uuid}.csv, where prefixForFile comes from the queue message (slashes removed) and uuid is a version-1 UUID.
Field descriptions – data
| Field | Type | Description |
|---|---|---|
| accountId | string | The account id for the export. |
| reportId | string | The report identifier. Resolved from reportTypeId when filters are used. |
| reportTypeName | string | The report type name. Resolved by Betterez from reportTypeId when the export is requested. |
| customReportId | string | The custom report id. Present for custom report exports. |
| bucket | object | S3 bucket configuration when delivery uses S3. Empty object {} for Email delivery. |
| filters | object | The filters applied to the report data. |
| columns | array of string | Column ids included in the export. |
| reportTypeId | string | The database id of the report type. |
| emails | array of string | Recipient email addresses for the export. |
| format | string | Output file format (for example, csv). |
| deliveryMethod | string | How the report is delivered: Email or S3. |
| createdAt | object | UTC date when the webhook was emitted (BzDate: value, offset). |
| createdBy | string | User id of the person who triggered the export. |
| fileName | string | Generated CSV file name. Present only on report.export.completed. Format: {prefixForFile}{uuid}.csv. |