*API REST › Guías*

# Paginación

> Las listas devuelven una página cada vez. Pide una página con `limit` y, mientras `pagination.hasMore` sea `true`, vuelve a llamar con el `nextCursor` que te dieron.

## El bucle

**El bucle de paginación**
- Tu sistema → API: GET /api/v1/orders?limit=50 limit vale 50 por defecto y 500 como máximo. Añade includeTotal=true para recibir pagination.total.
- API → Tu sistema: data y pagination { hasMore: true, nextCursor }
- Mientras hasMore sea true:
- Tu sistema → API: GET /api/v1/orders?limit=50&cursor=<nextCursor> El mismo limit y el mismo sort: el cursor está ligado a los dos. El cursor es opaco; no lo construyas.
- API → Tu sistema: Página siguiente
- hasMore: false: has leído todas las páginas.

1. **Pide la primera página** Envía la petición de lista con [`limit`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-limit): de 1 a 500, 50 por defecto. No envíes un cursor.
2. **Leer la página** Toma los registros de `data`. `pagination.hasMore` te indica si hay más resultados.
3. **Pide la siguiente** Mientras `hasMore` sea `true`, vuelve a llamar con [`cursor`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-cursor) igual a `pagination.nextCursor`, y con el mismo [`limit`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-limit) y los mismos filtros.
4. **Detener** En la última página `hasMore` es `false` y `nextCursor` es `null`.

*Leer todos los pedidos, una página cada vez*

**cURL**

```bash
# Needs curl and jq. Prints one order per line.
base="${FILMO_BASE_URL:-https://app.filmo.io}"
cursor=""
while :; do
  # Keep limit and sort identical on every page.
  set -- --data-urlencode "limit=100" --data-urlencode "sort=createdAt"
  [ -n "$cursor" ] && set -- "$@" --data-urlencode "cursor=$cursor"

  page="$(curl -sS --fail-with-body -G "$base/api/v1/orders" \
    -H "Authorization: Bearer $FILMO_API_KEY" "$@")" || { echo "$page" >&2; exit 1; }

  echo "$page" | jq -c '.data[]'
  cursor="$(echo "$page" | jq -r 'if .pagination.hasMore then .pagination.nextCursor else "" end')"
  [ -n "$cursor" ] || break
done
```

**Node**

```javascript
const base = process.env.FILMO_BASE_URL ?? "https://app.filmo.io";
const headers = { Authorization: `Bearer ${process.env.FILMO_API_KEY}` };

const orders = [];
let cursor = null;
do {
  const url = new URL("/api/v1/orders", base);
  url.searchParams.set("limit", "100"); // keep limit and sort identical on every page
  url.searchParams.set("sort", "createdAt");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, { headers });
  if (!res.ok) throw new Error(res.status + " " + (await res.text()));
  const page = await res.json();

  orders.push(...page.data);
  cursor = page.pagination.hasMore ? page.pagination.nextCursor : null;
} while (cursor);

console.log(orders.length + " orders");
```

**Python**

```python
import os
import requests

base = os.environ.get("FILMO_BASE_URL", "https://app.filmo.io")
headers = {"Authorization": f"Bearer {os.environ['FILMO_API_KEY']}"}

orders, cursor = [], None
while True:
    # Keep limit and sort identical on every page.
    params = {"limit": 100, "sort": "createdAt"}
    if cursor:
        params["cursor"] = cursor
    res = requests.get(base + "/api/v1/orders", headers=headers, params=params, timeout=30)
    res.raise_for_status()
    page = res.json()

    orders += page["data"]
    if not page["pagination"]["hasMore"]:
        break
    cursor = page["pagination"]["nextCursor"]

print(len(orders), "orders")
```

## El objeto de paginación

| Propiedad | Tipo | Significado |
| --- | --- | --- |
| `nextCursor` | string o null | Cursor opaco de la página siguiente. `null` cuando no hay más resultados. |
| `hasMore` | boolean | Si existen más resultados después de esta página. |
| `total` | integer | El número de resultados que coinciden con los filtros en todas las páginas. Solo está presente cuando la petición establece `includeTotal` en `true`. |

## Reglas

- Trata el cursor como opaco. No lo construyas, no lo interpretes ni lo guardes durante mucho tiempo; solo continúa el recorrido del que procede. Un cursor tiene como máximo 200 caracteres, y se rechaza uno que se haya alterado o que no coincida con el `limit` con el que se envía.
- Algunas listas no están paginadas: devuelven todo en una sola respuesta y no admiten `limit`, `cursor` ni `sort`. Son [`GET /api/v1/tags`](https://docs.filmo.io/es/rest-api/endpoint-reference/tags/list-tags), [`GET /api/v1/task-types`](https://docs.filmo.io/es/rest-api/endpoint-reference/task-types/list-task-types), [`GET /api/v1/crm/pipelines`](https://docs.filmo.io/es/rest-api/endpoint-reference/crm/list-pipelines), [`GET /api/v1/custom-fields`](https://docs.filmo.io/es/rest-api/endpoint-reference/custom-fields/list-custom-field-definitions), [`GET /api/v1/project-types`](https://docs.filmo.io/es/rest-api/endpoint-reference/projects/list-project-types), [`GET /api/v1/contacts/{contactId}/related-contacts`](https://docs.filmo.io/es/rest-api/endpoint-reference/contacts/list-the-contacts-related-to-a-contact), [`GET /api/v1/planner/services`](https://docs.filmo.io/es/rest-api/endpoint-reference/planner/list-the-services-to-cover) y [`GET /api/v1/planner/resources`](https://docs.filmo.io/es/rest-api/endpoint-reference/planner/list-the-assignable-resources). Las demás listas admiten `limit` y `cursor`.
- Un cursor está ligado al [`limit`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-limit) y al [`sort`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-sort) con los que se emitió. Mantén ambos idénticos en cada página de un recorrido. Consulta [Filtrado y orden](https://docs.filmo.io/es/rest-api/guides/filtering-and-sorting).
- Cada lista tiene un orden determinista y estable: lo más reciente primero salvo que la operación diga otra cosa, con `id` como desempate. La misma petición da el mismo orden, pero el cursor es una posición: los registros creados o eliminados mientras paginas pueden hacer que uno se repita o se omita, así que deduplica por `id`.
- Pide `total` solo cuando lo necesites, con [`includeTotal`](https://docs.filmo.io/es/rest-api/endpoint-reference/orders/list-orders#param-includeTotal). En otro caso se omite.
- Una página más grande significa menos peticiones contra el límite de 120 por minuto. Con el máximo de 500, leer 10,000 registros requiere 20 peticiones. Consulta [Límites de peticiones](https://docs.filmo.io/es/rest-api/guides/rate-limits).

## Cuando los registros cambian mientras paginas

> **Seguir el cursor puede saltarse registros:** El cursor marca una posición en el resultado. Si un registro que ya has leído se actualiza o se borra mientras sigues paginando, los registros posteriores se desplazan, y uno en el límite de una página puede perderse; no se devuelve de nuevo en esa pasada. Una pasada que tolere esto, como una exportación puntual, puede seguir el cursor. El cursor es una posición, no una instantánea: si ordenas por `updatedAt` y un registro se actualiza mientras paginas, pasa al final de una pasada ascendente (y los registros siguientes pueden saltarse) o al principio de una descendente (y puedes leer un registro dos veces). Para mantener otro sistema sincronizado con Filmo, no te apoyes en el cursor: lee ventanas de tiempo con los filtros `updated*`. [Sincronizar datos](https://docs.filmo.io/es/rest-api/guides/syncing-data) explica cómo.

## Siguientes pasos

- [Filtrado y orden](https://docs.filmo.io/es/rest-api/guides/filtering-and-sorting) reduce lo que tiene que leer una pasada.
- [Errores](https://docs.filmo.io/es/rest-api/guides/errors) cubre qué hacer cuando falla una petición de página.

---

URL canónica: https://docs.filmo.io/es/rest-api/guides/pagination  
Última actualización: 2026-10-09