> ## Documentation Index
> Fetch the complete documentation index at: https://docs.terrapinfinance.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Page through search results with cursors.

The search endpoints (`bond_search`, `muni_search`, `agency_search` and `securities_search`) return results one page at a time. Each response includes a `next_cursor`. Send it back as `cursor` to get the next page.

## Paging through results

1. Search as usual. `limit` sets the page size:

```json theme={"theme":{"light":"catppuccin-latte","dark":"github-dark-high-contrast"}}
{ "states": ["CA"], "sort": ["-maturity_date"], "limit": 1000 }
```

The response contains the first page, the `total` number of matching bonds, and the cursor for the next page:

```json theme={"theme":{"light":"catppuccin-latte","dark":"github-dark-high-contrast"}}
{ "data": ["…1,000 bonds…"], "total": 148672, "next_cursor": "QTEyOEdDTQ.ZpXo…" }
```

2. Send the same request again with `cursor` added:

```json theme={"theme":{"light":"catppuccin-latte","dark":"github-dark-high-contrast"}}
{ "states": ["CA"], "sort": ["-maturity_date"], "limit": 1000, "cursor": "QTEyOEdDTQ.ZpXo…" }
```

3. Repeat until `next_cursor` is `null`.

Only `cursor` and `limit` may change between pages. If a filter or `sort` changes, the cursor is rejected. Cursors don't expire, but an API update can occasionally invalidate them.

## Order

Results are ordered by `sort`, then by ISIN (and asset class on `securities_search`). Each page starts right after the last bond of the previous page, so no bond is skipped or repeated.

* Bonds with no value for a sort field come last, whether it sorts ascending or descending.
* A `muni_search` by `issuer_name` lists the bonds of the closest matching issuers first. Issuers are matched on the first page, and later pages reuse that match.

Pages read live data, which changes during the day. A bond added or updated while you page only shows up if it sorts after your current page. To download a whole universe, keep the default order (by ISIN): ISINs never change, so no bond can move between pages.

## Total

`total` is the number of bonds matching the filters. It is counted on the first page, and later pages repeat it. A `limit` of 0 returns only `total`, with `next_cursor` set to `null`.

## Errors

An unusable `cursor` returns `422 Unprocessable Entity`. The [error](/errors) points to `/cursor` (or `/offset`), and its `detail` gives the cause:

| Cause | What to do |
| - | - |
| The cursor belongs to a different search: a filter, `sort`, the endpoint or your tier changed. | Change only `cursor` and `limit` between pages, or leave out `cursor` to start over. |
| The request has both `cursor` and a non-zero `offset`. | Leave out `offset`. |
| The cursor is from an earlier API version. | Leave out `cursor` to start over. |
| The cursor is invalid. | Send `next_cursor` exactly as received, or leave out `cursor` to start over. |

## Moving from offset

`offset` is deprecated and will be removed on April 2, 2027. It gets slower the further you page, because each request skips every result before it. A cursor starts right after the previous page, so later pages are no slower than the first.

Responses to `offset` requests carry `Deprecation`, `Sunset` (the removal date) and `Link` (this page) headers. They also include a `next_cursor`, so you can switch midway: send it as `cursor` and leave out `offset` from then on.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.