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

# List the loans

> Every loan of the tenancy, or one client's, each row a summary with the folded state on it.

The collection answers summary rows, newest first — enough to find a Loan and see what it is, with the full record one [read](/api-reference/loans/read) away. The row carries the folded `state`, and a state that stops the Loan carries its date beside it: a ceded row reads `ceded_on`. It also carries the contract as issued — `rate`, `fee`, `penalty_rate` and the plan's total of payments — and what the receipts did: `paid`, the settled and remaining Periods, and whether the Loan still owes and to whom. A catalogue of credits prints from the row without a second read.

Four narrowings: by Client, by Product configuration, by merchant, and by state.

## Path parameters

<ParamField path="tenant_id" type="string" required>
  The Tenancy listing.
</ParamField>

## Query parameters

<ParamField query="client_id" type="string">
  One Client's Loans only.
</ParamField>

<ParamField query="configuration_id" type="string">
  One Product configuration's Loans only — every version of it, since a Loan names the version it was issued under and the narrowing is by product.
</ParamField>

<ParamField query="merchant_ref" type="string">
  The Loans issued naming one merchant only. A Loan that names none is on no merchant's listing. What the merchant is owed over a period is [the merchant's book](/api-reference/merchants/book).
</ParamField>

<ParamField query="state" type="string">
  One folded state only: `active`, `cancelled`, `closed`, `written_off`, `ceded`, `held`, `expired`, `voided`, `rescinded`, `withdrawn` or `restructured`.

  A Loan issued with a hold and not confirmed — `held`, `expired`, or `voided` before it was signed — is listed only when this filter names one of those three. A listing that names none reads the book as it read before holds existed. `expired` needs `on`.

  The state is derived rather than stored, so this filter narrows the book and not the page: the walk reads past rows that do not match until the page fills. The work one request may do is bounded at **ten times `limit`** rows examined, so a filtered page may come back short — or empty — **carrying a cursor**. Read the section below before you treat a short page as the end.
</ParamField>

<ParamField query="on" type="string">
  The date a hold is judged against: a hold whose `hold_until` this date is after reads `expired`. Without it an unconfirmed hold reads `held` — there is no today to judge it by.
</ParamField>

<ParamField query="limit" type="integer" default="50">
  How many rows to serve, between 1 and 200. A value outside that range is `400`, never clamped.
</ParamField>

<ParamField query="cursor" type="string">
  Where to resume, returned verbatim from the previous page.
</ParamField>

Any other parameter — unknown, repeated, or valueless — is `400` `invalid_query`. So is a `state` this platform does not fold to, and a `client_id`, `configuration_id` or `merchant_ref` that is not an identifier.

## Walking a filtered listing

Under `state`, a cursor says the walk continues and nothing about whether another matching Loan exists. A page can be empty and still carry one, which means the request spent its budget of rows before it found a match — send the cursor back and the walk carries on from there.

The listing ends when a page arrives **without** a cursor. That is the only end signal, on this route and on every other: never read the end from the length of a page.

<Warning>
  A client that stops when a page comes back shorter than `limit` will miss Loans under `state`. Loop while `cursor` is present.
</Warning>

## Response

<ResponseField name="loans" type="array" required>
  The rows.

  <Expandable title="row">
    <ResponseField name="id" type="string" required>
      The Loan's identifier.
    </ResponseField>

    <ResponseField name="reference" type="string" required>
      Your identifier from the issuance.
    </ResponseField>

    <ResponseField name="state" type="string" required>
      Folded, exactly as the read folds it.
    </ResponseField>

    <ResponseField name="closed_on" type="string">
      The value date the Loan was discharged on, present on a `closed` row. Absent while it is still owed something.
    </ResponseField>

    <ResponseField name="written_off_on" type="string">
      The day the debt was judged uncollectable, present on a `written_off` row. What it cost is on the single read.
    </ResponseField>

    <ResponseField name="ceded_on" type="string">
      The cut-off, present on a `ceded` row — so a reconciliation asks which Loans left and as of when without reading each one.
    </ResponseField>

    <ResponseField name="client_id" type="string" required>
      The Client the Loan names.
    </ResponseField>

    <ResponseField name="merchant_ref" type="string">
      The merchant the Loan names, absent where it names none.
    </ResponseField>

    <ResponseField name="configuration" type="object" required>
      `{id, version}`, pinned.
    </ResponseField>

    <ResponseField name="principal" type="object" required>
      The amount lent.
    </ResponseField>

    <ResponseField name="term_periods" type="integer" required>
      The term.
    </ResponseField>

    <ResponseField name="rate" type="string" required>
      The contract rate as issued, in per cent a year. Not derived — it is the agreement.
    </ResponseField>

    <ResponseField name="fee" type="object" required>
      The origination fee as issued. A Product that charges none states a zero, so it is never absent.
    </ResponseField>

    <ResponseField name="paid" type="object">
      What the receipts have settled against this Loan to date, a stated zero on a Loan nothing has reached.

      It is **absent** where the Client's allocation cannot be derived — and the row then names the difficulty in `anomalies`. A figure the platform cannot stand behind is not served as one it can.
    </ResponseField>

    <ResponseField name="totals.payments" type="object">
      What the plan collects, the payment at the purchase included. The Loan's own Periods summed, never derived.
    </ResponseField>

    <ResponseField name="settled_periods" type="integer">
      Periods of the term settled entire, whatever settled them — a Receipt, a return, a rollover, a payoff. The payment at the purchase is not counted. Absent exactly where `paid` is.
    </ResponseField>

    <ResponseField name="remaining_periods" type="integer">
      Periods the plan still charges and nothing has settled entire. A Period a prepayment recalculated is one of them. Absent exactly where `paid` is.
    </ResponseField>

    <ResponseField name="penalty_rate" type="string" required>
      The moratory rate the regime froze at issuance, in per cent a year.
    </ResponseField>

    <ResponseField name="owes" type="boolean" required>
      Whether the Loan still owes anything. Never infer it from `state` alone:

      | `state` | `owes` | `owed_to` |
      | - | - | - |
      | `active` | `true` | `tenant` |
      | `written_off` | `true` — a write-off is not a release | `tenant` |
      | `ceded` | `true` | `assignee` |
      | `restructured` | `true` | `tenant` |
      | `closed`, `cancelled`, `held`, `expired`, `voided`, `rescinded`, `withdrawn` | `false` | absent |

      A written-off Loan the Receipts later discharged keeps its state and owes nothing.
    </ResponseField>

    <ResponseField name="owed_to" type="string">
      `tenant` or `assignee`; absent where the Loan owes nothing.
    </ResponseField>

    <ResponseField name="anchor" type="string" required>
      The day the agreement runs from.
    </ResponseField>

    <ResponseField name="rolled_over" type="integer" required>
      Rollovers in force, zero included.
    </ResponseField>

    <ResponseField name="anomalies" type="array" required>
      As on the read — empty on a healthy Loan.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="cursor" type="string">
  Where the next page resumes. Present whenever the walk continues — under `state` a page may be short or empty and still carry one — and absent exactly at the end of the listing.
</ResponseField>

<RequestExample>
  ```bash List one client's loans theme={null}
  curl "https://api.capcells.com/v1/tenants/$TENANT_ID/loans?client_id=c-0001" \
    -H "Authorization: $(capcells_sign "$CAPCELLS_API_KEY" GET "/v1/tenants/$TENANT_ID/loans?client_id=c-0001")"
  ```

  ```bash Walk the ceded loans theme={null}
  QUERY="?state=ceded&limit=50"
  while :; do
    PAGE=$(curl -s "https://api.capcells.com/v1/tenants/$TENANT_ID/loans$QUERY" \
      -H "Authorization: $(capcells_sign "$CAPCELLS_API_KEY" GET "/v1/tenants/$TENANT_ID/loans$QUERY")")
    echo "$PAGE" | jq -r '.loans[].id'
    CURSOR=$(echo "$PAGE" | jq -r '.cursor // empty')
    [ -n "$CURSOR" ] || break
    QUERY="?state=ceded&limit=50&cursor=$CURSOR"
  done
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "loans": [
      {
        "id": "9c1a7e10-6b2f-4a55-8d31-1f0b52a4c7e2",
        "tenant_id": "t-0001",
        "client_id": "c-0001",
        "reference": "loan-0002",
        "configuration": { "id": "inst-000001", "version": 1 },
        "principal": { "minor_units": 500000, "currency": "MXN" },
        "term_periods": 6,
        "rate": "45.5",
        "fee": { "minor_units": 25000, "currency": "MXN" },
        "paid": { "minor_units": 0, "currency": "MXN" },
        "totals": { "payments": { "minor_units": 540396, "currency": "MXN" } },
        "settled_periods": 0,
        "remaining_periods": 6,
        "penalty_rate": "36",
        "owes": true,
        "owed_to": "assignee",
        "anchor": "2026-08-10",
        "state": "ceded",
        "rolled_over": 0,
        "ceded_on": "2026-09-15",
        "created_at": "2026-08-10T12:00:02Z",
        "anomalies": []
      },
      {
        "id": "7771aef0-9e65-4a0a-a902-aab4e970d33f",
        "tenant_id": "t-0001",
        "client_id": "c-0001",
        "reference": "loan-0001",
        "configuration": { "id": "inst-000001", "version": 1 },
        "principal": { "minor_units": 500000, "currency": "MXN" },
        "term_periods": 6,
        "rate": "45.5",
        "fee": { "minor_units": 25000, "currency": "MXN" },
        "paid": { "minor_units": 90066, "currency": "MXN" },
        "totals": { "payments": { "minor_units": 540396, "currency": "MXN" } },
        "settled_periods": 1,
        "remaining_periods": 5,
        "penalty_rate": "36",
        "owes": true,
        "owed_to": "tenant",
        "anchor": "2026-08-10",
        "state": "active",
        "rolled_over": 0,
        "created_at": "2026-08-10T12:00:01Z",
        "anomalies": []
      }
    ]
  }
  ```
</ResponseExample>


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