Skip to content
FeedbackDashboard
Getting started
Configure SDKs

Pagination

Configure pagination helpers and auto-iterators for your SDK. Support cursor, offset, and page number pagination schemes with automatic next-page fetching.

[reference]

Configuring pagination with Stainless SDKs generates a helper to fetch the next page and an auto-iterator to easily loop through items in your API. The helper makes it easy to manually paginate when needed and the auto-iterator makes consuming a list as natural as a for loop, with the iterator automatically fetching the next page when needed:

const iter: OffsetPage<Account> = await client.accounts.list()
for await (const account in iter) {
if (account.name === 'Michael') {
console.log(account.id)
}
}

Stainless will only use recognized pagination schemes when generating SDKs. If a method isn’t being paginated, make sure that it has the required schema for the request and response, and that it matches the schema in the OpenAPI spec. If a method is improperly paginated, make sure that the x-stainless-pagination-property is set correctly.

The request and response must include all parameters and fields needed for pagination. The request might have a limit, offset, page number, page size, or start ID; the response might have the data, a link to the next page, or the next start ID.

You can also include parameters that aren’t strictly necessary for pagination to work. For example, it might be appropriate to add a request parameter like sort_by, which might be an enum of the ways you can sort across your API.

Here’s an example of a pagination scheme Stainless recognizes:

stainless.yml
pagination:
- # Name for the pagination scheme.
# Stainless will use this name when generating code for pagination helpers.
name: cursor_page
# Type of pagination your API uses, used to set logic for fetching each page.
# For the list of allowed types, see the "Pagination Type" section below.
type: cursor_id
request:
# Specifies that paginated endpoints take a `starting_after` query param,
# which pagination helpers pass cursor IDs to.
starting_after: # This param name is the one your API uses.
type: string
x-stainless-pagination-property: # Defines the purpose of the param.
purpose: next_cursor_id_param
response:
# Specifies that paginated responses have a `data` field
# containing the contents of the requested page.
data:
type: array
items:
type: unknown
x-stainless-pagination-property:
purpose: items
# Specifies that responses have a `next_cursor` field,
# which pagination helpers will take the next cursor ID from.
next_cursor:
type: string
x-stainless-pagination-property:
purpose: next_cursor_field
# Optional. Specifies where pagination parameters are located.
# Can be `query` (default) or `body`.
param_location: query

The first step in configuring pagination is to define the type of pagination your API is using. The types of pagination Stainless supports are:

  • cursor: A pagination scheme that uses a cursor (a string or a number to indicate the element to start from) to paginate through a list of items.
  • cursor_id: Similar to cursor pagination, but the cursor comes from an id property of the response items.
  • cursor_url: A pagination scheme that simply returns a URL to fetch from to retrieve the next page of results.
  • offset: A simple pagination scheme that uses an offset (the number of entries to skip) and limit (number of elements to fetch) to paginate through a list of items.
  • page_number: Similar to offset pagination, but instead of an offset, which indexes on the items, page_number indexes on chunks of elements to skip.
Cursor Pagination
pagination:
- name: my_cursor_page
type: cursor
request:
next:
type: string
x-stainless-pagination-property:
purpose: next_cursor_param
limit:
type: integer
response:
my_data:
type: array
items:
type: object
next:
type: string
x-stainless-pagination-property:
purpose: next_cursor_field
Example OpenAPI Specification
openapi: 3.1.0
paths:
/accounts:
get:
parameters:
- name: next
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
responses:
'200':
description: 'success!'
content:
application/json:
schema:
type: object
properties:
my_data:
type: array
items:
type: object
next:
type: string
Cursor ID Pagination
pagination:
- name: my_cursor_id_page
type: cursor_id
request:
starting_after:
type: string
x-stainless-pagination-property:
purpose: next_cursor_id_param
ending_before:
type: string
x-stainless-pagination-property:
purpose: previous_cursor_id_param
limit:
type: integer
response:
my_data:
type: array
items:
type: object
properties:
id:
type: string
x-stainless-pagination-property:
purpose: cursor_item_id
required:
- id
Example OpenAPI Specification
openapi: 3.1.0
paths:
/accounts:
get:
parameters:
- name: starting_after
in: query
schema:
type: string
- name: ending_before
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
responses:
'200':
description: 'success!'
content:
application/json:
schema:
type: object
properties:
my_data:
type: array
items:
type: object
properties:
id:
type: string
Cursor URL Pagination
pagination:
- name: cursor_url_page
type: cursor_url
request:
page_size:
type: integer
response:
data:
type: array
x-stainless-pagination-property:
purpose: items
next:
type: string
x-stainless-pagination-property:
purpose: cursor_url_field
from_header: Link
Example OpenAPI Specification
openapi: 3.1.0
paths:
/paginated/cursor_url:
get:
description: Test case for cursor_url pagination
parameters:
- name: page_size
in: query
schema:
type: integer
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/MyModel'
next:
type: string
format: uri
description: The URL for the next page
required:
- data
- next_page
Offset Pagination
pagination:
- name: my_offset_page
type: offset
request:
my_offset:
type: integer
description: The number of elements to skip.
# this tells us to modify this param when getting the next page
x-stainless-pagination-property:
purpose: offset_count_param
my_limit:
type: integer
description: The maximum number of elements to fetch.
response:
my_data:
type: array
items:
type: object
my_total:
type: integer
x-stainless-pagination-property:
# total number of elements in the list
purpose: offset_total_count_field
my_count:
type: integer
x-stainless-pagination-property:
# where to start the next page
purpose: offset_count_start_field
Example OpenAPI Specification
openapi: 3.1.0
paths:
/accounts:
get:
parameters:
- name: my_offset
in: query
schema:
type: integer
- name: my_limit
in: query
schema:
type: integer
responses:
'200':
content:
application/json:
schema:
type: object
properties:
my_data:
type: array
items:
type: object
my_total:
type: integer
my_count:
type: integer
Page Number Pagination
pagination:
- name: my_page_number_page
type: page_number
request:
page:
type: integer
x-stainless-pagination-property:
purpose: page_number_param
page_size:
type: integer
response:
data:
type: array
items:
type: object
page:
type: integer
x-stainless-pagination-property:
purpose: current_page_number_field
last_page:
type: integer
x-stainless-pagination-property:
purpose: total_page_count_field
Example OpenAPI Specification
openapi: 3.1.0
paths:
/accounts:
get:
description: Example case for page_number pagination
parameters:
- name: page
in: query
schema:
type: integer
- name: page_size
in: query
schema:
type: integer
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/MyModel'
last_page:
type: integer
description: The last page number
page:
type: integer
description: The page number

By default, Stainless automatically enables pagination for methods whose names start with list_. For example, a method named list_accounts will automatically be paginated if it matches one of your configured pagination schemes.

stainless.yml
resources:
accounts:
methods:
list_accounts: get /accounts # Automatically paginated due to list_ prefix
list_transactions: get /transactions # Also automatically paginated

If you have a paginated method that doesn’t follow the list_ naming convention, you can explicitly enable pagination by setting paginated: true in the method configuration:

stainless.yml
resources:
accounts:
methods:
search: # Not using list_ prefix
endpoint: get /accounts/search
paginated: true # Explicitly enable pagination

When you have multiple pagination schemes configured, Stainless will automatically match each endpoint to the appropriate scheme based on the request parameters and response fields. If you need to explicitly specify which pagination scheme a method should use, you can provide the scheme name as a string:

stainless.yml
pagination:
- name: cursor_page
type: cursor
# ... scheme configuration
- name: offset_page
type: offset
# ... scheme configuration
resources:
accounts:
methods:
list_accounts:
endpoint: get /accounts
paginated: cursor_page # Use the cursor_page scheme specifically
list_transactions:
endpoint: get /transactions
paginated: offset_page # Use the offset_page scheme specifically

This is especially useful when:

  • Multiple pagination schemes could match an endpoint and you want to disambiguate
  • You want to ensure a method uses a specific pagination scheme and get an error if it doesn’t match
  • You have methods that don’t follow the list_ naming convention but are still paginated

The pagination section accepts multiple pagination schemes. We match each endpoint against the defined pagination schemes by making sure the relevant request parameters/response fields exist for that endpoint and have the correct type.

In cases where it’s ambiguous or you want to explicitly assert that a method matches a specific pagination scheme, you can provide paginated: <scheme_name> in the method configuration (e.g., paginated: my_offset_page), and the generator reports an error if it doesn’t match that specific page.

For more details on enabling pagination at the method level, see Enabling Pagination on Methods.

See the config reference for pagination for various examples and edge cases.

Retrieving pagination properties from headers

Section titled “Retrieving pagination properties from headers”

If your API returns pagination values in headers, you can use the from_header property to specify the header to read the value from.

pagination:
- name: page_cursor_from_headers
type: cursor
request: ...
response:
my_cursor:
type: string
nullable: true
x-stainless-pagination-property:
purpose: next_cursor_field
from_header: 'X-My-Cursor'

Retrieving pagination properties from nested items

Section titled “Retrieving pagination properties from nested items”

If your API returns pagination values nested within the response, you can configure Stainless to read them from the nested items.

Example response:

{
"data": {
"items": [{}, {}]
},
"pagination_object": {
"next_page": "next_page_cursor",
"previous_page": "previous_page_cursor"
}
}
pagination:
- name: page_cursor_nested_items
type: cursor_id
request: ...
response:
data:
type: object
properties:
items:
x-stainless-pagination-property:
purpose: items
type: array
items: {}
pagination_object:
type: object
properties:
next_page:
type: string
x-stainless-pagination-property:
purpose: next_cursor_id_param
previous_page:
type: string
x-stainless-pagination-property:
purpose: previous_cursor_id_param

You can use the is_top_level_array property to indicate that the response is a top-level array.

Example response:

[
{
"id": 1,
"name": "Alice"
},
{
"id": 2,
"name": "Bob"
}
]
pagination:
- name: top_level_array
type: offset
request: ...
response:
items:
type: array
items: {}
x-stainless-pagination-property:
is_top_level_array: true