Submit an asynchronous export of cards or table records, selected by a saved report or an ad-hoc filter, as a JSON or CSV file.
Before You Begin
🔗 Use the GraphQL Playground to execute the mutation in this guide.
➡️ New to GraphQL? Learn how to navigate the Playground with our Playground Basics Guide.
Why this use case
The batchExportData mutation submits an asynchronous export of cards (from a pipe) or records (from a database) as a single JSON or CSV file, selected either by a saved report or by an ad-hoc filter. It replaces polling large result sets page by page for bulk reads, and it reuses the same BatchOperation envelope (status lifecycle, idempotency, resultFile, and the completion webhook) that batchUpsert already exposes.
Availability
batchExportData is a Service Account only operation and is served behind the same batch operations feature flag that gates batchUpsert. The field is present in the schema only for organizations where the feature is enabled; if your organization does not have it enabled, the field will not appear and the mutation will fail validation.
A submission runs end to end: the batch is submitted, its rows are streamed to a single file, the file is uploaded, and the batch reaches a terminal status on its own. A submission is accepted as pending and moves to completed (with resultFile populated) or, if the run cannot produce a file, failed.
Prerequisites
- Authentication: Use a Service Account token (Personal Access Tokens are deprecated). The mutation rejects any non-service-account caller.
- Permissions: Your Service Account must be able to create/update cards in the target pipe or database (the same permission
batchUpsertrequires). - Selection: Exactly one of
reportIdoradvancedFilter— never both, never neither. UsereportIdto export the same rows and columns a saved report already resolves, oradvancedFilterfor an ad-hoc filter in the same shape saved reports accept.
Step 1: Run the mutation
mutation BatchExportData($input: BatchExportDataInput!) {
batchExportData(input: $input) {
batchOperation {
id
status
operationType
}
}
}
Variables
{
"input": {
"repoId": "pipe-or-table-id-here",
"entity": "CARDS",
"format": "csv",
"reportId": "42",
"idempotencyKey": "export-2026-08-06-daily"
}
}
repoId(required): the pipe or database (table) to export from.entity(required):CARDSorTABLE_RECORDS, and it must match whetherrepoIdis a pipe or a database; a mismatch is rejected before any batch is persisted.format(required):csvorjson.reportIdoradvancedFilter(exactly one required): the saved report to reuse, or an ad-hocReportCardsFilter-shaped filter. Submitting both, or neither, is a validation error and no batch is persisted. An empty or null value counts as absent, soreportId: ""with noadvancedFilteris rejected the same way as omitting both. AreportIdthat does not exist, or that belongs to a different repo thanrepoId, is also rejected.columns(optional): the columns to include in the export, by identifier (card_id,title,field_<id>, …). When omitted, the export resolves the repo's default column set. In the exported file, a custom field's column is headed by the field's label (repeated labels are disambiguated with the field id, e.g.Comment (field_105)); built-in columns keep their identifier.idempotencyKey(optional): resubmitting the same key returns the existing batch instead of starting a second export. See the section below before relying on this for a recurring export.callbackUrl(optional): a URL notified when the batch reaches a terminal status.
Step 2: Check the response
{
"data": {
"batchExportData": {
"batchOperation": {
"id": "8f3b1c9e-2a4d-4c7b-9f10-1d2e3a4b5c6d",
"status": "pending",
"operationType": "export_data"
}
}
}
}
Returned fields
| Field | Description |
|---|---|
batchOperation.id | Public identifier of the batch operation (a UUID) |
batchOperation.status | Lifecycle status; pending on submission, then completed or failed asynchronously |
batchOperation.operationType | Always export_data for a batch created by this mutation |
Poll this batch's status with the batchOperations query (see List Batch Operations of a Repo) or wait for callbackUrl to be notified when the batch reaches a terminal status.
Key Notes
Idempotency and re-running an export
idempotencyKey is accepted with the same semantics batchUpsert already uses: submitting the same key for the same repo again returns the original batch instead of creating a second one. For a write operation like batchUpsert that guarantee is unambiguous. For a read/export operation, it creates two edge cases that have no automatic resolution today:
- The exported file has expired. Once a batch's artifact is removed from storage (per your organization's retention window), resubmitting its
idempotencyKeystill returns the original batch ascompleted— but the download URL it carries no longer resolves to anything. The mutation cannot tell that the file is gone; it only knows the batch already ran. - The same key freezes the export's data forever. Reusing an
idempotencyKeyalways returns the original run's batch, never a fresh one — there is no path to force a new export for a key that has already been used. This differs frombatchUpsert, wherereprocessBatchOperationcan resubmit failed items to pick up new data; an export has no items at all, so that mutation has nothing to act on for a batch created bybatchExportData.
Workaround for both: use a new, never-before-used idempotencyKey (or omit it entirely) whenever you need a guaranteed fresh export. Do not reuse a fixed key across a recurring schedule if you expect each run to reflect current data — a fixed key is only safe for a genuinely one-time submission where returning the exact original result, or its now-expired URL, is acceptable.
Downloading the export
When the batch reaches completed, resultFile on the BatchOperation is a temporary download URL for the exported file, and totalCount is the number of rows exported (itemCounts is all zeros, since an export has no per-item results). resultFile is null while the batch is still pending, and on a failed batch. Read it with the batchOperations query once the status is completed, or take it from the completion webhook payload.

