> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waycore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transactions

> Browse historical transactions and sync incremental changes

A **Transaction** represents a single line item on a bank account as reported by the institution. Transactions are read-only and are populated automatically during connection syncs.

## Status lifecycle

| Status      | Meaning                                                                            |
| ----------- | ---------------------------------------------------------------------------------- |
| `pending`   | Authorised but not yet settled. Amount or details may still change.                |
| `posted`    | Fully settled.                                                                     |
| `reversed`  | Previously posted transaction that was reversed.                                   |
| `cancelled` | Pending item that was voided before settlement.                                    |
| `unknown`   | The bank provided a state that does not yet map cleanly to a richer public status. |

The current public implementation mainly emits `pending` and `posted`; the remaining values are reserved for broader coverage.

## Two ways to read transactions

### Historical browse — `GET /v1/transactions`

Use this endpoint for backfills, date-range queries, and reconciliation views. It supports filtering by `accountId`, `connectionId`, `entityId`, `status`, `rail`, `postedDateGte`, and `postedDateLt`. Results are cursor-paginated and can be sorted by `postedDate` or `updatedAt`.

List cursors are valid only for the same query and sort order. They are not interchangeable with sync cursors.

### Incremental sync — `GET /v1/transactions/sync`

Use this endpoint to maintain a current mirror of transactions over time. The sync stream returns change events ordered by the server's sync cursor ascending, not by `postedDate` or raw `updatedAt`.

<Warning>
  This is **not** the endpoint for fetching existing transactions, and it does **not** return your transaction history. The first call (without a cursor) returns **zero events by design** — it only establishes your stream head. Load historical data from `GET /v1/transactions`, then use sync for changes from that point on.
</Warning>

### No-gap bootstrap

1. Call `GET /v1/transactions/sync` **without** a cursor. This returns **no events** — its only purpose is to establish the stream head.
2. Save the returned `nextCursor` as your stream head.
3. Backfill historical data from `GET /v1/transactions`.
4. Resume polling `GET /v1/transactions/sync` from the saved cursor.
5. If `hasMore` is `true`, call again immediately with the returned `nextCursor`.

Duplicates between the backfill and later sync pages are expected. Reconcile by stable `transaction.id`.

<Note>
  Persist `nextCursor` only after the full page has been durably applied. If a sync call is retried, reuse the same cursor.
</Note>

### Empty responses are normal

A sync call that returns zero events means nothing has changed in that stream since your cursor — keep the same cursor and poll again later. Sync **does** deliver transactions: once data is created or changes, it arrives as `added` and `modified` events on the next poll. A zero-event response simply means there is nothing new since your cursor; it does **not** mean the connection has no transactions. Use `GET /v1/transactions` to read transactions that already exist (your historical set), and sync to stay up to date from there. If you expect changes but consistently see zero events, confirm you are polling with the cursor you saved and the **same** stream-defining filters you bootstrapped with (see below).

## Sync event types

| Event type | How to handle it                                               |
| ---------- | -------------------------------------------------------------- |
| `added`    | Upsert the embedded transaction by `transaction.id`.           |
| `modified` | Upsert the embedded transaction by `transaction.id`.           |
| `removed`  | Delete the referenced transaction id from your current mirror. |

`removed` currently represents transaction deletions. Account visibility changes without transaction mutations are intentionally out of scope for the current sync stream.

## Cursor and retry rules

* Sync cursors are valid only for the same stream-defining filters: `accountId`, `connectionId`, and `entityId`. If you bootstrap with one of these filters, keep polling with the same filter value.
* Sparse `fields=` selections do **not** change stream membership and are not part of cursor compatibility.
* Sync cursors expire after 90 days.
* `invalid_cursor` means the cursor is malformed or does not match the filter set. Changing the filters between bootstrap and polling returns this error — it does **not** silently fall back to zero events. Rebootstrap with the original filters.
* `cursor_expired` means you need to rebootstrap from scratch.
* If rate limited, honor `Retry-After` when present and retry with the same cursor.

## Key fields and rails

* **`amount`** — Signed decimal string. Positive = inflow, negative = outflow.
* **`entryType`** — `credit` or `debit`, as reported by the bank.
* **`rail`** — Payment rail such as `internalTransfer`, `card`, `ach`, `pix`, `caEft`, `auNpp`, `auBecsDirectEntry`, `auRtgs`, `sepaCredit`, `sepaDebit`, `wire`, `swift`, `fasterPayments`, `check`, `cash`, `crypto`, `other`, or `unknown`.
* **`paymentReference`** — Remittance reference for reconciliation (e.g. invoice number).
* **`bankReference`** — Bank-assigned operational tracking ID.
* **`counterpartyName`** / **`counterpartyAccountMasked`** — Available on many rail types.

Waycore can notify you through the [`transactions.sync_available`](/webhooks) webhook when fresh data is ready, so you do not need to poll blindly. Treat that webhook as a prompt to call `GET /v1/transactions/sync`, not as a replacement for the sync stream itself.

## Endpoints

<CardGroup cols={3}>
  <Card title="List transactions" icon="list" href="/api-reference/transactions/list-transactions" />

  <Card title="Sync transactions" icon="refresh-cw" href="/api-reference/transactions/sync-transactions" />

  <Card title="Get transaction" icon="search" href="/api-reference/transactions/get-transaction" />
</CardGroup>

## Required scopes

| Scope               | Used by         |
| ------------------- | --------------- |
| `transactions:read` | List, sync, get |
