Release candidate

This is v2.2-rc2 — a release candidate for the v2.2 standards, published for review and not yet ratified. It MUST NOT be used as the basis for a production implementation. For the current standards, switch to v2.1 using the version selector. See the v2.1 → v2.2-rc2 changelog for every change in this version.

LFI · Banking · Bank Data Sharing

Pagination 3 min read

Pagination for Bank Data Sharing endpoints is page-based on the LFI (Ozone Connect) side. The API Hub converts the LFI's page/meta response into the Links envelope returned to the TPP.

For the end-to-end picture — including how the Hub converts LFI meta into TPP Links — see Pagination — LFI meta to TPP Links.

01 Which endpoints require pagination

Required vs optional pagination

EndpointPagination
GET/accounts/{accountId}/transactionsRequired
GET/accounts/{accountId}/statementsRequired
GET/accountsOptional
GET/accounts/{accountId}/balancesOptional
GET/accounts/{accountId}/beneficiariesOptional
GET/accounts/{accountId}/direct-debitsOptional
GET/accounts/{accountId}/scheduled-paymentsOptional
GET/accounts/{accountId}/standing-ordersOptional
GET/accounts/{accountId}/productsOptional
GET/accounts/{accountId}/customerOptional

Transactions and statements span long history (at least two years) and routinely produce large result sets — pagination is required so responses remain bounded. For other list endpoints, LFIs MAY paginate where result sets warrant it, or return all matching records in a single response.

02 Request

page / page-size

The Hub sends page and page-size as query parameters on every paginated request:

ParameterTypeDefaultDescription
pageinteger11-indexed page number
page-sizeinteger100Number of records per page

The LFI MUST return the slice of the result set that corresponds to page and page-size. Three steps, in that order: filtering (e.g. fromBookingDateTime / toBookingDateTime for transactions) is applied first, the filtered result set is then ordered, and the page is cut from the ordered set last. See Ordering and stability for the order transactions and statements MUST use.

03 Response

meta — paginated, totalPages, totalRecords

The LFI indicates the pagination state in the response meta object:

FieldTypeDescription
paginatedbooleantrue if the response is paginated. false or omitted if the full result set is returned in a single response
totalPagesintegerThe total number of pages in the full result set, given the current page-size
totalRecordsintegerThe total number of records in the full result set across all pages

totalPages and totalRecords MUST reflect the filtered result set — not the whole table. If a transaction query filters by date range, totalRecords is the count of transactions in that range, and totalPages is ceil(totalRecords / page-size).

Example — transactions, page 2 of 12

Request:

requesthttp
GET /accounts/acc-001/transactions?fromBookingDateTime=2026-01-01T00:00:00Z&page=2&page-size=100

Response:

responsejson
{
  "data": [
    { "accountId": "acc-001", "transactionId": "txn-900234", "...": "..." }
  ],
  "meta": {
    "paginated": true,
    "totalPages": 12,
    "totalRecords": 1187
  }
}

The Hub uses totalPages to construct Links.First, Links.Prev, Links.Next, and Links.Last on the TPP-facing response, and surfaces totalPages in the TPP's Meta. See the Pagination KB article for the full conversion.

04 API Sequence Flow

Walking pages end-to-end

The diagram below traces a three-page transactions query between the TPP, Hub, and your Ozone Connect endpoint. The TPP makes a single unparameterised request and follows Links.Next on each response; the Hub translates each call into a page / page-size request sent to your Ozone Connect GET /accounts/{accountId}/transactions endpoint and converts your meta back into the TPP's Links envelope.

Sequence diagramPagination API FlowClick to expand
05 Empty result sets

Empty matches return 200, not 404

If filtering yields no records, return 200 with an empty data array and:

empty responsejson
{
  "data": [],
  "meta": {
    "paginated": true,
    "totalPages": 0,
    "totalRecords": 0
  }
}

Do not return 404 for an empty filtered result.

06 Ordering and stability

Newest first, applied before the page is cut

From v2.2 the order is specified rather than left to the LFI. Transactions and statements MUST be returned newest first:

EndpointOrder (MUST)Tiebreaker (SHOULD)
GET/accounts/{accountId}/transactionsbookingDateTime descendingtransactionId descending
GET/accounts/{accountId}/statementsOpeningDate descendingStatementId descending
Note the casing — statements are PascalCase

Transactions order on bookingDateTime and tiebreak on transactionId, matching the camelCase used across most of Ozone Connect. The statement fields are OpeningDate and StatementId — PascalCase, as they appear in the statement schema. OpeningDate is also not the same field as StatementDate, which the schema carries separately.

The date field is a MUST and the tiebreaker a SHOULD, but apply both — the tiebreaker is what makes the order stable rather than merely correct. Transactions routinely share a bookingDateTime, and OpeningDate is a date rather than a timestamp, so ties are common on both endpoints. Ordering on the date alone lets two tied records swap places between one page request and the next, which can return the same record on two pages and omit another entirely.

Order the result set before you cut the page

The ordering MUST be applied to the filtered result set beforepage and page-size are applied — that is where the page is cut. Page 1 then always contains the most recent records matching the request, and a record does not move between pages while a TPP is paging through a result set.

fromBookingDateTime / toBookingDateTime and fromStatementDate / toStatementDate filter the result set. They have no effect on the order of what remains.

There is no sort parameter on either endpoint — a TPP cannot request ascending order, so the order above is the only one your Ozone Connect GET /accounts/{accountId}/transactions and GET /accounts/{accountId}/statements endpoints ever need to produce. If new records arrive between page requests, the LFI SHOULD ensure the same record is not returned on two different pages of the same logical query.