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

# Loans

> One-shot loan origination via POST /loans — submit, approve, and disburse in a single call.

A **loan** is an extension of credit to a customer. Origination is a
**single call**: `POST /v1/loans` submits the application, approves it,
and disburses the full principal, returning a loan that is already
`Active`.

```
POST /v1/loans  ⇒  Active (with repayments) → Closed
```

There are no separate approve or disburse endpoints — those steps
happen automatically inside `POST /v1/loans`. Reversals are available
for admin/operational use:

| From state                   | Reversal                                                                                     |
| ---------------------------- | -------------------------------------------------------------------------------------------- |
| `Active`                     | [Undo disbursal](/loans/undo-disbursal) — returns the loan to `Approved`                     |
| `Approved`                   | [Undo approval](/loans/undo-approval) — returns the loan to `Submitted and pending approval` |
| Any with outstanding balance | [Write off](/loans/writeoff) the remaining balance                                           |

## The loan object

<ResponseField name="id" type="string">
  Unique loan identifier.
</ResponseField>

<ResponseField name="accountNo" type="string" />

<ResponseField name="externalId" type="string">
  Your partner-supplied identifier for the loan. Always present —
  an empty string `""` when the loan was created without one — so you
  can rely on the key existing when joining list rows back to your own
  records.
</ResponseField>

<ResponseField name="customerId" type="string">
  The customer this loan belongs to.
</ResponseField>

<ResponseField name="customerName" type="string" />

<ResponseField name="loanProductId" type="string">
  The product template this loan was created from. See
  [Loan products](/loan-products/list).
</ResponseField>

<ResponseField name="loanProductName" type="string" />

<ResponseField name="status" type="string">
  Lifecycle status. Common values: `Submitted and pending approval`,
  `Approved`, `Active`, `Closed (obligations met)`,
  `Closed (written off)`.
</ResponseField>

<ResponseField name="principal" type="number">
  Requested principal amount.
</ResponseField>

<ResponseField name="approvedPrincipal" type="number">
  Approved principal (may differ from requested). Present after approval.
</ResponseField>

<ResponseField name="currencyCode" type="string">
  ISO-4217 currency code, e.g. `TZS`, `USD`.
</ResponseField>

<ResponseField name="termFrequency" type="integer">
  Loan term in units of frequency type.
</ResponseField>

<ResponseField name="numberOfRepayments" type="integer">
  How many installments the loan is scheduled across.
</ResponseField>

<ResponseField name="interestRatePerPeriod" type="number" />

### Balance roll-up

These fields summarise what has been charged, paid, and is still owed
across the loan. **Every roll-up field is always present** on both list
and detail responses — a `0` means "nothing charged/owed", never "field
missing" — so dashboards can read them without existence checks.

<ResponseField name="principalDisbursed" type="number">
  Principal amount actually paid out at disbursal.
</ResponseField>

<ResponseField name="principalPaid" type="number">Principal portion already repaid.</ResponseField>
<ResponseField name="principalOutstanding" type="number">Principal portion still owed.</ResponseField>

<ResponseField name="interestCharged" type="number">Total interest accrued over the life of the loan.</ResponseField>
<ResponseField name="interestPaid" type="number">Interest already repaid.</ResponseField>
<ResponseField name="interestOutstanding" type="number">Interest still owed.</ResponseField>

<ResponseField name="feeCharged" type="number">Total fees charged.</ResponseField>
<ResponseField name="feePaid" type="number">Fees already paid.</ResponseField>
<ResponseField name="feeOutstanding" type="number">Fees still owed.</ResponseField>

<ResponseField name="penaltyCharged" type="number">Total penalty charges applied (e.g. late fees).</ResponseField>
<ResponseField name="penaltyPaid" type="number">Penalty portion already paid.</ResponseField>
<ResponseField name="penaltyOutstanding" type="number">Penalty portion still owed.</ResponseField>

<ResponseField name="totalRepayment" type="number">
  Sum of everything the customer has paid in across all components
  (principal + interest + fees + penalty).
</ResponseField>

<ResponseField name="totalOutstanding" type="number">
  Headline "what does the customer still owe" — sum of every
  *outstanding* field above. This is the number to display on the USSD
  / dashboard when telling the customer their debt.
</ResponseField>

<ResponseField name="totalOverpaid" type="number">
  Non-zero only when the loan status is `Overpaid`. The credit on the
  loan that needs to be refunded via
  [Credit balance refund](/repayments/credit-balance-refund).
</ResponseField>

### Next-due and schedule

<ResponseField name="nextDueDate" type="string">
  ISO-8601 (`yyyy-MM-dd`) date of the next unpaid instalment. Empty
  for fully-paid or closed loans.
</ResponseField>

<ResponseField name="nextDueAmount" type="number">
  Amount outstanding on that next-unpaid instalment (sum of the period's
  outstanding principal + interest + fee + penalty). Zero when there
  is no next-due.
</ResponseField>

<ResponseField name="overdue" type="boolean">
  `true` when the loan is `Active` **and** has at least one past-due
  unpaid instalment. Computed server-side so partners don't need to
  compare schedule dates against the current date themselves.
  Always `false` for non-Active loans — `Closed (obligations met)`,
  `Closed (written off)`, and `Overpaid` have already settled the
  obligation one way or the other.
</ResponseField>

<ResponseField name="repaymentSchedule" type="array of objects">
  Full amortisation table — one entry per instalment. Each period
  carries `period`, `dueDate`, `complete`, plus the
  `principal{Due,Paid,Outstanding}`, `interest{Due,Paid,Outstanding}`,
  `fee{Due,Paid,Outstanding}`, `penalty{Due,Paid,Outstanding}`, and
  `total{Due,Paid,Outstanding}` triplets. Always present on single-loan
  reads; **best-effort on list rows** (see the note on
  [List loans](/loans/list#response)) — a list row can transiently omit
  it, in which case `nextDueDate`/`nextDueAmount` are still populated.
</ResponseField>

<ResponseField name="repaymentHistory" type="array of objects">
  The loan's **repayment** transactions, newest first — only customer
  repayments (disbursements, waivers, and accruals are excluded). Each
  entry is a [repayment object](/repayments/overview). Present **only on
  single-loan reads**, not on the loan list. For a paginated view of the
  same data, use [List repayments](/repayments/list).
</ResponseField>

## Endpoints

| Method | Path                                                             | Purpose                                                                                                                     |
| ------ | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| POST   | `/v1/loans`                                                      | [Create](/loans/create) a loan — `customerId` in the body carries the **customer's externalId**; optional loan `externalId` |
| GET    | `/v1/loans`                                                      | [List](/loans/list) loans — filterable by `customerId`, `customerExternalId`, and `status`                                  |
| GET    | `/v1/loans/external/{loan_external_id}`                          | [Get](/loans/get) by externalId (recommended)                                                                               |
| GET    | `/v1/loans/{loan_id}`                                            | [Get](/loans/get) by LMS id                                                                                                 |
| POST   | `/v1/loans/external/{loan_external_id}/...`                      | Every [repayment](/repayments/overview) op in externalId form (recommended)                                                 |
| POST   | `/v1/loans/{loan_id}/repayments[/...]`                           | Repayments in LMS-id form                                                                                                   |
| POST   | `/v1/loans/external/{loan_external_id}/rollback`                 | [Roll back](/loans/rollback) a failed disbursement in one call (recommended)                                                |
| POST   | `/v1/loans/{loan_id}/rollback`                                   | [Roll back](/loans/rollback) by LMS id                                                                                      |
| POST   | `/v1/loans/external/{loan_external_id}/undo-disbursal`           | [Undo disbursal](/loans/undo-disbursal) by externalId (recommended)                                                         |
| POST   | `/v1/loans/{loan_id}/undo-disbursal`                             | [Undo disbursal](/loans/undo-disbursal) by LMS id                                                                           |
| POST   | `/v1/loans/external/{loan_external_id}/undo-approval`            | [Undo approval](/loans/undo-approval) by externalId (recommended)                                                           |
| POST   | `/v1/loans/{loan_id}/undo-approval`                              | [Undo approval](/loans/undo-approval) by LMS id                                                                             |
| DELETE | `/v1/loans/external/{loan_external_id}`                          | [Delete](/loans/delete) by externalId (recommended)                                                                         |
| DELETE | `/v1/loans/{loan_id}`                                            | [Delete](/loans/delete) by LMS id                                                                                           |
| POST   | `/v1/loans/external/{loan_external_id}/adjust-disbursement-date` | [Adjust disbursement date](/loans/adjust-disbursement-date) by externalId (recommended)                                     |
| POST   | `/v1/loans/{loan_id}/adjust-disbursement-date`                   | [Adjust disbursement date](/loans/adjust-disbursement-date) by LMS id                                                       |
| PUT    | `/v1/loans/{loan_id}`                                            | [Update](/loans/update) a loan (pending only) — numeric only                                                                |
| POST   | `/v1/loans/{loan_id}/writeoff`                                   | [Write off](/loans/writeoff) — numeric only                                                                                 |

Read, repayment, undo, delete, and rollback paths all support both
forms; the externalId form is recommended for partner integrations.

For repayment-side operations, see the [Repayments](/repayments/overview)
section.
