# How LOC billing cycles work

A line of credit billing cycle is fundamentally different from an installment loan. Understanding this structure is critical for migration because Peach must initialize balance buckets correctly at cutover — and post-migration, these mechanics govern how balances move, when interest accrues, and when a borrower becomes overdue.

This page explains how LOC billing cycles work. To run a migration, see [the LOC migration procedure](/loan-lifecycle/loc-migration/migration-procedure).

## Billing period structure

Every LOC billing cycle is divided into periods defined by four key dates:

| Date | What happens |
|  --- | --- |
| **startDate** | Period begins. New balance tracking starts. |
| **endDate** | Period ends. Last day of the billing period. |
| **statementDate** | Statement generated. Always `endDate + 1`. Non-due balances move to due. |
| **dueDate** | Payment deadline. Full balance must be paid by this date for grace (if applicable). |
| **dueDate + 1** | Enforcement. Unpaid due amounts move to overdue. Grace eligibility checked. |


In Peach, `statementDate` must always equal `endDate + 1 day`. This is a hard validation rule — if they don't match, migration will fail with "Period statement date should be one day after end date."

## Balance movement: non-due → due → overdue

Unlike installment loans where a single payment obligation comes due on one date, LOCs move balances through buckets on specific dates.

### Non-due to due (statement date)

Between `startDate` and `statementDate`, all accrued interest and posted transactions sit in the **non-due** bucket. On `statementDate`, the system moves the remaining non-due balance to the due bucket. The amount moved equals the `remainingAmount` from the obligation for that period.

During this step, outstanding non-due interest is **truncated** to the nearest cent. Any fractional cents are moved to a `forgone_interest_rounding` bucket and are not recovered. This is a key difference from systems that round interest at a different cadence.

### Due to overdue (due date + 1)

After `statementDate`, the balance sits in the **due** bucket. For LOCs, this is typically 2–3 weeks (`dueDate - statementDate + 1` days). On `dueDate + 1`, any remaining due balance moves to overdue.

| Loan type | Non-due → due | Time in "due" | Due → overdue |
|  --- | --- | --- | --- |
| **Line of credit** | Statement date | 2–3 weeks | Due date + 1 |
| **Installment** | Due date | 1 day | Due date + 1 |


This is the most important structural difference between LOCs and installment loans. For installment loans, balances move from non-due to due on the due date and become overdue just one day later. For LOCs, there's a substantial window between "due" and "overdue."

## Obligations: tracking what the borrower owes

An **obligation** tracks how much the borrower must pay in a specific billing period. It answers: "How much is owed, how much has been paid, and how much remains?"

The obligation amount is computed from **expected payments** — forecasts of what the borrower should pay based on the loan's schedule and fee structure:


```
obligationAmount = sum(expectedPayment.amount)
  where expectedPayment.period_id = obligation.period_id
```

Expected payments include: one `PeriodicPayment` (principal + interest), any number of `DynamicFee` entries (e.g., periodic servicing fees), and optionally one `OriginationFee` or `DrawFee`.

The obligation also tracks payment progress:


```
fulfilledAmount = paymentsAmount + serviceCreditsAmount
remainingAmount = obligationAmount - fulfilledAmount
```

The `fulfilledAmount` calculation respects the `allowPrepayments` loan type setting. If prepayments are allowed, a borrower's early payment can satisfy future obligations. If prepayments are not allowed, excess payments are tracked as `overpaymentsAmount` but don't reduce future `remainingAmount`.

The `refresh_obligations()` function recomputes all obligations whenever a relevant event occurs (payment, service credit, refund, etc.).

## Why this matters for migration

During migration, you must seed Peach's ledger with the correct balance buckets. Your legacy system's balances must be broken down into non-due, due, and overdue — **per fee type** (principal, interest, periodic fees, late fees, origination fees, draw fees, etc.). If these breakdowns are incorrect, post-migration DLM will move the wrong amounts at statement date, causing balance discrepancies.

You also need to provide the correct `obligationAmount` for the migration period (reconstructed from your legacy system's billing data). For overdue loans, you must include `migratedDaysOverdue` and `migratedOverdueAmount` so that Peach can correctly track the borrower's delinquency status going forward.

## Timeline example


```
Day 1 (Aug 1):    startDate — Period begins
                   ├─ Interest accrues daily in non-due bucket
                   ├─ Purchases post to non-due bucket
                   └─ Borrower can make payments (reduce non-due)

Day 31 (Aug 31):  endDate — Period ends

Day 32 (Sep 1):   statementDate — Statement generated
                   ├─ Non-due balance moves to due bucket
                   ├─ Interest truncated (fractional cents → forgone_interest_rounding)
                   ├─ Obligation sealed (obligationAmount set)
                   └─ Statement mailed/emailed to borrower

Days 32–53:       Due period (balance in "due" for ~3 weeks)
                   ├─ Borrower makes payments (reduce due)
                   └─ Grace: payments effectiveDate → statementDate if eligible

Day 53 (Sep 22):  dueDate — Payment deadline
                   └─ Last day to pay for grace eligibility

Day 54 (Sep 23):  dueDate + 1 — Enforcement
                   ├─ Remaining due balance moves to overdue
                   ├─ Grace eligibility checked (revoke or reinstate)
                   ├─ loan_overdue event fires (if overdue)
                   ├─ Late fees may be charged
                   └─ Acceleration/charge-off threshold checked
```

## See also

- [LOC migration procedure](/loan-lifecycle/loc-migration/migration-procedure) — Apply these mechanics when seeding balances.
- [How grace periods work for lines of credit](/loan-lifecycle/loc-migration/how-grace-periods-work) — How grace interacts with the balance-movement timeline.
- [How LOC draws work](/loan-lifecycle/loc-migration/how-loc-draws-work) — How draws carry the balances that move through these buckets.