# After LOC migration

After a successful migration, validate the results, adjust any discrepancies, and configure ongoing features.

## Validate balances

Compare the following values between Peach and your legacy system:

1. Total outstanding balance (principal + interest + fees)
2. Due amounts (minimum payment due)
3. Overdue amounts and days past due
4. Credit limit and available credit
5. Individual draw balances
6. Next payment due date and amount
7. Interest rate(s) and any active promo rates
8. Payment history accuracy
9. Migrated payment instruments


Use the following endpoints for validation:


```json
GET /api/people/{personId}/loans/{loanId}/balance
GET /api/people/{personId}/loans/{loanId}/draws/{drawId}/balance
GET /api/people/{personId}/loans/{loanId}/expected-payments
```

## Adjust balances

If there's a discrepancy between Peach and your legacy system:

**If Peach balance is higher** → apply a service credit:


```json
POST /api/people/{personId}/loans/{loanId}/transactions
Content-Type: application/json

{
  "amount": 5.43,
  "type": "serviceCredit",
  "serviceCreditsDetails": {
    "reason": "Migration balance adjustment",
    "sponsor": "loanServicer"
  },
  "effectiveDate": "2024-08-01",
  "effectiveTimeOfDay": {
    "hour": 12,
    "minute": 0,
    "second": 0
  }
}
```

**If Peach balance is lower** → apply an adjustment fee or leave as-is (in the borrower's favor):


```json
POST /api/people/{personId}/loans/{loanId}/fees
Content-Type: application/json

{
  "feeTypeId": "FT-ADJ-ABCD",
  "amount": 3.21,
  "chargeDate": "2024-08-01",
  "chargeTimeOfDay": {
    "hour": 12,
    "minute": 0,
    "second": 0
  }
}
```

The adjustment fee type (`adHoc` with a custom display name like "Balance Adjustment") must be configured by Peach. Contact your implementation team if you don't have one set up.

## Configure autopay

If the borrower was enrolled in autopay on the legacy system, set it up in Peach **after** migration completes.


```json
POST /api/people/{personId}/loans/{loanId}/autopay
Content-Type: application/json

{
  "type": "lineOfCredit",
  "paymentInstrumentId": "PI-1234-ABCD",
  "autopayAmountLogic": "statement_minimum_amount",
  "paymentScheduleDayOfMonth": 22,
  "paymentFrequency": "monthly",
  "consentDocumentId": "DD-CONSENT-ABCD"
}
```

**Autopay timing:** Configure autopay after the migrate call completes, not before. Peach does not process autopay payments during the migration replay period — if an autopay payment would have been due during the migration window, the system silently skips it. Be aware that it is possible to configure autopay schedules that don't align with your LOC billing frequency (e.g., `twiceMonthly` autopay on a `monthly` LOC), and there is currently no validation to prevent this, so ensure your autopay configuration matches your billing cycle.

## Re-enable borrower communications

Once you're confident the migration is successful and balances are correct, re-enable borrower notifications:


```json
PUT /api/people/{personId}/loans/{loanId}
Content-Type: application/json

{
  "muteLoanNotices": false
}
```

Don't re-enable communications until you've completed balance validation and any necessary adjustments. Premature re-enablement can trigger confusing notifications to borrowers (e.g., payment reminders with incorrect amounts).

## Set up credit reporting

If you report to credit bureaus, configure credit reporting during loan creation to maintain history continuity. You have two options.

For a full reference on Peach's credit reporting system, see the [Metro 2® Credit Reporting Logic Guide](/credit-reporting). The sections most relevant to migration are:

- [Payment Rating and History](/credit-reporting/payment-rating-history) — Payment History Profile character definitions and calculation algorithm (including migration history handling)
- [Field Specifications](/credit-reporting/field-specifications) — K2 Segment (Purchased From) and L1 Segment (Account Number Change) field details
- [Account Status Codes](/credit-reporting/account-status) — How Peach determines status codes post-migration


**Option 1: Report with payment history** (provide `paymentHistoryProfile`)

Include the borrower's Payment History Profile from the legacy system. This preserves up to 24 months of payment history on credit reports, ensuring no gap in the borrower's credit record.

Pass the following fields in the `migration.creditReporting` object when creating the loan:


```json
{
  "migration": {
    "migrationStatus": "prepMigration",
    "activatedDate": "2023-06-15",
    "activatedTimeOfDay": { "hour": 10, "minute": 0, "second": 0 },
    "creditReporting": {
      "paymentHistoryProfile": "000000000000000000000000",
      "dateOfFirstDelinquency": null,
      "k2Segment": {
        "purchasedFromName": "LEGACY LENDER INC"
      },
      "l1Segment": {
        "changeIndicator": "3",
        "oldConsumerAccountNumber": "LEGACY-ACCT-12345",
        "oldIdentificationNumber": "LEGACY-ID-6789"
      }
    }
  }
}
```

| Field | Description |
|  --- | --- |
| `paymentHistoryProfile` | 24-character string representing the last 24 months of payment history per the Metro 2 spec. Each character is a payment rating code. Most recent month first. See character definitions below. |
| `dateOfFirstDelinquency` | FCRA Date of First Delinquency (DOFD), if applicable. This value is provided as part of the migration process and is used directly by Peach the very first time the LOC is reported to credit bureaus. It does not interact with `migratedDaysOverdue` — they are independent fields. Set to the date the account first became 30+ days past due on the legacy system. `null` if the account has never been delinquent. See [Field Specifications — FCRA Date of First Delinquency](/credit-reporting/field-specifications#fcra-date-of-first-delinquency) for how Peach uses this value post-migration. |
| `k2Segment.purchasedFromName` | Name of the entity the account was purchased or transferred from. Reported in the Metro 2 K2 Segment with a Purchased From indicator (`1`). Maximum 30 characters, uppercase. See [Field Specifications — K2 Segment](/credit-reporting/field-specifications#k2-segment-purchased-from--sold-to). |
| `l1Segment.changeIndicator` | Indicates what changed during migration. `"1"` = Consumer Account Number changed only. `"2"` = Identification Number changed only. `"3"` = both changed. See [Field Specifications — L1 Segment](/credit-reporting/field-specifications#l1-segment-account-number-change). |
| `l1Segment.oldConsumerAccountNumber` | The Consumer Account Number from the legacy system. Peach reports this old number in the Base Segment and the new Peach account number in the L1 Segment, so bureaus can link the records. |
| `l1Segment.oldIdentificationNumber` | The Identification Number (subscriber code) from the legacy system. Same reporting logic as the account number — old value in the Base Segment, new value in L1. |


The K2 and L1 segment fields are independent of the Payment History Profile. You can provide a `paymentHistoryProfile` without K2/L1 segments, or vice versa, depending on your reporting needs.

**Payment History Profile character definitions:**

The `paymentHistoryProfile` string uses the standard Metro 2 character set. Use the codes from your legacy system's reporting data:

| Character | Meaning |
|  --- | --- |
| `0` | Current (0–29 days past due) |
| `1` | 30–59 days past due |
| `2` | 60–89 days past due |
| `3` | 90–119 days past due |
| `4` | 120–149 days past due |
| `5` | 150–179 days past due |
| `6` | 180+ days past due |
| `B` | No payment history available for this month |
| `D` | No payment due (e.g., forbearance, bankruptcy) |
| `E` | Zero balance / current (open-ended accounts) |
| `L` | Charge-off |


For a complete reference on how Peach calculates the Payment History Profile post-migration (including how the migrated profile merges with live data), see [Payment Rating and History](/credit-reporting/payment-rating-history).

The `paymentHistoryProfile` string must be exactly 24 characters. If the account has fewer than 24 months of history, pad the remaining positions (oldest months) with `B` to indicate no prior history. For example, an account with 12 months of current history: `000000000000BBBBBBBBBBBB`.

**Option 2: Report as new account** (omit `paymentHistoryProfile`)

If you don't have the borrower's Payment History Profile or prefer to start fresh, simply omit the `paymentHistoryProfile` field from the `creditReporting` object:


```json
{
  "migration": {
    "creditReporting": {
      "dateOfFirstDelinquency": null
    }
  }
}
```

With this option, Peach reports the account without historical payment data. For months prior to the migration cutoff date, the Payment History Profile will show `B` (no payment history available). History begins building from the migration date forward based on live loan performance.

**Charge-off reason during migration:** For accounts that were charged off on the legacy system, set the `chargedOffReason` value to match your legacy system's reason. Accepted values are `term`, `fraudulent`, `bankruptcy`, and `legal`. Matching the reason ensures consistency between your legacy reporting and Peach's ongoing reporting.

## System behavior after migration succeeds

Once `migrationStatus` transitions to `completed`, several automated processes begin running on the migrated loan. Understanding this sequence helps you validate results and avoid surprises during the first billing cycle.

### When daily loan maintenance (DLM) starts

Immediately after migration succeeds, Peach generates DLM events for the loan starting from the `interest_start_date` through today. DLM then runs daily (triggered by Google Cloud Scheduler at the start of US Pacific Time) for all subsequent days.

For migrated loans, DLM behavior depends on the loan's post-migration status:

| Post-migration status | DLM runs? | Interest accrues? |
|  --- | --- | --- |
| `active` | Yes | Yes |
| `accelerated` | Yes | No |
| `chargedOff` | No | No |


DLM is also responsible for balance movement between non-due, due, and overdue buckets, firing overdue/current events (used for webhooks), and charging late fees or service fees via a separate worker. For a deeper explanation of how DLM works for LOCs, see [Appendix A: LOC Billing Cycle Mechanics](/loan-lifecycle/loc-migration/how-loc-billing-cycles-work).

### First post-migration statement

The statement for the migration previous period (the billing cycle immediately before the cutoff date) is generated **during the migrate call itself**, not at the next statement date. Peach populates the previous period's statement with draw balances from the ledger update events you provided in the migration period data. This statement is used for autopay generation.

The first **new** statement generates at the next `statementDate` boundary after migration. For example, if your migration period runs Aug 1–Aug 31 with a statement date of Sep 1, the first new statement generates on Sep 1.

### Snapshot backfill

After migration completes, Peach queues a snapshot backfill that regenerates balance snapshots for every day between the migration cutoff date and the current date. This ensures that balance history is continuous for reporting and loan tape purposes.

The snapshot backfill process is being improved for greater reliability. Note that you should not see interest accrual on the migration cutoff date + 1 day — the backfill preserves historical consistency by not introducing interest charges for the cutoff boundary day.

### How ongoing activity works

After migration, the way you create activity changes:

| Activity | During migration | After migration |
|  --- | --- | --- |
| **Purchases** | Posted to migration draw with `originalDrawId` | Posted to actual draws (`POST /draws/{drawId}/purchases`) |
| **Transactions** | `POST .../transactions` with `isExternal: true` | `POST .../transactions` (standard — no `isExternal` flag) |
| **Fees** | `POST .../fees` with `migration.originalDrawId` | `POST .../fees` (standard) |
| **Payment instruments** | `isExternal: true` for historical instruments | Standard instruments |


Static draw disabled
After migration, the migration draw (drawType=Static) is disabled. Do not attempt to post new activity to it — the API will reject requests targeting a static draw with the error "This endpoint is invalid for a static draw."

### What happens at the next billing cycle boundary

The first post-migration billing cycle follows the standard LOC balance movement timeline:

1. **On statement date**: Non-due balances move to due. The amount moved equals the `remainingAmount` from the obligation for that period. Interest is truncated at this step — any fractional cents are moved to a `forgone_interest_rounding` bucket. See [Appendix A: LOC Billing Cycle Mechanics](/loan-lifecycle/loc-migration/how-loc-billing-cycles-work) for details.
2. **Between statement date and due date**: Balances sit in "due" buckets for 2–3 weeks. Borrowers make payments during this window. For LOC products with grace periods, payments applied during this window may have their `effectiveDate` set to the statement date for interest calculation purposes. See [Appendix B: Grace Period for Lines of Credit](/loan-lifecycle/loc-migration/how-grace-periods-work).
3. **On due date + 1**: Any remaining due balance moves to overdue. The system fires `loan_overdue` events, checks grace period eligibility, and evaluates whether the loan qualifies for acceleration or charge-off based on the loan type's overdue day threshold.


## Known limitations

These behaviors are by design but may surprise clients who expect the system to work differently than their legacy platform.

### Grace period override during migration

If a draw is configured with `numPeriodsToRestoreGrace` greater than 1 (meaning the borrower must pay in full for multiple consecutive periods to regain grace), this rule is **overridden to 1** during the migration period. Peach defaults to the borrower-favorable behavior because it does not have per-draw grace history for pre-migration periods. The configured `numPeriodsToRestoreGrace` takes full effect starting in the period after migration. See [Appendix B: Grace Period for Lines of Credit](/loan-lifecycle/loc-migration/how-grace-periods-work) for details.

### DPD calculation for migrated loans

Days past due for migrated loans combines the migrated overdue days with the time elapsed since cutoff:


```
effectiveDPD = peachTimeDiff + maxMigratedDaysOverdue
```

Where `peachTimeDiff` is `(today - migrationCutoffDate).days` and `maxMigratedDaysOverdue` is the highest `migratedDaysOverdue` value across all obligations. This means DPD continues to increase after migration if the borrower doesn't pay — it doesn't reset to zero at cutoff.

As the borrower pays down the overdue balance, the migrated overdue remaining amount decreases:


```
migratedOverdueRemainingAmount = migratedOverdueAmount - amountPaid
```

When `migratedOverdueRemainingAmount` reaches zero, the migrated overdue component is fully resolved.

The DPD prorating is continuous and does not account for period-level overdue buckets. This can produce unexpected results when a borrower has overdue balances spanning multiple periods. For example, if a borrower has overdue balances of $100 from period 1 (90 days overdue), $100 from period 2 (60 days overdue), and $800 from period 3 (30 days overdue), and they pay $200, they might expect to be considered only 30 days overdue (having cleared the two oldest periods). However, the system pro-rates continuously: with 80% of the total overdue amount remaining, it calculates 80% × 90 = 72 days overdue. This behavior is on the roadmap to be improved, but it is the current system behavior.

### No loan tapes for pre-migration periods

Peach does not generate loan tapes for periods before the migration cutoff date. After migration, loan tape fields are conditionally enabled based on whether the loan has a migration cutoff. This means historical loan tape data from before the cutoff must be sourced from your legacy system.

### Past-transaction drawSplitDetails access

The `drawSplitDetails` field for past transactions (showing how a payment was allocated across draws) is only available through the migration-specific endpoint (`GET .../migration/past-transaction`). The standard `GET .../transactions` endpoint does not return this field. This is a common source of confusion when building post-migration reconciliation tools.

### Balance precision and credit balance handling

All balance amounts must have a precision of exactly 0.01 (two decimal places) and be ≥ 0.00. Amounts with more than two decimal places are rejected. If a borrower has a credit balance (the lender owes the borrower money), use the `reimbursementAmount` field — do not use negative principal values.

### Statement date must be endDate + 1

Peach enforces a hard constraint: the statement date must be exactly one day after the period's end date. If `statementDate != endDate + 1 day`, validation fails. This is worth noting because some legacy systems use different date conventions.

### Effective time of day minimum

All transactions must have an `effectiveTimeOfDay` after 2:00 AM in the product's timezone. Transactions with earlier times fail validation. This constraint exists because DLM processes run in the early morning hours, and transactions must not conflict with those processes.

### Overdue amount and days overdue consistency

The system validates that `migratedDaysOverdue` and `migratedOverdueAmount` are consistent:

- Cannot have `migratedDaysOverdue > 0` if `migratedOverdueAmount` is 0
- Cannot have `migratedOverdueAmount > 0` if `migratedDaysOverdue` is 0
- Cannot have `migratedOverdueAmount > 0` if the total `obligationAmount` is less than the statement's `minimumAmountDue` (this implies payments were made that should have reduced the overdue state)


### Interest rounding for LOCs

At statement date, when non-due interest moves to due, the system truncates to the nearest cent. The fractional cents are moved to a `forgone_interest_rounding` bucket and are not recovered. Over many periods, this can create small discrepancies between Peach's interest calculation and a legacy system that rounds differently.

## See also

- [Modify data after LOC migration](/loan-lifecycle/loc-migration/modifying-data-after-migration) — Dispute purchases, cancel fees, and change or reverse past transactions.
- [LOC migration validation and troubleshooting](/loan-lifecycle/loc-migration/validation-and-troubleshooting) — Validation rules and a troubleshooting FAQ.
- [How LOC billing cycles work](/loan-lifecycle/loc-migration/how-loc-billing-cycles-work) — The balance-movement mechanics behind these behaviors.