Reference
Pagination
The pagination envelope every list response carries, and how to walk it: auto-iterate, one page at a time, collect everything, or by hand.
Every list endpoint returns one page of items plus the metadata to find the next. The SDKs will walk it for you, hand you one page at a time, or stay out of the way while you drive page and page_size yourself.
| Approach | Reach for it when |
|---|---|
| Auto-pagination | You want every result and would rather not think about pages |
| Collect all items | You want every result in one list and the result set is small |
| Page-level iteration | You process results a batch at a time |
| Manual pagination | You decide which page is fetched and when |
Response format
Paginated endpoints are offset-based. You ask for a page number and a page size, and the response reports where that page sits in the full result set.
page=1.{
"success": true,
"data": {
"items": [],
"pagination": {
"total_items": 142,
"total_pages": 15,
"current_page": 1,
"page_size": 10,
"has_next": true,
"has_previous": false
}
},
"timestamp": "2025-10-15T10:00:00Z"
}success, data and timestamp are the standard envelope on every LevelFour response, described in the API reference.
Auto-pagination
The SDK fetches the next page when you reach the end of the current one, so your loop reads as though the whole result set were already in memory.
for rec in client.recommendations.list(page_size=50):
print(rec.recommendation_id)Async (Python)
The async client takes the same call. Await it once, then iterate with async for.
async for rec in await async_client.recommendations.list(page_size=50):
print(rec.recommendation_id)Collect all items
Fetch every page and return all items as a single collection.
all_recs = list(client.recommendations.list(page_size=100))Page-level iteration
Each turn of the loop hands you a whole page rather than a single item.
for page in client.recommendations.list(page_size=50).iter_pages():
print(f"Processing {len(page.items)} items")
for item in page.items:
process(item)levelfour.ErrNoPages from GetNextPage. Match it with errors.Is before treating the error as a failure.Async pages (Python)
iter_pages() works the same way on the async client.
async for page in (await async_client.recommendations.list(page_size=50)).iter_pages():
print(f"Processing {len(page.items)} items")Manual pagination
Pass page and page_size directly and handle navigation yourself.
page = client.recommendations.list(page=1, page_size=50)
while page:
for item in page.items:
process(item)
page = page.next_page()Paginated endpoints
Every method below returns a paginated result. The resource pages carry each one's parameters and response shape.
| What it lists | Python | TypeScript | Go |
|---|---|---|---|
| Recommendations | recommendations.list() | recommendations.list() | Recommendations.List() |
| Recommendations for one provider | recommendations.list_by_provider() | recommendations.listByProvider() | Recommendations.ListByProvider() |
| Potential savings for one provider | recommendations.list_provider_potential_savings() | recommendations.listProviderPotentialSavings() | Recommendations.ListProviderPotentialSavings() |
| Realized savings | recommendations.audit.list() | recommendations.audit.list() | Recommendations.Audit.List() |
| Realized savings for one provider | recommendations.audit.list_by_provider() | recommendations.audit.listByProvider() | Recommendations.Audit.ListByProvider() |
| Cost breakdown | costs.list() | costs.list() | Costs.List() |
| Cost breakdown for one provider | costs.list_by_provider() | costs.listByProvider() | Costs.ListByProvider() |
providers namespace behind these. client.providers lists your connected providers and nothing else. Everything scoped to a single provider lives on recommendations or costs and takes a provider_id.Defaults
These are the values a request falls back to when you leave the parameter out. page is always 1.
The page size is not the same everywhere. The two savings lists and the recommendations list are sized for scanning a backlog; the breakdowns return one row per resource and are capped tighter.
| Endpoint | page_size default | Maximum |
|---|---|---|
recommendations.list() | 20 | 200 |
recommendations.list_by_provider() | 20 | 200 |
recommendations.list_provider_potential_savings() | 20 | 200 |
recommendations.audit.list() | 10 | 100 |
recommendations.audit.list_by_provider() | 10 | 100 |
costs.list() | 10 | 100 |
costs.list_by_provider() | 10 | 100 |
422, not a silent clamp. The auto-paginating iterators above sidestep the whole question, because they carry the page size the server gave them.Next
- Error handling maps each status code to its typed class and lists what the SDKs retry before you see the failure
- Resources documents every method, paginated or not, in all three SDKs
- Python, TypeScript and Go name the pager type each client returns