> ## 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.

# Sync Transactions

> Incremental transaction changefeed for maintaining a current mirror, not an immutable history log. For a no-gap bootstrap, call this endpoint without a cursor and save `nextCursor`, then backfill with `GET /v1/transactions`, then poll from the saved cursor. Responses are ordered by the server's sync cursor ascending and act as a convergence-safe stream: reusing the same cursor later returns the then-current ordered suffix after that cursor, not a byte-for-byte replay of an earlier page. Persist `nextCursor` only after the full page has been durably applied. Clients should upsert both `added` and `modified`, delete on `removed`, and call again immediately with `nextCursor` while `hasMore` is true. Duplicates between the backfill and later sync calls are expected. Cursors are valid only for the same stream-defining filters, expire after 90 days, and return `invalid_cursor` for malformed or filter-mismatched cursors or `cursor_expired` when the client must rebootstrap. If rate limited, honor `Retry-After` when present and retry with the same cursor. Under the current product model, sync events are transaction-write driven: `removed` is emitted for transaction deletions, and account visibility changes without transaction mutations are intentionally out of scope.



## OpenAPI

````yaml /openapi.json get /v1/transactions/sync
openapi: 3.1.0
info:
  title: Waycore Bank Connections API
  description: >-
    Developer-first API for direct bank connections, accounts, and transactions.


    Design goals:

    - Flat records with minimal nesting.

    - Clear, bank-centric naming.

    - One canonical endpoint per resource.

    - Sparse fieldsets via `fields=`.

    - Historical browsing via `GET /transactions`.

    - Incremental ETL via `GET /transactions/sync`.

    - Discover supported institutions via `GET /institutions`.

    - Model downstream client businesses via `/entities` and explicit `entityId`
    ownership.


    Authentication:

    - Opaque API keys passed as `Authorization: Bearer <key>`.

    - Key format: `way_<environment>_<key_id>_<secret>`.

    - Keys are organization-bound, environment-bound (`live` or `test`),
    scope-carrying, and expiring.

    - Managed via the Waycore Console.
  version: 0.5.0
servers:
  - url: https://api.waycore.com
security: []
paths:
  /v1/transactions/sync:
    get:
      tags:
        - transactions
      summary: Sync Transactions
      description: >-
        Incremental transaction changefeed for maintaining a current mirror, not
        an immutable history log. For a no-gap bootstrap, call this endpoint
        without a cursor and save `nextCursor`, then backfill with `GET
        /v1/transactions`, then poll from the saved cursor. Responses are
        ordered by the server's sync cursor ascending and act as a
        convergence-safe stream: reusing the same cursor later returns the
        then-current ordered suffix after that cursor, not a byte-for-byte
        replay of an earlier page. Persist `nextCursor` only after the full page
        has been durably applied. Clients should upsert both `added` and
        `modified`, delete on `removed`, and call again immediately with
        `nextCursor` while `hasMore` is true. Duplicates between the backfill
        and later sync calls are expected. Cursors are valid only for the same
        stream-defining filters, expire after 90 days, and return
        `invalid_cursor` for malformed or filter-mismatched cursors or
        `cursor_expired` when the client must rebootstrap. If rate limited,
        honor `Retry-After` when present and retry with the same cursor. Under
        the current product model, sync events are transaction-write driven:
        `removed` is emitted for transaction deletions, and account visibility
        changes without transaction mutations are intentionally out of scope.
      operationId: sync_transactions_v1_transactions_sync_get
      parameters:
        - name: cursor
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              Opaque cursor returned by a previous `/v1/transactions/sync`
              response. Omit on the first call to initialise the stream head for
              no-gap bootstrap. Cursors are valid only for the same
              stream-defining filters (`accountId`, `connectionId`, `entityId`),
              expire after 90 days, and act as lower bounds in the ordered sync
              stream. `invalid_cursor` means malformed or filter-mismatched.
              `cursor_expired` means the client must rebootstrap.
            title: Cursor
          description: >-
            Opaque cursor returned by a previous `/v1/transactions/sync`
            response. Omit on the first call to initialise the stream head for
            no-gap bootstrap. Cursors are valid only for the same
            stream-defining filters (`accountId`, `connectionId`, `entityId`),
            expire after 90 days, and act as lower bounds in the ordered sync
            stream. `invalid_cursor` means malformed or filter-mismatched.
            `cursor_expired` means the client must rebootstrap.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            maximum: 500
            minimum: 1
            description: Maximum number of change events to return.
            default: 100
            title: Limit
          description: Maximum number of change events to return.
        - name: fields
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              Comma-separated sparse fieldset applied to embedded `transaction`
              objects. The server always includes required identifiers. This
              does not change stream membership and is not part of cursor
              compatibility.
            title: Fields
          description: >-
            Comma-separated sparse fieldset applied to embedded `transaction`
            objects. The server always includes required identifiers. This does
            not change stream membership and is not part of cursor
            compatibility.
        - name: accountId
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: >-
              Limit the stream to a single account. This is a stream-defining
              filter and must stay consistent for the lifetime of the cursor
              stream.
            title: Accountid
          description: >-
            Limit the stream to a single account. This is a stream-defining
            filter and must stay consistent for the lifetime of the cursor
            stream.
        - name: connectionId
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: >-
              Limit the stream to a single connection. This is a stream-defining
              filter and must stay consistent for the lifetime of the cursor
              stream.
            title: Connectionid
          description: >-
            Limit the stream to a single connection. This is a stream-defining
            filter and must stay consistent for the lifetime of the cursor
            stream.
        - name: entityId
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: >-
              Limit the stream to a single entity. This is a stream-defining
              filter and must stay consistent for the lifetime of the cursor
              stream.
            title: Entityid
          description: >-
            Limit the stream to a single entity. This is a stream-defining
            filter and must stay consistent for the lifetime of the cursor
            stream.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionsSyncResponse'
                type: object
                additionalProperties: true
                title: Response Sync Transactions V1 Transactions Sync Get
        '400':
          description: >-
            Bad Request. `type` may be `invalid_request` for malformed query
            parameters or validation failures, `invalid_fields` when `fields`
            contains unknown names, `invalid_cursor` when a sync cursor is
            malformed or does not match the supplied stream-defining filters, or
            `cursor_expired` when the client must rebootstrap.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicErrorResponse'
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicErrorResponse'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicErrorResponse'
          description: Forbidden
        '429':
          description: >-
            Too Many Requests. Retry after the number of seconds in
            `Retry-After` when present, then retry the same request with the
            same cursor.
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying, when rate limiting
                provides a specific backoff.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicErrorResponse'
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicErrorResponse'
          description: Internal Server Error
      security:
        - apiKeyBearer:
            - transactions:read
components:
  schemas:
    TransactionsSyncResponse:
      properties:
        events:
          items:
            anyOf:
              - $ref: '#/components/schemas/TransactionUpsertEvent'
              - $ref: '#/components/schemas/TransactionRemovedEvent'
          type: array
          title: Events
          description: >-
            Mirror-maintenance change events ordered by the server's sync cursor
            ascending. They are designed to keep a current mirror correct, not
            to provide an immutable replay log. Reusing the same cursor later
            returns the then-current ordered suffix after that cursor rather
            than a byte-for-byte replay of an earlier page.
        nextCursor:
          type: string
          title: Nextcursor
          description: >-
            Opaque cursor to use on the next sync call. Persist it only after
            the full page has been durably applied.
        hasMore:
          type: boolean
          title: Hasmore
        meta:
          $ref: '#/components/schemas/app__transactions__public__models__Meta'
      type: object
      required:
        - events
        - nextCursor
        - hasMore
        - meta
      title: TransactionsSyncResponse
    PublicErrorResponse:
      properties:
        type:
          title: Type
          type: string
        message:
          type: string
          title: Message
        requestId:
          anyOf:
            - type: string
            - type: 'null'
          title: Requestid
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
      type: object
      required:
        - type
        - message
      title: PublicErrorResponse
    TransactionUpsertEvent:
      properties:
        eventId:
          type: string
          title: Eventid
          description: >-
            Opaque identifier for this change event, stable across retries of
            the same event.
        eventAt:
          type: string
          format: date-time
          title: Eventat
          description: When this change event was recorded in Waycore's public sync stream.
        type:
          type: string
          enum:
            - added
            - modified
          title: Type
          description: >-
            Change type. Treat both values as idempotent upserts keyed by
            `transaction.id`.
        transaction:
          $ref: '#/components/schemas/Transaction'
      type: object
      required:
        - eventId
        - eventAt
        - type
        - transaction
      title: TransactionUpsertEvent
    TransactionRemovedEvent:
      properties:
        eventId:
          type: string
          title: Eventid
          description: >-
            Opaque identifier for this change event, stable across retries of
            the same event.
        eventAt:
          type: string
          format: date-time
          title: Eventat
          description: When this change event was recorded in Waycore's public sync stream.
        type:
          type: string
          const: removed
          title: Type
          description: Change type. Delete this transaction from the current mirror.
        id:
          type: string
          format: uuid
          title: Id
          description: Identifier of the transaction that should be removed.
      type: object
      required:
        - eventId
        - eventAt
        - type
        - id
      title: TransactionRemovedEvent
    app__transactions__public__models__Meta:
      properties:
        requestId:
          type: string
          title: Requestid
      type: object
      required:
        - requestId
      title: Meta
    Transaction:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        connectionId:
          type: string
          format: uuid
          title: Connectionid
        accountId:
          type: string
          format: uuid
          title: Accountid
        status:
          $ref: '#/components/schemas/TransactionStatus'
          description: >-
            Transaction lifecycle status. Current implementation emits only
            `pending` and `posted`; other values are reserved for future use.
        postedDate:
          anyOf:
            - type: string
              format: date
            - type: 'null'
          title: Posteddate
        updatedAt:
          type: string
          format: date-time
          title: Updatedat
          description: >-
            When the serialized public transaction representation last changed.
            It advances when a change would alter a field currently exposed by
            this API. Internal-only changes and changes to data not currently
            surfaced here do not change `updatedAt`.
        amount:
          type: string
          title: Amount
        currency:
          title: Currency
          type: string
        entryType:
          $ref: '#/components/schemas/EntryType'
        description:
          type: string
          title: Description
        rawDescription:
          anyOf:
            - type: string
            - type: 'null'
          title: Rawdescription
        customerReference:
          anyOf:
            - type: string
            - type: 'null'
          title: Customerreference
        bankReference:
          anyOf:
            - type: string
            - type: 'null'
          title: Bankreference
        rail:
          $ref: '#/components/schemas/PaymentRail'
        baiCode:
          anyOf:
            - type: string
            - type: 'null'
          title: Baicode
        category:
          anyOf:
            - type: string
            - type: 'null'
          title: Category
        subcategory:
          anyOf:
            - type: string
            - type: 'null'
          title: Subcategory
        mcc:
          anyOf:
            - type: string
            - type: 'null'
          title: Mcc
        merchantName:
          anyOf:
            - type: string
            - type: 'null'
          title: Merchantname
        counterpartyName:
          anyOf:
            - type: string
            - type: 'null'
          title: Counterpartyname
        counterpartyAccountMasked:
          anyOf:
            - type: string
            - type: 'null'
          title: Counterpartyaccountmasked
      type: object
      required:
        - id
        - connectionId
        - accountId
        - status
        - postedDate
        - updatedAt
        - amount
        - currency
        - entryType
        - description
        - rail
      title: Transaction
    TransactionStatus:
      type: string
      enum:
        - pending
        - posted
        - reversed
        - cancelled
        - unknown
      title: TransactionStatus
    EntryType:
      type: string
      enum:
        - credit
        - debit
      title: EntryType
    PaymentRail:
      type: string
      enum:
        - internalTransfer
        - card
        - ach
        - pix
        - caEft
        - auNpp
        - auBecsDirectEntry
        - auRtgs
        - sepaCredit
        - sepaDebit
        - bacsDirectDebit
        - wire
        - swift
        - fasterPayments
        - check
        - cash
        - crypto
        - other
        - unknown
      title: PaymentRail
  securitySchemes:
    apiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: way_<environment>_<key_id>_<secret>
      description: >-
        Opaque API key passed as `Authorization: Bearer <key>`. Keys are
        organization-bound, environment-bound (`live` or `test`),
        scope-carrying, and expiring. Create and manage keys via the console.

````