Submit a Batch Export of Records or Cards

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

  1. Authentication: Use a Service Account token (Personal Access Tokens are deprecated). The mutation rejects any non-service-account caller.
  2. Permissions: Your Service Account must be able to create/update cards in the target pipe or database (the same permission batchUpsert requires).
  3. Selection: Exactly one of reportId or advancedFilter — never both, never neither. Use reportId to export the same rows and columns a saved report already resolves, or advancedFilter for 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): CARDS or TABLE_RECORDS, and it must match whether repoId is a pipe or a database; a mismatch is rejected before any batch is persisted.
  • format (required): csv or json.
  • reportId or advancedFilter (exactly one required): the saved report to reuse, or an ad-hoc ReportCardsFilter-shaped filter. Submitting both, or neither, is a validation error and no batch is persisted. An empty or null value counts as absent, so reportId: "" with no advancedFilter is rejected the same way as omitting both. A reportId that does not exist, or that belongs to a different repo than repoId, 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

FieldDescription
batchOperation.idPublic identifier of the batch operation (a UUID)
batchOperation.statusLifecycle status; pending on submission, then completed or failed asynchronously
batchOperation.operationTypeAlways 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:

  1. The exported file has expired. Once a batch's artifact is removed from storage (per your organization's retention window), resubmitting its idempotencyKey still returns the original batch as completed — 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.
  2. The same key freezes the export's data forever. Reusing an idempotencyKey always 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 from batchUpsert, where reprocessBatchOperation can 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 by batchExportData.

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.