Skip to main content
Returns transactions across your connected users as a single flat, keyset-paginated list, newest first. Every row carries the externalReferenceId and accountId of the user it belongs to. There is no per-user cap — page with nextCursor to walk every transaction in the window across every target user. Defaults to the last 90 days when no date filter is supplied.
Breaking change. This query previously returned results, one entry per target user, each holding up to 20 transactions. It now returns a flat transactions list with cursor pagination. See Migrating from the per-target response.

Requirements

  • Authorization: Basic <API_KEY> (your application API key)
  • The bulk API capability on your application
  • The LIST_PAYMENT and LIST_PURCHASES scopes on each target user’s grant
Failures are reported per target and never fail the whole request. See Bulk API Overview for the targeting model and error codes.

Query

Variables

Response

Arguments

The date window bounds the data; limit bounds a single page. The window may span at most 365 days. Transactions are stored in monthly partitions and each partition in the window is scanned per target, so a wider window costs more per page — it isn’t free. For longer history, use the export.

Targeting

targetSpec.mode is either SELECTED (name the users in targets, using the externalReferenceId you connected them with) or ALL_CONNECTED (every user with an active grant on your application). Duplicate targets are removed. This query accepts up to 1,000 target users. For more than that, use the asynchronous export.

Response fields

BulkTransaction

Four behaviors to be aware of:
  • transactionType is a human-readable label, not a stable enum — values look like "Account Transfer - In" or "Add Money", not TRANSFER or DEPOSIT. The set is open and the wording may change. Don’t switch on it in code; use recordId and the amount/sign for logic, and treat this field as display text.
  • Only PENDING and SETTLED transactions are returned — declined and other non-baseline records are excluded, matching the single-user transactions surface.
  • Ordering is newest first across the whole flat stream (createdAt descending, ties broken by recordId, then by user).
  • A transaction on a shared account appears once per grant that can see it — two attributed rows with the same recordId and different externalReferenceId.
BulkTransaction is a purpose-built, narrow type. It is not the full Transaction type returned by the single-user transactions query — the fields above are the complete set. For richer per-transaction data, use the asynchronous export.

BulkTargetFailure

A failed target never fails the request. Select both identifiers. externalReferenceId is null for any grant you connected without one, so on its own it may not tell you which user failed. accountId is populated whenever the target resolved — which is the case for INSUFFICIENT_SCOPE and ACCOUNT_NOT_PERMITTED — and is null only for TARGET_NOT_CONNECTED and INVALID_TARGET_IDENTIFIER, where nothing resolved. Querying errors { externalReferenceId accountId code message } means every entry is identifiable by at least one of the two.

Request-level errors

Everything above is per-target. These reject the whole request, returning data.getBulkTransactions: null plus a GraphQL error. Branch on extensions.code, never on the message text — wording can change, codes won’t. The two date failures share a code — both mean “the range you asked for isn’t usable” — and the message distinguishes them:
A cursor altered in any way — truncated, re-encoded, hand-edited — fails as APPLICATIONS-0010 before it reaches the database. Treat it as “start again from page one”, not as retryable.

Paging

Read the first page, then follow nextCursor until hasMore is false. Keep every other argument identical across pages — the cursor encodes a position in that specific query’s ordering.
Because paging is keyset-based rather than offset-based, transactions written while you page won’t shift rows across page boundaries or produce duplicates.

Migrating from the per-target response

When to use the export instead

getBulkTransactions can walk complete history by paging, so the export is for pulls you’d rather not page through — more than 1,000 users, windows longer than a year, scheduled batch jobs, or when you need richer per-transaction fields than BulkTransaction carries. Submit GET_TRANSACTIONS_EXPORT via submitBulkOperation, poll getBulkOperationJob, and download the NDJSON from the short-lived resultUrl. See Bulk Operations.