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

# Pagination & filters

> How Croma Legal lists page, what each filter matches, which date means what, and how to sync incrementally.

## Two pagination styles

**Cursor pagination** is used by the large lists:
[`GET /v1/processes`](/legal/api-reference/list-processes),
[`GET /v1/actions`](/legal/api-reference/list-actions) and
[`GET /v1/defendants`](/legal/api-reference/list-defendants).

| Param / field            | Meaning                                                          |
| ------------------------ | ---------------------------------------------------------------- |
| `page_size` (request)    | Rows per page. Default `25`, max `100`.                          |
| `cursor` (request)       | The `next_cursor` of the previous page. Omit for the first page. |
| `next_cursor` (response) | Opaque string for the next page; `null` on the last page.        |
| `has_more` (response)    | `true` while there are more rows.                                |

Cursors are opaque: pass them back unchanged and don't build them yourself.
They are meant to be used within one pass over the list; to start over, drop
the cursor and request the first page again.

```ts theme={"dark"}
async function* processes(params: Record<string, string>) {
  let cursor: string | null = null;
  do {
    const url = new URL("https://api.legal.usecroma.com/v1/processes");
    for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
    url.searchParams.set("page_size", "100");
    if (cursor) url.searchParams.set("cursor", cursor);

    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.CROMA_LEGAL_API_KEY}` },
    });
    const body = await res.json();
    yield* body.data;
    cursor = body.has_more ? body.next_cursor : null;
  } while (cursor);
}
```

**Page-number pagination** is used by a single case's timeline,
[`GET /v1/processes/{process_id}/actions`](/legal/api-reference/list-process-actions):
`page` (from `1`) and `page_size` (default `25`, max `100`), with the `total`
count in the response.

<Note>
  Paging through a whole portfolio to build a file is the slow way. For the
  complete dataset, use [Exports](/legal/exports): one request, one CSV or
  JSONL download, up to 100,000 rows.
</Note>

## Addressing a case

Wherever a process appears in a path, both forms work and resolve to the same
case:

* the internal `id` (a UUID) returned by the list endpoints, or
* the registration number (radicado), e.g. `11001400300120240012300`.

Defendants are addressed by their internal `id` from
[`GET /v1/defendants`](/legal/api-reference/list-defendants) (also exposed as
`defendant_uuid` on a process's detail). The `defendant_id` field on processes
and actuaciones is the identification number (cédula or NIT), not that UUID.

## How filters match

* **Text filters** (`q`, `defendant`, `defendant_id`, `office`, `name`,
  `content`) are partial and case-insensitive: `office=civil municipal`
  matches `JUZGADO 001 CIVIL MUNICIPAL DE BOGOTÁ`.
* **Enums** (`status`, `priority`, `since_mode`, `granularity`) must match
  exactly; an unknown value returns `400 invalid_param`.
* **Booleans** (`has_actions`) take `true` or `false`.
* **Dates** are ISO 8601 (`2026-08-01` or `2026-08-01T00:00:00Z`). An
  unparseable date is ignored rather than rejected, so double-check the format
  if a date filter seems to have no effect.
* Filters **combine with AND**. A list with no matches is a `200` with an empty
  `data`, never a `404`.

`q` always matches the **registration number** (radicado): use it on processes
and on the actuaciones feed. On defendants, `q` matches the identification
number and `name` matches the name.

## Which date is which

The portfolio carries several dates; picking the right one matters for
reporting and for syncing.

| Field                 | On             | Meaning                                                                                                                 |
| --------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `registration_date`   | process        | Filing date (fecha de radicación). `date_from` / `date_to` filter on it.                                                |
| `last_discovery_date` | process        | Last time Croma reviewed the case. It updates even when nothing changed, so it does **not** indicate judicial activity. |
| `tracking_since`      | process detail | When the case entered your organization's portfolio.                                                                    |
| `registration_date`   | actuación      | The actuación's judicial date. The date that measures procedural activity; may be `null` for some actuaciones.          |
| `action_created_at`   | actuación      | When Croma recorded the actuación. The date to use for "what is new since my last sync".                                |

On the actuaciones feed, `since_mode` picks which of the two actuación dates
`since` / `until` and the ordering use:

* `discovered` (default): `action_created_at`.
* `judicial`: `registration_date`.

## Default ordering

| Endpoint                            | Order                                                                                                  |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `GET /v1/processes`                 | Most recently reviewed first (`last_discovery_date` desc).                                             |
| `GET /v1/processes/{id}/actions`    | Newest first by judicial date.                                                                         |
| `GET /v1/actions`                   | Most relevant first: a relevance score over the actuación text, then date (per `since_mode`), then id. |
| `GET /v1/defendants`                | Newest defendant record first.                                                                         |
| `GET /v1/defendants/{id}/processes` | Most recently active case first (latest actuación date).                                               |

## Recipe: incremental sync of actuaciones

To mirror the portfolio's activity into your own system, pull the feed by
discovery time and keep a watermark:

<Steps>
  <Step title="Remember when you start">
    Capture `now` before the first request. This will be the next run's
    `since`, so anything recorded while you page is picked up next time.
  </Step>

  <Step title="Page through everything recorded since the last watermark">
    ```bash theme={"dark"}
    curl "https://api.legal.usecroma.com/v1/actions?since=2026-08-20T06:00:00Z&since_mode=discovered&page_size=100" \
      -H "Authorization: Bearer $CROMA_LEGAL_API_KEY"
    ```

    Follow `next_cursor` until `has_more` is `false`. Each row carries
    `process_id` and `registration_number`, so you can attach it to the case
    you already hold, or fetch the case with
    [`GET /v1/processes/{process_id}`](/legal/api-reference/get-process) if it
    is new to you.
  </Step>

  <Step title="Advance the watermark">
    Store the `now` you captured as the next `since`. Because `since` is
    inclusive, re-running with the same watermark is safe: you may see the
    boundary rows again, and their `id` lets you de-duplicate.
  </Step>
</Steps>

Use `since_mode=judicial` instead when the question is "which actuaciones
happened in court during a period", for example a weekly report of filings
dated within that week.

<Card title="Next: Rate limits" icon="gauge" href="/legal/rate-limits">
  How quotas are bucketed and reported on every response.
</Card>
