# Pagination Guide The Bermuda Commercial Bank Open Banking API uses **cursor-based pagination** with server-side result-set management for efficient handling of large datasets. ## ๐Ÿ”ข Pagination Parameters ### Request Parameters *(query string)* | Parameter | Type | Description | | --- | --- | --- | | `pageStart` | integer | The record (page number) from which the response should be displayed (default: 1) | | `pageSize` | integer | The total number of records per page (max: 1000, default 100 if pageSize omitted) | | `pageToken` | string | Opaque cursor ID received from the previous response โ€“ required for subsequent requests | ### Response Parameters *(returned in `meta.pagination`)* | Parameter | Type | Description | | --- | --- | --- | | `page_size` | integer | The total number of records per page (echoed from request or default) | | `page_start` | integer | The record from which the current response is displayed | | `total_size` | integer | The total number of records present in the complete result set | | `page_token` | string | Opaque cursor ID for this result set โ€“ use in subsequent requests | > โ„น๏ธ **Naming convention difference** *Request* parameters are **camelCase** (`pageStart`, `pageSize`, `pageToken`). *Response* properties are **snake_case** (`page_start`, `page_size`, `page_token`, `total_size`). ## ๐Ÿงฎ Pagination Mathematics Given a dataset with `total_size` records and `page_size` records per page: - **Total Pages**: `ceil(total_size / page_size)` - **Records on Last Page**: `total_size % page_size` (or `page_size` if evenly divisible) ### Example Calculation If you have **345 total records** with **page_size = 100**: - **Page 1**: Records 1-100 (100 records) - **Page 2**: Records 101-200 (100 records) - **Page 3**: Records 201-300 (100 records) - **Page 4**: Records 301-345 (45 records) - **Total Pages**: `ceil(345 / 100) = 4 pages` ## โš™๏ธ How Pagination Works Internally ### Server-Side Cursor Management 1. **First Request** โ€“ The server creates a cursor for the result set based on: โ€ข Query parameters (filters, sorting, etc.) โ€ข Business logic and security rules โ€ข Current data state at request time ๐Ÿ”นNote: Sorting is not yet supported 2. **Cursor Token** โ€“ The server returns an opaque cursor ID in `page_token` โ€ข Example: `"202503190209330227.01,100"` โ€ข Encodes pagination context (including `page_size`) โ€ข Unique to this specific query run 3. **Subsequent Requests** โ€“ Reuse the same cursor for pages 2, 3, โ€ฆ โ€ข Token remains valid until it expires or query parameters change โ€ข Ensures a consistent view across the entire pagination sequence ### Important Notes - **Page Token embeds Page Size** โ€“ The `page_token` contains the original `page_size`, so *do not* send `pageSize` again after the first request. - **Cursor Expiration** โ€“ Cursors may expire after a period of inactivity; handle `4xx` errors by restarting pagination. - **Changing Parameters** โ€“ Any change to filtering/sorting invalidates the existing cursor; start a new sequence. ## ๐Ÿ‘จโ€๐Ÿ’ป Client Usage Guide ### Step 1 โ€“ First Request Send the initial call with an optional `pageSize` parameter: ```http GET /api/accounts/1000012345/payments?pageSize=100 ``` **Sample Response** ```json { "meta": { "pagination": { "page_start": 1, "page_token": "202503190209330227.01,100", "total_size": 345, "page_size": 100 } }, "data": [ // First 100 records ] } ``` ### Step 2 โ€“ Calculate Total Pages ```javascript const totalPages = Math.ceil(totalSize / pageSize); // Example: Math.ceil(345 / 100) = 4 ``` ### Step 3 โ€“ Subsequent Requests Use the `pageToken` from the previous response together with the desired `pageStart` value: ```http GET /api/accounts/1000012345/payments?pageToken=202503190209330227.01,100&pageStart=2 ``` **Response** ```json { "meta": { "pagination": { "page_start": 2, "page_token": "202503190209330227.01,100", "total_size": 345, "page_size": 100 } }, "data": [ // Records 101-200 ] } ``` ### Step 4 โ€“ Continue Until Last Page Repeat Step 3 with increasing `pageStart` values (`3`, `4`, โ€ฆ) until you reach `totalPages`. ## ๐Ÿ“‹ Best Practices ### โœ… Do - **Store the `pageToken`** from the first response and reuse it for all subsequent requests. - **Calculate total pages** using `ceil(total_size / page_size)` to know when to stop. - **Handle the last page** which may contain fewer records than `page_size`. - **Specify `pageSize` only in the first request** โ€“ it's embedded in the token thereafter. ### โŒ Don't - **Don't send `pageSize` in subsequent requests** โ€“ the token already contains it. - **Don't reuse tokens across different query parameters** โ€“ each unique query gets its own cursor. - **Don't assume cursors last forever** โ€“ handle expired token errors by restarting the sequence. ## ๐Ÿšจ Error Handling If a cursor expires or becomes invalid you will receive an error response. In that case: 1. Start over with a new first request (without `pageToken`). 2. The server will create a new cursor and return a fresh `pageToken`.