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

# Pagination

> How to walk through long lists of posts, media, and other resources.

List endpoints return a paginated response. Pagination is offset-based and predictable.

## Request

Pass `page` (1-indexed) and optionally `per_page` (defaults to 25, capped per endpoint):

```bash theme={null}
curl "https://api.publishbuddy.com/v1/workspaces/$WORKSPACE_ID/posts?page=3&per_page=50" \
  -H "Authorization: Bearer $PUBLISHBUDDY_TOKEN"
```

## Response shape

Paginated responses include a `meta` object alongside `data`:

```json theme={null}
{
  "data": [ /* up to per_page items */ ],
  "meta": {
    "current_page": 3,
    "from": 101,
    "to": 150,
    "per_page": 50,
    "last_page": 12,
    "total": 587,
    "path": "https://api.publishbuddy.com/v1/workspaces/xxx/posts"
  },
  "links": {
    "first": "https://api.publishbuddy.com/v1/workspaces/xxx/posts?page=1",
    "last":  "https://api.publishbuddy.com/v1/workspaces/xxx/posts?page=12",
    "prev":  "https://api.publishbuddy.com/v1/workspaces/xxx/posts?page=2",
    "next":  "https://api.publishbuddy.com/v1/workspaces/xxx/posts?page=4"
  }
}
```

* Stop iterating when `meta.current_page === meta.last_page` (or when `links.next` is `null`).
* `meta.total` is the total count across all pages — useful for "X of Y" UI counters.

## Iterating in code

<CodeGroup>
  ```javascript Node.js theme={null}
  async function* paginate(url, token) {
    let page = 1;
    while (true) {
      const res = await fetch(`${url}?page=${page}&per_page=100`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      const body = await res.json();
      for (const item of body.data) yield item;
      if (page >= body.meta.last_page) return;
      page += 1;
    }
  }

  for await (const post of paginate(
    `https://api.publishbuddy.com/v1/workspaces/${workspaceId}/posts`,
    token
  )) {
    // ...
  }
  ```

  ```python Python theme={null}
  def paginate(url, token, params=None):
      page = 1
      while True:
          res = requests.get(
              url,
              headers={'Authorization': f'Bearer {token}'},
              params={**(params or {}), 'page': page, 'per_page': 100},
          )
          res.raise_for_status()
          body = res.json()
          yield from body['data']
          if page >= body['meta']['last_page']:
              return
          page += 1
  ```
</CodeGroup>

## Sensible per\_page values

| Use case                    | Recommended `per_page`               |
| --------------------------- | ------------------------------------ |
| Interactive UI (table view) | 25 — fast and matches the dashboard. |
| Sync / export job           | 100 — fewer round-trips.             |

Don't go above 100 — it's the hard cap on most list endpoints, and larger pages don't speed things up because the underlying database queries are tuned for that size.

## Stable ordering

List endpoints return results in a deterministic order (most recently updated first, or most recently published — endpoint-dependent). Pagination is stable as long as no new items are inserted at the top mid-iteration. For long-running exports, consider also filtering by `from` / `to` date range to keep the result set stable.
