{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"How LOC billing cycles work","siteUrl":"https://docs.peachfinance.com","description":"API and product documentation for Peach Finance, a lending-as-a-service platform.","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"how-loc-billing-cycles-work","__idx":0},"children":["How LOC billing cycles work"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["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."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This page explains how LOC billing cycles work. To run a migration, see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/loan-lifecycle/loc-migration/migration-procedure"},"children":["the LOC migration procedure"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"billing-period-structure","__idx":1},"children":["Billing period structure"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every LOC billing cycle is divided into periods defined by four key dates:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Date"},"children":["Date"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"What happens"},"children":["What happens"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["startDate"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Period begins. New balance tracking starts."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["endDate"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Period ends. Last day of the billing period."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["statementDate"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Statement generated. Always ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["endDate + 1"]},". Non-due balances move to due."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["dueDate"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Payment deadline. Full balance must be paid by this date for grace (if applicable)."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["dueDate + 1"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Enforcement. Unpaid due amounts move to overdue. Grace eligibility checked."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"danger"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In Peach, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["statementDate"]}," must always equal ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["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.\""]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"balance-movement-non-due--due--overdue","__idx":2},"children":["Balance movement: non-due → due → overdue"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Unlike installment loans where a single payment obligation comes due on one date, LOCs move balances through buckets on specific dates."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"non-due-to-due-statement-date","__idx":3},"children":["Non-due to due (statement date)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Between ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startDate"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["statementDate"]},", all accrued interest and posted transactions sit in the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["non-due"]}," bucket. On ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["statementDate"]},", the system moves the remaining non-due balance to the due bucket. The amount moved equals the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["remainingAmount"]}," from the obligation for that period."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During this step, outstanding non-due interest is ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["truncated"]}," to the nearest cent. Any fractional cents are moved to a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["forgone_interest_rounding"]}," bucket and are not recovered. This is a key difference from systems that round interest at a different cadence."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"due-to-overdue-due-date--1","__idx":4},"children":["Due to overdue (due date + 1)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["statementDate"]},", the balance sits in the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["due"]}," bucket. For LOCs, this is typically 2–3 weeks (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dueDate - statementDate + 1"]}," days). On ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dueDate + 1"]},", any remaining due balance moves to overdue."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Loan type"},"children":["Loan type"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Non-due → due"},"children":["Non-due → due"]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Time in \"due\""},"children":["Time in \"due\""]},{"$$mdtype":"Tag","name":"th","attributes":{"align":"left","data-label":"Due → overdue"},"children":["Due → overdue"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Line of credit"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Statement date"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["2–3 weeks"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Due date + 1"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Installment"]}]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Due date"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["1 day"]},{"$$mdtype":"Tag","name":"td","attributes":{"align":"left"},"children":["Due date + 1"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["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.\""]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"obligations-tracking-what-the-borrower-owes","__idx":5},"children":["Obligations: tracking what the borrower owes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["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?\""]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The obligation amount is computed from ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["expected payments"]}," — forecasts of what the borrower should pay based on the loan's schedule and fee structure:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"obligationAmount = sum(expectedPayment.amount)\n  where expectedPayment.period_id = obligation.period_id\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected payments include: one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PeriodicPayment"]}," (principal + interest), any number of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DynamicFee"]}," entries (e.g., periodic servicing fees), and optionally one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OriginationFee"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DrawFee"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The obligation also tracks payment progress:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"fulfilledAmount = paymentsAmount + serviceCreditsAmount\nremainingAmount = obligationAmount - fulfilledAmount\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fulfilledAmount"]}," calculation respects the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["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 ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["overpaymentsAmount"]}," but don't reduce future ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["remainingAmount"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["refresh_obligations()"]}," function recomputes all obligations whenever a relevant event occurs (payment, service credit, refund, etc.)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"why-this-matters-for-migration","__idx":6},"children":["Why this matters for migration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["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 — ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["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."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You also need to provide the correct ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["obligationAmount"]}," for the migration period (reconstructed from your legacy system's billing data). For overdue loans, you must include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["migratedDaysOverdue"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["migratedOverdueAmount"]}," so that Peach can correctly track the borrower's delinquency status going forward."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"timeline-example","__idx":7},"children":["Timeline example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"Day 1 (Aug 1):    startDate — Period begins\n                   ├─ Interest accrues daily in non-due bucket\n                   ├─ Purchases post to non-due bucket\n                   └─ Borrower can make payments (reduce non-due)\n\nDay 31 (Aug 31):  endDate — Period ends\n\nDay 32 (Sep 1):   statementDate — Statement generated\n                   ├─ Non-due balance moves to due bucket\n                   ├─ Interest truncated (fractional cents → forgone_interest_rounding)\n                   ├─ Obligation sealed (obligationAmount set)\n                   └─ Statement mailed/emailed to borrower\n\nDays 32–53:       Due period (balance in \"due\" for ~3 weeks)\n                   ├─ Borrower makes payments (reduce due)\n                   └─ Grace: payments effectiveDate → statementDate if eligible\n\nDay 53 (Sep 22):  dueDate — Payment deadline\n                   └─ Last day to pay for grace eligibility\n\nDay 54 (Sep 23):  dueDate + 1 — Enforcement\n                   ├─ Remaining due balance moves to overdue\n                   ├─ Grace eligibility checked (revoke or reinstate)\n                   ├─ loan_overdue event fires (if overdue)\n                   ├─ Late fees may be charged\n                   └─ Acceleration/charge-off threshold checked\n"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"see-also","__idx":8},"children":["See also"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/loan-lifecycle/loc-migration/migration-procedure"},"children":["LOC migration procedure"]}," — Apply these mechanics when seeding balances."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/loan-lifecycle/loc-migration/how-grace-periods-work"},"children":["How grace periods work for lines of credit"]}," — How grace interacts with the balance-movement timeline."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/loan-lifecycle/loc-migration/how-loc-draws-work"},"children":["How LOC draws work"]}," — How draws carry the balances that move through these buckets."]}]}]},"headings":[{"value":"How LOC billing cycles work","id":"how-loc-billing-cycles-work","depth":1},{"value":"Billing period structure","id":"billing-period-structure","depth":2},{"value":"Balance movement: non-due → due → overdue","id":"balance-movement-non-due--due--overdue","depth":2},{"value":"Non-due to due (statement date)","id":"non-due-to-due-statement-date","depth":3},{"value":"Due to overdue (due date + 1)","id":"due-to-overdue-due-date--1","depth":3},{"value":"Obligations: tracking what the borrower owes","id":"obligations-tracking-what-the-borrower-owes","depth":2},{"value":"Why this matters for migration","id":"why-this-matters-for-migration","depth":2},{"value":"Timeline example","id":"timeline-example","depth":2},{"value":"See also","id":"see-also","depth":2}],"frontmatter":{"title":"How LOC billing cycles work","description":"How a line-of-credit billing cycle works in Peach: period dates, non-due to due to overdue balance movement, obligations, interest truncation.","verifiedDate":"2026-06-10T00:00:00.000Z","verifiedSpec":"loc-migration.yml","verifiedRef":"peach@41d1f8a","seo":{"title":"How LOC billing cycles work"}},"lastModified":"2026-06-10T22:51:20.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/loan-lifecycle/loc-migration/how-loc-billing-cycles-work","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}