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

# Pagination

> Page through results with cursor-based pagination.

All list endpoints return paginated results using cursor-based pagination. This approach is stable even when items are added or removed between requests.

## How it works

Every list response includes pagination metadata:

```json theme={null}
{
  "object": "list",
  "results": [...],
  "has_more": true,
  "next_cursor": "eyJpZCI6MTIzNH0="
}
```

| Field         | Type           | Description                                                                        |
| ------------- | -------------- | ---------------------------------------------------------------------------------- |
| `results`     | array          | The page of results.                                                               |
| `has_more`    | boolean        | `true` if there are more results after this page.                                  |
| `next_cursor` | string \| null | Pass this as `cursor` to get the next page. `null` when there are no more results. |

## Paginating through results

To get all items, keep requesting with the `cursor` parameter until `has_more` is `false`:

```bash theme={null}
# First page
curl "https://api.getmatter.com/public/v1/items?limit=50" \
  -H "Authorization: Bearer $MATTER_TOKEN"

# Next page (use next_cursor from previous response)
curl "https://api.getmatter.com/public/v1/items?limit=50&cursor=eyJpZCI6MTIzNH0=" \
  -H "Authorization: Bearer $MATTER_TOKEN"
```

```python Python example theme={null}
import requests

url = "https://api.getmatter.com/public/v1/items"
headers = {"Authorization": f"Bearer {token}"}
params = {"limit": 50}
all_items = []

while True:
    response = requests.get(url, headers=headers, params=params).json()
    all_items.extend(response["results"])

    if not response["has_more"]:
        break
    params["cursor"] = response["next_cursor"]

print(f"Fetched {len(all_items)} items")
```

## Page size

Control page size with the `limit` parameter:

| Parameter | Default | Min | Max |
| --------- | ------- | --- | --- |
| `limit`   | 25      | 1   | 100 |

## Incremental sync

Use `updated_since` to fetch only items that changed after a given timestamp. This is the most efficient way to keep a local copy of your library in sync.

```bash theme={null}
# Get everything changed since your last sync
curl "https://api.getmatter.com/public/v1/items?updated_since=2026-03-29T00:00:00Z" \
  -H "Authorization: Bearer $MATTER_TOKEN"
```

An item's `updated_at` reflects **any** change to the item or its associated data — status changes, reading progress, favorites, tag additions/removals, new annotations, and content re-extraction all advance the timestamp. For inbox items that have never been interacted with, `updated_at` is the time the item appeared in your inbox.

The `updated_since` parameter filters by `updated_at` and works with all other filters (`status`, `tag`, etc.). Combine it with pagination to sync large deltas:

```python Python example theme={null}
from datetime import datetime

last_sync = "2026-03-29T00:00:00Z"
params = {"updated_since": last_sync, "limit": 100}
changed_items = []

while True:
    response = requests.get(url, headers=headers, params=params).json()
    changed_items.extend(response["results"])
    if not response["has_more"]:
        break
    params["cursor"] = response["next_cursor"]

# Save the current time as your new sync checkpoint
new_sync = datetime.utcnow().isoformat() + "Z"
```

<Tip>
  Store the timestamp *before* you start syncing. If the sync fails partway through, you can retry from the same checkpoint without missing changes.
</Tip>

## Multi-value filters

Several filter parameters accept comma-separated values to match any of the given options:

```bash theme={null}
# Items in queue OR archive
curl "https://api.getmatter.com/public/v1/items?status=queue,archive" \
  -H "Authorization: Bearer $MATTER_TOKEN"

# Articles OR podcasts
curl "https://api.getmatter.com/public/v1/items?content_type=article,podcast" \
  -H "Authorization: Bearer $MATTER_TOKEN"

# Items with any of these tags
curl "https://api.getmatter.com/public/v1/items?tag=tag_n5j2x,tag_k3m9p" \
  -H "Authorization: Bearer $MATTER_TOKEN"
```

Multi-value filters use **OR** logic — an item matches if it has any of the specified values.

## Ordering

By default, items are ordered by `updated_at` descending (most recently changed first). This is optimized for incremental sync workflows.

You can also request **position ordering** to get items in the same order shown in the app:

```bash theme={null}
# Queue in manual order (as arranged in the app)
curl "https://api.getmatter.com/public/v1/items?status=queue&order=library_position" \
  -H "Authorization: Bearer $MATTER_TOKEN"

# All library items (queue + archive) in manual order
curl "https://api.getmatter.com/public/v1/items?order=library_position" \
  -H "Authorization: Bearer $MATTER_TOKEN"

# Inbox in feed order
curl "https://api.getmatter.com/public/v1/items?order=inbox_position" \
  -H "Authorization: Bearer $MATTER_TOKEN"
```

| `order` value      | Description                                                                                  |
| ------------------ | -------------------------------------------------------------------------------------------- |
| `updated`          | Sort by last-updated timestamp (default). Works with all status filters and `updated_since`. |
| `library_position` | Sort by library position (manual queue ordering). Items without a library entry sort last.   |
| `inbox_position`   | Sort by inbox feed position (newest first). Items not in the inbox sort last.                |

No status filter is required for position orderings — items without a position sort last.

### Position fields and incremental sync

Every item includes `library_position` and `inbox_position` fields, regardless of the `order` parameter used. This means you can use `order=updated` with `updated_since` for efficient incremental sync, and still use the position fields to sort items locally into app order:

```python theme={null}
# Incremental sync — fetches only changed items
params = {"updated_since": last_sync, "limit": 100}
changed = fetch_all_pages(params)

# Update local cache with changed items
for item in changed:
    local_db[item["id"]] = item

# Display in app order using position fields
queue_items = sorted(
    [i for i in local_db.values() if i["status"] == "queue"],
    key=lambda i: i["library_position"] or 0,
    reverse=True,
)
```

<Note>
  Annotations, tags, and other list endpoints always use `updated_at` ordering.
</Note>
