# 2026 Release Notes

Weekly notes appear below, newest first; the 2026 Q1 quarterly notes follow at the end of the page.

## Week of August 3, 2026

This week brings interest, payment tape, and loan tape corrections along with a portal reliability fix.

### Bug Fixes

#### Migrated line-of-credit draws now charge the minimum interest amount on the statement date

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle · Loan Configuration

Fixed an issue where a draw on a migrated line of credit that is configured to charge interest up to a minimum amount — such as a non-amortized draw — did not charge that minimum on the statement date. The minimum interest charge now follows the draw's current minimum-payment configuration, so a later change to that configuration is reflected when interest is charged.

#### Investor-scoped payment tapes include only payments that settled to that investor

**Type:** Bug Fix
**Impact:** Informational
**Area:** Data & Reporting

Fixed an issue where a payment tape scoped to a single investor could include payments that had settled to a different investor, so the tape did not reconcile against the cash that investor actually received. An investor-scoped payment tape now includes a payment only when it settled to that investor.

See [Generate a loan tape for a single investor](/data-reporting/loan-tape-by-investor).

#### Loan tape creation no longer fails in a rare edge case

**Type:** Bug Fix
**Impact:** Informational
**Area:** Data & Reporting

Fixed a rare edge case that could cause loan tape creation to fail. Loan tapes now generate reliably in this case.

#### The portal recovers from a persistent error screen after a new release

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where the portal could show a persistent error screen after a new version was released, which a page refresh or signing out and back in did not clear.

## Week of July 27, 2026

This week brings a newly generally available API version, credit-reporting and statement corrections, and several portal and servicing fixes.

### New Features

#### API version 2025-03-26 is now generally available

**Type:** New Feature
**Impact:** Informational
**Area:** Developer Tools

**What:** API version `2025-03-26` has graduated from Beta and is now generally available. As the latest non-Beta version, it becomes the version applied to new API keys and to requests that do not specify a version. Existing API keys stay pinned to their current version and are unaffected.

**Why it matters:** You can adopt `2025-03-26` as a stable, supported version rather than a Beta. New API keys and requests that don't specify a version now use it automatically. If you stay on your current version, note that Peach maintains each older API version for one year after a new version reaches general availability; after that one-year window the older version is no longer supported, so plan to move to `2025-03-26` within a year of this release.

**How to use it:** Specify `2025-03-26` in your request version header, or set it on a new API key. Before moving an existing integration, review the breaking changes bundled into this version — including the renamed loan `fields` value, where `idsOnly` is deprecated in favor of `minimal`. See the [API versioning overview](/developer-tools/api-versioning).

#### New "fail the tape" option when loan tape data is missing

**Type:** New Feature
**Impact:** Informational
**Area:** Data & Reporting

**What:** Loan tape types support a new `actionOnMissingData` value, `failTape`. When a required loan snapshot is still missing after the tape worker's retry window, the entire loan tape record fails and nothing is delivered, rather than shipping a partial or reduced file. Records affected by this setting return `failTape: true` on the loan-tape data endpoint, distinct from the existing `excludeFromTape` behavior.

**Why it matters:** Lenders who would rather receive no tape than an incomplete one can enforce all-or-nothing delivery, avoiding reconciliation against a tape that silently dropped or blanked rows.

**How to use it:** Set `actionOnMissingData` to `failTape` on the loan tape type — you can enable it on loan tape types you already have as well as on newly created ones. Peach retries on its existing budget and, only if a snapshot is still missing, marks the tape record failed and skips delivery. `failTape` applies to loan tapes only; payment tapes never read snapshots and are unaffected.

### Bug Fixes

#### Line of credit autopay now debits the correct remaining amount due

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Loan Configuration

Fixed an issue where line-of-credit autopay could calculate a payment lower than the actual remaining amount due, which previously required manual correction. Autopay now draws the correct remaining amount due after a failed or partial payment.

#### Metro 2 Date of First Delinquency is no longer reported before the account open date

**Type:** Bug Fix
**Impact:** Informational
**Area:** Credit Reporting

Fixed an issue where the Metro 2 Date of First Delinquency (Field 25) could be reported with a date earlier than the account open date for migrated, already-delinquent loans — a value credit reporting agencies reject. The reported Date of First Delinquency is now floored at the account open date, so an impossible pre-open value is never emitted.

#### Final statement is generated when a loan is charged off by daily maintenance on its statement date

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance · Loan Lifecycle

Fixed an issue where an installment loan charged off by daily loan maintenance on its statement date did not generate that period's statement, which then permanently blocked the loan's final statement from being produced.

#### Collection agency assignment response returns the newly assigned agency's external ID

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations · Developer Tools

Fixed an issue where assigning a collection agency to a loan returned the previously assigned agency's `agencyExternalId` in the response, even though the assignment was saved correctly. The response now reflects the newly assigned agency.

#### Editing employees in the Admin Portal no longer fails when a manager is assigned

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue in the Admin Portal where opening an employee that had an assigned manager for editing silently cleared the Manager field, which then blocked saving unrelated changes such as the employee's job name. See the [Manage employees](/servicing-operations/admin-portal/admin-portal-employees) guide.

#### Inactive employees no longer appear in Manager Dashboard case assignment lists

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where inactive employees appeared in the Manager Dashboard dropdowns for assigning, reassigning, filtering, and escalating cases, allowing cases to be routed to employees who were no longer active.

## Week of July 20, 2026

This week adds a legacy closed date for Metro 2 credit reporting on migrated loans, includes `borrowerId` on `case.changed` webhook events, refines the SCRA loan-term agent tools, and fixes autopay scheduling, mail address validation, and transactions on migrated lines of credit.

### New Features

#### Provide a legacy closed date at migration for Metro 2 reporting

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Reporting

**What:** When migrating a loan, you can now supply a legacy closed date through the migration `creditReporting.dateClosed` field. Metro 2 Date Closed then reflects the date from your source system instead of only Peach's own close or payoff timing. This matters for migrated lines of credit that charge off immediately after migration.

**Why it matters:** Migrated loans that closed in a prior system previously reported a Peach-derived Date Closed, which could diverge from the historical record furnished to the bureaus. Supplying the source date keeps Metro 2 reporting consistent across the migration boundary.

**How to use it:** Include `creditReporting.dateClosed` in the migration payload. If omitted, Metro 2 Date Closed falls back to the loan's existing Peach-derived close date, so no action is required for loans that closed within Peach. Note that the migration `creditReporting` object now rejects undocumented fields rather than ignoring them.

### Improvements

#### `case.changed` webhook events now include `borrowerId`

**Type:** Improvement
**Impact:** Informational
**Area:** Servicing & Operations · Developer Tools

**What:** The `case.changed` webhook event and its events-API representation now include a top-level `borrowerId` when the case has an associated borrower. Previously, your integration had to parse the `jsonPatch` payload to recover the borrower.

**Why it matters:** Systems subscribed to `case.changed` can identify the borrower behind a case change directly from the event, restoring the convenience the deprecated `case.created` event provided without parsing patch data.

**How to use it:** Read `borrowerId` from the `case.changed` payload. The field is additive and backward compatible — it is omitted when the case has no associated borrower, so existing handlers continue to work unchanged.

#### Record declined purchases on closed and terminal draws

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** You can now create a purchase with `status` of `declined` on a draw in a terminal status (`chargedOff`, `paidOff`, or `canceled`). Previously these were rejected.

**Why it matters:** Declined card authorizations can be recorded for account history even after a line has closed, which keeps purchase records complete for reconciliation and audit. Declined purchases never post to the ledger, so recording one on a closed draw does not affect its balances.

**How to use it:** Submit the purchase with `status` set to `declined` as usual; no `force` flag is required. Non-declined purchases (for example, `settled`) on terminal draws remain rejected.

#### SCRA loan-term agent tools use inclusive start and end dates

**Type:** Improvement
**Impact:** Informational
**Area:** Statements & Compliance · Servicing & Operations

**What:** In the agent portal, the SCRA loan-term tools (Set and Manage) now treat start and end dates as inclusive, so a term's start date may equal its end date. For lines of credit, a custom end date is required (there is no "End of loan" option and no cap at the loan's end); installment loans keep the choice between "End of loan" and a custom date capped at the loan or schedule end. The "Send notice to borrower" option has been removed from the line-of-credit SCRA term forms, whose endpoints do not support it, and remains available for installment loan types.

**Why it matters:** Inclusive date handling removes off-by-one adjustments that previously shifted eligible date ranges, and the line-of-credit and installment flows now match how each product's term dates actually work.

**How to use it:** Set SCRA loan terms from the agent portal as usual. The date pickers now enforce the inclusive bounds automatically.

### Bug Fixes

#### Autopay `specificDays` no longer returns null when aligned to due dates

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where an autopay enrollment aligned to the loan's due dates returned `specificDays` as null, including when setup auto-aligned because the frequency and days already matched the loan's schedule. Autopay GET responses now report the loan's due-date pattern in `specificDays`, so you can read the scheduled days directly instead of inferring them.

See the [autopay guide](/payments/autopay) for configuration details.

#### Mail sends are validated for a complete recipient address before submission

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications

Fixed an issue where a mail send request with a partial recipient address (for example, city, state, and ZIP but no street address) was accepted and then failed later during delivery. The request now returns a `400` error identifying the missing `addressLine1` at submission time, so the failure surfaces immediately instead of after the letter is queued.

#### Transactions are rejected on the static draw of a migrated line of credit

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Loan Lifecycle

Fixed an issue where a transaction could be posted with a `drawId` referencing the static draw (the term used in the `400` message; also called the migration draw in the docs) created during line-of-credit migration. Posting to that draw now returns a `400` error ("Cannot create a transaction on a static draw"); payments that omit `drawId` or reference an active draw are unaffected.

See [Modifying data after migration](/loan-lifecycle/loc-migration/modifying-data-after-migration) for the constraints on the read-only migration draw.

## Week of July 13, 2026

This week lets you reopen paid-off lines of credit for post-closure corrections and fixes several statement, purchase, and portal issues.

### New Features

#### Reopen a paid-off line of credit or draw for post-closure corrections

**Type:** New Feature
**Impact:** Informational
**Area:** Loan Lifecycle · Developer Tools

**What:** You can now reopen a line of credit or draw that has transitioned to `paidOff` status by passing `force: true` to the reopen endpoints (`POST /people/{personId}/loans/{loanId}/reopen` and `POST /people/{personId}/loans/{loanId}/draws/{drawId}/reopen`). Previously, a `paidOff` line or draw could not be reopened at all.

**Why it matters:** Supports post-closure balance corrections — for example, applying a dispute resolution that arrives after the borrower has already paid off and closed the line.

**How to use it:** Set `force` to `true` in the reopen request body. Reopening a line with `force` also reopens its `paidOff` draws; reopening a single draw with `force` also reopens its parent line while leaving sibling draws unchanged. No permission beyond `loan:reopen` is required. See the [Loans API reference](/api-docs/api-public#tag/Loans).

### Improvements

#### The Send Message endpoint now validates the delivery channel

**Type:** Improvement
**Impact:** Informational
**Area:** Communications · Developer Tools

**What:** The Send Message endpoint (`POST /communicator/send`) now accepts only the channels it actually supports — `voice`, `email`, `text`, and `mail` — and rejects any other value with a `400` and a clear message. The `fax`, `chat`, `gui`, and `document` values are no longer part of the endpoint's contract.

**Why it matters:** Those four values were previously accepted by the schema but were never valid delivery channels for Send Message, so requests using them failed further downstream with a less clear error. The endpoint now rejects them immediately with an explicit message.

**How to use it:** Send `voice`, `email`, `text`, or `mail` as the `channel` value (individually or in an array). See the [Communicator API reference](/api-docs/api-public#tag/Communicator).

### Bug Fixes

#### Creating a purchase no longer returns a server error on invalid card data

**Type:** Bug Fix
**Impact:** Informational
**Area:** Credit Cards & Card Programs · Loan Lifecycle

Fixed an issue where creating a purchase on a line of credit returned a `500` server error when the card's address-verification (AVS) data contained certain invalid characters. See the [Line of Credit Purchases API reference](/api-docs/api-public#tag/Line-of-Credit-Purchases).

#### Payments backdated onto the statement date no longer create a spurious statement adjustment

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance

Fixed an issue where a payment backdated from the statement date into the prior statement period could produce a spurious payment adjustment on the following statement. The same fix also corrects an incorrect interest adjustment that could appear for that period.

#### CRM SMS conversations no longer crash on newer versions of Chrome

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations · Communications

Fixed an issue where opening an SMS conversation in the CRM could crash the page on Chrome 150 and later.

#### Card declines with unrecognized reason codes now record as failed transactions

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where a card payment declined with a reason code Peach had not yet mapped failed to record as a failed transaction and instead produced a processing error that retried. These declines now record as a failed transaction with a generic decline reason.

#### `purchase.dispute.updated` now reports `isPastPurchaseDispute` consistently

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle · Developer Tools

Fixed an issue where the `purchase.dispute.updated` webhook event could report `isPastPurchaseDispute` as `false` on a metadata-only update (such as an `externalId` change) even though the event carried the original draw in `drawId`. `isPastPurchaseDispute` is now derived the same way as on `purchase.dispute.created`, so it stays consistent with `drawId` on every update.

#### Corrected the documented response shape for the promo programs list endpoint

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools · Loan Lifecycle

Fixed the API reference for the promo programs list endpoint, where the `PromoProgramPaging` response incorrectly documented `data` as an object wrapping a `promoPrograms` array. The reference now correctly shows `data` as a direct array of `PromoProgramResult`, matching the response the API has always returned.

## Week of July 6, 2026

This week adds richer webhook payloads and migrated-statement PDF controls, aligns the line-of-credit SCRA endpoints with their public contract, and fixes several payment and credit-reporting issues.

### New Features

#### Attach or replace the statement PDF on a migrated line-of-credit statement

**Type:** New Feature
**Impact:** Informational
**Area:** Statements & Compliance · Loan Lifecycle

**What:** You can now attach or replace the statement PDF on a migrated past-period line-of-credit statement (statements where `isExternal` is `true`) by sending a `documentDescriptorId` to `PUT /people/{personId}/loans/{loanId}/statements/{statementId}`, even when the loan type is configured to generate and send its own PDFs.

**Why it matters:** Migrated statements often need the historical PDF that was produced by the prior servicer. Previously the PDF on these statements could only be set when the loan type had `isCreateAndSendPDF` turned off, which blocked clients whose loan type generates PDFs from supplying the original migrated document.

**How to use it:** Upload the document, then pass its `documentDescriptorId` on `PUT /people/{personId}/loans/{loanId}/statements/{statementId}` for a statement with `isExternal` set to `true`.

#### Outgoing webhook payloads now include a `createdAt` timestamp

**Type:** New Feature
**Impact:** Informational
**Area:** Developer Tools

**What:** Every outgoing webhook payload now includes a `createdAt` timestamp in addition to the existing `effectiveAt` timestamp.

**Why it matters:** When two events share the same `effectiveAt` — for example, backdated `loan.statuschanged` events — you can now use `createdAt` to order them by when they were actually recorded.

**How to use it:** Read the new `createdAt` field from the webhook payload. It applies automatically to all outgoing webhooks — no configuration needed.

#### New Docs Hub page: how multiple cards are modeled on a line of credit

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Cards & Card Programs · Loan Lifecycle

**What:** A new conceptual page in the Docs Hub explains how multiple cards are modeled on a single line of credit.

**Why it matters:** The page gives a single reference for how cards relate to a line-of-credit loan, so teams designing card programs can understand the model before integrating.

**How to use it:** Read the new page in the Docs Hub. Applies automatically — no action needed.

### Improvements

#### Line-of-credit SCRA endpoints now match their public contract and always send Borrower notices

**Type:** Improvement
**Impact:** Informational
**Area:** Statements & Compliance · Developer Tools

**What:** The line-of-credit SCRA payment-plan endpoints (`/people/{personId}/loans/{loanId}/loc-payment-plan-scra`) no longer accept the `locScraSendNotice` query parameter on the DELETE or a `sendNotice` field in the create and update request bodies, and their create and update responses now return only `isLocked`, `paymentFrequency`, and `specificDays` rather than the full `schedule` object. Borrower notices always fire on the paths that previously fired them.

**Why it matters:** Neither the `sendNotice`/`locScraSendNotice` inputs nor the `schedule` object were part of the public API specification, so this change brings the endpoints' behavior in line with their documented contract. Borrower SCRA notices now fire reliably on these paths rather than depending on an undocumented input.

**How to use it:** No action is required if you followed the public specification. If you were sending the undocumented `sendNotice`/`locScraSendNotice` inputs, you can stop — they are now ignored, and notices always fire. Read `isLocked`, `paymentFrequency`, and `specificDays` from the create and update responses.

### Bug Fixes

#### Over-limit line-of-credit draws no longer show a minimum due greater than the new balance

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance

Fixed an issue where a line-of-credit statement could show a `minimumDueAmount` greater than the statement's `newBalanceAmount` when an over-limit draw used included-over-limit amounts.

#### Metro 2 records assemble correctly for reported and skipped appendage segments

**Type:** Bug Fix
**Impact:** Informational
**Area:** Credit Reporting

Fixed Metro 2 record assembly so that a reported-but-absent appendage segment (K1, K2, or L1) now emits its two-byte segment identifier followed by blank-fill, while a skipped segment is omitted entirely and the record, header, and trailer lengths stay consistent.

#### Backdated succeeded transactions now populate `succeededAt`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where a backdated succeeded transaction could be created without a `succeededAt` timestamp. The `succeededAt` field is now populated when a succeeded transaction is backdated, so it is present in the transaction API response.

#### `autopay.schedule.changed` can now be selected when configuring webhook subscriptions

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Developer Tools

Fixed an issue where the `autopay.schedule.changed` event could not be selected when configuring a webhook subscription, even though the event was already being emitted. It is now a valid subscription event type.

#### Communicator template endpoints no longer return a server error on older API versions

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications · Developer Tools

Fixed an issue where calling the communicator template endpoints with an older `Peach-Version` returned a `500` server error. Those requests now succeed.

## Week of June 29, 2026

This week adds line-of-credit migration and card purchase controls, a promo program status change requiring action, and fixes to autopay, disputes, and payment tapes.

### Breaking Changes

#### Promo program type status now uses `inactive` and `archived` instead of `deprecated`

**Type:** Breaking Change
**Impact:** Action Required
**Area:** Loan Configuration

**What's changing:** Promo program type status now uses the values `inactive` and `archived` in place of the former `deprecated` value. Creating or updating a promo program type with `deprecated` or `archived` is rejected. Sending `DELETE` on a promo program type now archives it: a type must first be set to `inactive` before it can be archived, and an archived type can no longer be edited. Listing promo program types with `GET /companies/{companyId}/promo-program-types` now supports a `status` filter along with `limit`, `offset`, and `sortBy`.

**Who is affected:** Clients that create, update, delete, or list promo program types and that read or write the `status` value. Clients that store the legacy `deprecated` value will see it treated as `inactive` when filtering.

**What you need to do:**

1. Replace any use of `deprecated` with `inactive` when setting promo program type status.
2. To retire a type, set it to `inactive`, then send `DELETE` to archive it.
3. Stop editing types once they are archived.


### Deprecations

#### The `status` field on communicator template versions is removed on API version `2025-03-26`

**Type:** Deprecation
**Impact:** Recommended Action
**Area:** Developer Tools
**Deprecated on:** 2026-07-03
**Removal date:** Removed on API version `2025-03-26` (Beta); still present on the default `2023-11-29` version.

**What's deprecated:** The non-operational `status` field on communicator template versions is removed from the create, update, and read payloads on API version `2025-03-26`, which is currently a Beta (non-default) version. On the default `2023-11-29` version the field is still returned and accepted.

**What to use instead:** Stop sending and reading `status` on template versions. The field had no operational effect, so no replacement is required.

**Who should migrate:** Clients calling the communicator template version endpoints on API version `2025-03-26`.

**Timeline:**

- Available today: `status` continues to be accepted and returned on the default `2023-11-29` version.
- On API version `2025-03-26` (Beta): `status` is no longer present on create, update, or read payloads.


### New Features

#### Migrate paid-off line-of-credit accounts

**Type:** New Feature
**Impact:** Informational
**Area:** Loan Lifecycle · Loan Configuration

**What:** You can now migrate a line-of-credit account that was already paid off in another system by setting `postMigrationLoanStatus` to `paidOff` and supplying a `paidOffDate` on the migration period. A line migrated this way is static and does not transition to any other status.

**Why it matters:** Previously, paid-off lines could not be represented during migration, so historical closed accounts could not be brought onto Peach cleanly.

**How to use it:** On the migration period, set `postMigrationLoanStatus=paidOff` and provide `paidOffDate` (a date after the line activation date and before the migration cutoff date). Do not pass `obligation`, `gracePeriod`, or `balances` when the status is `paidOff`.

#### Record over-limit or post-closure card purchases with `forceOverLimit` and `forceIfClosed`

**Type:** New Feature
**Impact:** Informational
**Area:** Loan Lifecycle · Developer Tools

**What:** The create purchase and update purchase endpoints on line-of-credit draws now accept the `forceOverLimit` and `forceIfClosed` query parameters. These let you record over-limit or post-closure card activity independently, rather than relying on the all-or-nothing `force` parameter.

**Why it matters:** You can now permit exactly one of the two override conditions instead of bypassing all purchase validation at once, giving finer control over which non-standard purchases you record.

**How to use it:** Pass `forceOverLimit=true` or `forceIfClosed=true` on the create or update purchase request. If `force=true` is passed, both parameters are ignored. Using these parameters requires the `draw.purchase:force` permission.

### Improvements

#### Expected payments can report a `singleTerm` payment frequency

**Type:** Improvement
**Impact:** Informational
**Area:** Payments · Developer Tools

**What:** Expected-payments responses can now report `singleTerm` as the `paymentFrequency`, alongside the existing `weekly`, `everyTwoWeeks`, `twiceMonthly`, and `monthly` values.

**Why it matters:** Single-term loans previously had no matching frequency value in the expected-payments response, so integrations reading `paymentFrequency` for those loans could not classify them accurately.

**How to use it:** Applies automatically — no action needed. Handle `singleTerm` as a possible value when reading `paymentFrequency` on expected-payments responses.

### Bug Fixes

#### Backdated payments now appear on the payment tape for the date they were recorded

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Data & Reporting

Fixed an issue where a backdated payment created as succeeded in a single request could be assigned to the wrong day and miss the payment tape for the date it was recorded.

#### Autopay on a line of credit no longer overcharges on the due date

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Loan Lifecycle

Fixed an issue where dynamic autopay on a line of credit could debit the full expected payment on the due date instead of the remaining amount due after post-statement repayments, resulting in an overcharge.

#### Dispute webhooks now fire for purchases carried over during a line-of-credit migration

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools · Loan Lifecycle

Fixed an issue where the `purchase.dispute.created` and `purchase.dispute.updated` webhooks were never delivered for purchases that were carried over during a line-of-credit migration.

## Week of June 22, 2026

This week deprecates a legacy card field on line of credit purchases and fixes several line of credit servicing and credit reporting issues.

### Deprecations

#### The `purchaseDetails.externalCardId` field is deprecated for line of credit purchases

**Type:** Deprecation
**Impact:** Recommended Action
**Area:** Credit Cards & Card Programs · Payments
**Deprecated on:** 2026-06-22

**What's deprecated:** The `purchaseDetails.externalCardId` field on the Create and Update Purchase requests for a line of credit is deprecated. It continues to work today.

**What to use instead:** Use the top-level `cardId` field instead. If both `cardId` and `purchaseDetails.externalCardId` are supplied in the same request, the top-level `cardId` takes precedence and `externalCardId` is ignored.

**Who should migrate:** Any client that sets `purchaseDetails.externalCardId` when creating or updating line of credit purchases.

### Bug Fixes

#### Past authorized purchases now count toward available credit on migrated lines of credit

**Type:** Bug Fix
**Impact:** Informational
**Area:** Credit Cards & Card Programs · Loan Lifecycle

Fixed an issue where authorized purchases made before a line of credit was migrated were not reflected in the `openToBuyAmount`, `utilizationAmount`, and `authorizedAmount` values.

#### Creating an SCRA record on a line of credit now requires an end date

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Statements & Compliance

Fixed an issue where creating an SCRA record on a line of credit accepted a missing or null `endDate`. Requests that omit `endDate` or send it as null now return a `400` error, and the API reference has been corrected to mark `endDate` as required for line of credit SCRA.

#### Final line of credit statements no longer show fees out of sync with a zero balance

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance · Servicing & Operations

Fixed an issue where the final statement for a paid-off or charged-off line of credit could show fees and a `minimumAmountDue` that were out of sync with a zero balance. This affected lines of credit configured with `obligationFulfilledCalculation=postStatement` whose payoff or charge-off skipped daily maintenance.

#### Credit reporting resumes after a payoff is reversed

**Type:** Bug Fix
**Impact:** Informational
**Area:** Credit Reporting

Fixed an issue where credit reporting stayed permanently stopped after a loan's payoff was reversed. When a payoff is reversed within the same calendar month, credit reporting for that loan now resumes.

## Week of June 15, 2026

This week adds one-call template activation, alongside five fixes to payments, communications, and API reliability.

### New Features

#### Create and activate a communication template version in a single call

**Type:** New Feature
**Impact:** Informational
**Area:** Developer Tools

**What:** You can now create and activate a communication template version in one request by passing `activate: true` in the body of `POST /communicator/templates`. Previously, activating a new version required a separate call to the activate endpoint.

**Why it matters:** Removes a round-trip from template promotion workflows, so a new version can go live in a single step.

**How to use it:** Set `activate: true` in the request body when creating the version. This requires the `communicator.template:activate` permission in addition to `communicator.template:create`. Without `activate: true`, the version is created inactive as before.

### Improvements

#### Identify an at-origination dynamic fee by `dynamicFeeTypeId`

**Type:** Improvement
**Impact:** Informational
**Area:** Loan Configuration

**What:** When setting at-origination dynamic fees on a loan, you can now identify a fee by `dynamicFeeTypeId` in addition to `apiName`. If both are provided, `apiName` takes precedence.

**Why it matters:** Lets you reference a dynamic fee by its stable identifier rather than only by name, which is useful when names are not unique or convenient to track on your side.

**How to use it:** Pass `dynamicFeeTypeId` on the dynamic fee entry when creating the loan. Existing requests that use `apiName` continue to work unchanged.

### Bug Fixes

#### Malformed `check` payment instruments now report the actual missing fields

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where creating a `check` payment instrument on `POST /people/{personId}/payment-instruments` with missing required fields returned a `400` that implied the `check` `instrumentType` was unsupported. The error now names the actual missing required fields, such as `checkNumber`, so you can correct the request directly.

#### Overpayments on charged-off loans are now rejected

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments · Servicing & Operations

Fixed an issue where a payment on a charged-off loan whose loan type has `paymentAllowedWhenChargedOff` set to `true` could exceed the outstanding balance. Such overpayments are now rejected with a `400` and the message "Amount exceeds outstanding balance."

#### Invalid Twilio credentials during task-history sync now return a `409`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations · Developer Tools

Fixed an issue where invalid or expired Twilio credentials during task-history sync returned a generic server error. The request now returns a `409` with `errorType` `TwilioCredentialsInvalid`, so you can distinguish a credentials problem from other failures.

#### Payment date in transaction status notifications now shows the correct calendar day

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations · Payments

Fixed an issue where the `paymentDate` in transaction status notifications could appear as a full timestamp instead of a date, or show the wrong calendar day for lenders in time zones behind UTC.

#### Backdating a transaction on a migrated installment loan no longer returns a server error

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations · Loan Configuration

Fixed an issue where backdating a transaction on a migrated installment loan returned a `500` server error.

## Week of June 8, 2026

This week adds single-call past-dated transactions and clearer settlement docs, plus fixes to loan tape delivery and an API error message.

### New Features

#### Create a past-dated transaction in a single API call on active loans

**Type:** New Feature
**Impact:** Informational
**Area:** Payments

**What:** You can now create a past-dated transaction on an active loan in a single `POST` call by supplying `effectiveDate` and `effectiveTimeOfDay`, instead of the previous two-step create-then-backdate flow. This applies to external one-time payments, down payments, and service credits.

**Why it matters:** Removes a round trip for recording transactions with an effective date in the past, simplifying migration and backfill integrations.

**How to use it:** On an active (non-migrating) loan, pass `effectiveDate` (today or in the past) together with `effectiveTimeOfDay`, leave `scheduledDate` empty, and set `isExternal` to `true`. Use `sync=true` to wait for the transaction to finish processing.

### Improvements

#### Settlement and reconciliation API documentation clarified

> **Correction — 2026-08-14:** BYOB (Bring Your Own Bank) settlements, in production since 2026-08-03, superseded the behavior described in this entry. Automated investor settlement and settlement ACH files are **no longer** limited to the Peach-managed payment processor — companies using their own bank now receive them too. The original statements below are preserved as first published; a full release note follows.


**Type:** Improvement
**Impact:** Informational
**Area:** Data & Reporting · Payments

**What:** The settlement and reconciliation API documentation now explains that automated investor settlement applies only when Peach manages the payment processor, and it documents the Funding Instruments endpoints and related fields.

**Why it matters:** Clarifies for integrators that `isSettlementRequired` behavior and settlement ACH files (`isSettlement` on the ACH File resource) are produced only for the Peach payment processor; companies using a third-party processor do not receive them.

**How to use it:** Applies automatically — no action needed. Review the Funding Instruments and ACH File reference documentation if you reconcile settlement activity.

### Bug Fixes

#### Loan Tape generation now fails instead of shipping a partial tape

**Type:** Bug Fix
**Impact:** Informational
**Area:** Data & Reporting

Fixed an issue where a Loan Tape could be delivered with truncated data while still being marked complete. A data-retrieval failure during Loan Tape generation now fails the record instead of producing a partial Loan Tape.

#### Duplicate external ID error message no longer contains an unexpected character

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where the duplicate external ID error message contained an unexpected em dash character. The message now reads `External IDs must be unique: '{id}' already exists.`

## Week of June 1, 2026

This week expands custom communication templates, adds card identifiers to purchase events and disputes, and fixes several payment and agent-facing issues.

### New Features

#### Configure up to 100 custom communication templates

**Type:** New Feature
**Impact:** Informational
**Area:** Communications

**What:** You can now configure up to 100 custom communication templates, using the `custom1` through `custom100` interaction subject values. Previously the ceiling was 20 (`custom1` through `custom20`).

**Why it matters:** Lenders running a large number of tailored borrower communications no longer hit the 20-template limit and can manage the full set through a single interaction subject range.

**How to use it:** Reference any subject from `custom1` to `custom100` when configuring an interaction template. The additional values (`custom21`–`custom100`) are available on all interaction endpoints that accept an interaction subject.

#### Backdate external check payments with an effective date

**Type:** New Feature
**Impact:** Informational
**Area:** Payments · Agent Experience

**What:** When applying an external check payment in the portal, you can now set an effective date to backdate the transaction. The date can be any day from the loan start date through today.

**Why it matters:** Agents recording checks received earlier can apply them on the date they were actually received, so balances, interest, and payment history reflect the correct timing rather than the entry date.

**How to use it:** In the Apply External Check flow, choose an effective date within the allowed range before submitting. Leaving it at today preserves the prior behavior.

#### Show a TCPA disclosure note when borrowers edit their phone number

**Type:** New Feature
**Impact:** Informational
**Area:** Borrower Portal · Loan Configuration

**What:** You can now display a fixed disclosure note (such as a TCPA consent notice) on the Borrower Portal when a borrower changes their primary or personal phone number, using the new `phoneDisclosureNote` company UI setting.

**Why it matters:** Lenders can surface required phone-consent language at the moment a borrower updates their number, supporting TCPA compliance without a custom portal build.

**How to use it:** Set `phoneDisclosureNote` to `shown` in your company UI configuration. Absent or null keeps the note hidden, which remains the default.

### Improvements

#### Purchase events now include the card used

**Type:** Improvement
**Impact:** Informational
**Area:** Webhooks & Events · Card Servicing

**What:** All `purchase.*` events now include an optional `cardId` identifying the card used for the purchase.

**Why it matters:** Clients consuming purchase events can attribute each purchase to a specific card without a follow-up lookup, simplifying reconciliation and downstream routing.

**How to use it:** Read the `cardId` field from any `purchase.*` event payload. It is optional and may be absent when no card is associated with the purchase. Applies automatically — no action needed.

#### Filter purchase disputes by card and see the card on dispute responses

**Type:** Improvement
**Impact:** Informational
**Area:** Card Servicing · Disputes

**What:** Purchase dispute responses now include a read-only `cardId`, and the draw- and line-of-credit-scoped dispute list endpoints accept an optional `cardIds` filter.

**Why it matters:** Clients can narrow dispute lists to specific cards and identify the card behind each dispute directly from the response, without cross-referencing other resources.

**How to use it:** Pass `cardIds` when listing purchase disputes to scope the results. If none of the supplied card identifiers resolve, the filter is not applied and the full list is returned.

### Bug Fixes

#### Line-of-credit migration submissions with a partially paid prior period are no longer rejected

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Servicing

Fixed an issue where a line-of-credit migration submission was rejected when the pre-migration period was partially paid but a `migratedOverdueAmount` was still reported. A `migratedOverdueAmount` equal to the unpaid portion of the `minimumAmountDue` is now accepted.

#### Saving an already-recorded call recording returns a clear error instead of a server error

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications · Agent Experience

Fixed an issue where saving a call recording that had already been recorded returned a `500` server error. The request now returns a `400` response with a message indicating the call has already been recorded.

#### Bulk email to all impacted borrowers on a supercase now targets the correct recipients

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications · Agent Experience

Fixed an issue where sending a bulk email to all impacted borrowers across a supercase could reach the wrong recipient population.

## Week of May 25, 2026

This week adds a new debt-settlement service credit type, expands card and purchase API filtering and pagination, and fixes bank-linking and support-link issues.

### New Features

#### Issue a "Settlement of debt - no loss reported" service credit

**Type:** New Feature
**Impact:** Informational
**Area:** Servicing & Operations

**What:** The Issue Service Credit action in the agent portal now offers a new service credit type, "Settlement of debt - no loss reported" (`settlementOfDebtNoLoss`). Help text on the action explains how it differs from `settlementOfDebt` and how the credit applies to line-of-credit draws.

**Why it matters:** Lets agents record a debt settlement that closes out an outstanding balance without reporting a loss, keeping the distinction from a standard settlement of debt clear at the point of issuance.

**How to use it:** In the agent portal, open the Issue Service Credit action for a loan and choose "Settlement of debt - no loss reported" as the service credit type. The `settlementOfDebtNoLoss` service credit type is available in the API service credit type enum.

### Improvements

#### Filter purchases by card with the new `cardIds` parameter

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Cards & Card Programs · Loan Lifecycle

**What:** You can now filter purchase list and purchase timeline results by card using the new `cardIds` query parameter. Each value accepts either a Peach card id (`CD-...`) or an external id (`ext-...`); ids that do not resolve are ignored.

**Why it matters:** Lets you scope purchases and their timelines to specific cards without retrieving the full result set and filtering client-side.

**How to use it:** Pass one or more ids in the `cardIds` query parameter on the purchase list and purchase timeline endpoints. Omit the parameter for no filtering.

#### Paginate the Get Cards endpoint

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Cards & Card Programs · Developer Tools

**What:** The Get Cards endpoint (`GET /people/{personId}/loans/{loanId}/cards`) now supports pagination and sorting through the `limit`, `offset`, `startingAfter`, `endingBefore`, and `sortBy` query parameters, and returns a paged response.

**Why it matters:** Lets you retrieve cards in controlled pages and order results (for example, by `createdAt`) instead of receiving the entire card list in one response.

**How to use it:** Add the `limit`, `offset`, `startingAfter`, `endingBefore`, or `sortBy` query parameters when calling `GET /people/{personId}/loans/{loanId}/cards`.

#### Access training documentation and release notes from the agent portal

**Type:** Improvement
**Impact:** Informational
**Area:** Servicing & Operations

**What:** The agent portal now links out to the external Docs Hub for training documentation and adds a new Release notes link in the sidebar and user menus. The former in-app training and documentation pages have been replaced by these external links.

**Why it matters:** Points agents to a single, continuously updated documentation source rather than in-app pages that could fall out of date.

**How to use it:** Select the training documentation or Release notes links in the agent portal sidebar or user menu.

### Bug Fixes

#### Bank linking no longer fails for lenders using their own Plaid credentials

**Type:** Bug Fix
**Impact:** Informational
**Area:** Borrowers

Fixed an issue where lenders using their own Plaid credentials could not start bank linking because creating the Plaid Link token failed with a "link_customization_name was not found" error. Peach's default link customization is now applied only for lenders on Peach's own Plaid credentials, so lenders on their own credentials no longer hit this error.

#### Peach Support link in the agent portal now opens Zendesk

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where selecting the Peach Support link in the agent portal sidebar opened a blank page instead of the Zendesk support site.

## Week of May 18, 2026

This week reshapes the Cards and Purchases APIs, reorganizes the Docs Hub by domain, and enforces transaction idempotency.

### New Features

#### Card `status` is promoted to a top-level field with a new five-value enum

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** The Card object's top-level `status` field is now backed by the card status enum with five lender-owned values: `Active`, `Inactive`, `Blocked`, `Closed`, `Expired`. This value is stored separately from the existing issuer-driven internal status (which remains available under `cardDetails.status`). Card list and search endpoints accept the new top-level `status` as a filter parameter.

**Why it matters:** Separates the lender-controlled lifecycle state of a card from the issuer-driven operational state. Previously the two were conflated under a single ten-value enum, making it harder to reason about which transitions you control versus which Marqeta/Galileo/Lithic/Qolo drives.

**How to use it:** Read `status` at the top level for the lender-owned state; read `cardDetails.status` when you need the issuer-driven operational view. Pass `status` as a query parameter on list/search endpoints to filter cards by lender state. See the [Card object reference](/api-docs/api-public#tag/Cards).

#### Top-level `cardId` on Create/Update Purchase, with a `validation.cardIdMissing` warning

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** Create Purchase and Update Purchase requests now accept an optional top-level `cardId` field, persisted on `loan_purchases` via a new nullable foreign key. When `cardId` is omitted, the response includes a soft `validation.cardIdMissing` warning rather than rejecting the request.

**Why it matters:** Lets you associate a purchase with the specific card used for it at create or update time, instead of inferring the card after the fact. The soft-warning pattern gives clients a deprecation runway to start sending `cardId` before any future hard requirement.

**How to use it:** Include `cardId` (as a `CD-...` public ID) on `POST` and `PATCH` to the Purchase endpoints. Existing flows that omit `cardId` continue to work; if you see `validation.cardIdMissing` in the response warnings, update your purchase-creation flow to include the card. See the [Purchases API reference](/api-docs/api-public#tag/Line-of-Credit-Purchases).

#### Purchase status can transition from `authorized` to `declined`

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** The Update Purchase endpoint now accepts a status transition from `authorized` to `declined`. Declined purchases are treated like canceled purchases for ledger and credit-utilization purposes — no ledger write, credit hold released.

**Why it matters:** Lets you record a post-authorization decline (for example, a fraud signal arriving after initial authorization) without having to cancel-and-recreate, preserving the authorization audit trail.

**How to use it:** `PATCH` the purchase with `status: "declined"` from an `authorized` state. The transition is also documented in the OpenAPI spec. See the [Purchases API reference](/api-docs/api-public#tag/Line-of-Credit-Purchases).

#### New `company.config.ui.phoneDisclosureNote` field controls Borrower Portal phone-change disclosure

**Type:** New Feature
**Impact:** Informational
**Area:** Borrowers

**What:** A new optional `phoneDisclosureNote` field on `company.config.ui` controls whether a fixed disclosure note is shown in the Borrower Portal when a borrower changes their phone number.

**Why it matters:** Lets you meet jurisdiction-specific phone-disclosure requirements without a code change, by toggling the note per-company.

**How to use it:** Set `company.config.ui.phoneDisclosureNote` via the company configuration endpoint.

### Improvements

#### `Purchase.cardId` is consistently returned across all Purchase read endpoints

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** Every Purchase read endpoint — single-purchase, list, and embedded responses — now returns `cardId` as a `CD-...` public ID (or `null` if no card is associated). The OpenAPI schema explicitly states this contract, and the change is locked in by a new test suite covering every read endpoint.

**Why it matters:** Lets you rely on `cardId` being present in any Purchase response shape without endpoint-specific conditional logic.

**How to use it:** No action needed — applies automatically. If your integration previously branched on whether `cardId` was present based on which endpoint returned the purchase, that branching can be removed.

#### Request validation improved across several configuration endpoints

**Type:** Improvement
**Impact:** Informational
**Area:** Developer Tools

**What:** Request validation on the employees, loan type create/update, payment instrument create, borrower campaigns, and promo programs endpoints now produces more consistent, field-level error messages. Validation failures return `400` responses with structured error messages identifying the specific fields and constraints that failed.

**Why it matters:** Produces clearer, more actionable error messages when a request to these endpoints contains invalid data.

**How to use it:** No action needed — valid requests continue to work unchanged. If you have integration tests that match on specific error message text from these endpoints, the messages may have shifted shape; the HTTP status codes are unchanged.

#### Docs Hub reorganized into ten domain-first sections

**Type:** Improvement
**Impact:** Informational
**Area:** Developer Tools

**What:** The Peach Docs Hub has been restructured around ten domain sections — Getting Started, Developer Tools, Borrowers, Payments, Loan Lifecycle, Credit Reporting, Communications, Data & Reporting, Servicing & Operations, and Release Notes — replacing the previous twelve product-pillar sections. The homepage has been redesigned with a hero, goal-oriented tiles, and an all-sections list; the top navbar now exposes Docs, Get Started, API Reference, and Release Notes as primary destinations.

**Why it matters:** Content is now organized by what you're trying to do (the domain) rather than what Peach calls the internal product pillar that delivers it, making it easier to find documentation for a task without needing to know Peach's internal product taxonomy.

**How to use it:** Browse from the new homepage or the redesigned top navbar. **If you have bookmarks or internal links pointing to specific Peach documentation pages, expect to update them** — the new structure organizes content by domain rather than the previous product-pillar layout, so URLs for many individual pages have changed. The API reference itself is unchanged.

### Bug Fixes

#### `POST` transactions returns `409 DuplicateApiError` on duplicate `externalId` within the same company

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Payments · Developer Tools

Fixed an issue where `POST` transactions accepted duplicate `externalId` values within the same company, silently creating multiple transaction records for what should have been a single idempotent request. `POST` requests submitting a duplicate `externalId` now return `409 DuplicateApiError`. The constraint is enforced for transactions created on or after 2026-05-13, leaving historical duplicates in place — no remediation is needed for past data.

If your transaction-creation integration relies on `externalId` as an idempotency key — the field's intended purpose — treat `409` from this endpoint as a successful no-op (the prior transaction with that `externalId` already exists) rather than as a transient conflict to retry. Submitting the same `externalId` twice was always semantically wrong; the constraint now enforces it explicitly.

#### Preview-mode `POST /unfreeze` no longer emits webhooks for rolled-back loan-status events

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle · Developer Tools

Fixed an issue where `POST /unfreeze` requests with `previewMode: true` could fire webhooks for `loan_status_changed_event` rows that were rolled back as part of the preview, leaving subscribers receiving webhook payloads whose `eventId` had no matching row in the events table.

#### `POST /api/auth/token` returns `400` when `username` is missing

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where calling `POST /api/auth/token` without a `username` (or with `username: null`) returned a server error during credential normalization. The endpoint now returns `400 "Must include username"`.

#### Multipart form-data uploads no longer crash in request validation when middleware has pre-read the body

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where file-only `multipart/form-data` uploads could fail with a server error during request validation when an upstream middleware had pre-read the raw request body. The validator now handles pre-read request bodies correctly for form content types.

#### `GET /companies/{companyId}/users` returns `400` (not `500`) for malformed query strings

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where `GET /companies/{companyId}/users` requests with a malformed query string — for example `?userType=Agent?page=1`, where `?` was mistakenly used instead of `&` between query parameters — returned a `500 Internal Server Error`. The endpoint now returns `400 Bad Request` for malformed query strings of this shape.

## Week of May 11, 2026

This week brings new Card attributes and credit-agency tooling, plus loan-tape and statement refinements and fixes across statements, payments, and cases.

### New Features

#### Card object adds an `isExternal` attribute

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Cards & Card Programs

**What:** Card objects now include a boolean `isExternal` attribute identifying whether a card was issued outside Peach's card-issuer integrations. The field defaults to `true` on existing cards and on new cards created without explicitly setting it, preserving prior behavior.

**Why it matters:** Lets you distinguish externally-issued cards from cards issued through Peach's Marqeta, Galileo, Lithic, or Qolo integrations when reading Card responses, without inferring from issuer-specific fields.

**How to use it:** Read `isExternal` on any Card response. If you explicitly create a card with `isExternal: false`, the request must include the issuer-specific identifier and token fields that the corresponding card-issuer integration requires; the API now validates these on writes when `isExternal` is false. Contact your Peach implementation team for the issuer-specific identifier and token fields required when setting `isExternal: false`. Existing create/update flows that omit `isExternal` continue to work unchanged. See the [Card object reference](/api-docs/api-public#tag/Cards).

#### New service credit type `settlementOfDebtNoLoss`

**Type:** New Feature
**Impact:** Informational
**Area:** Payments · Credit Reporting

**What:** A new service credit type, `settlementOfDebtNoLoss`, is available on transaction creation and serialization. The type extends the `serviceCreditTypes` and `serviceCreditTypesForCreate` enums in the public OpenAPI spec and is supported by Metro2 reporting via the "AU" special comment.

**Why it matters:** Distinguishes settlement-of-debt transactions that do not result in lender loss from those that do (`settlementOfDebt`), giving you a cleaner audit signal for charge-off reconciliation and credit reporting.

**How to use it:** Pass `creditType: "settlementOfDebtNoLoss"` when creating a service credit transaction. The value flows through to Metro2 reporting and triggers the AU special comment on the next bureau submission. See the [Service Credit Types reference](/api-docs/api-public#tag/Transactions).

#### New endpoint to regenerate SSH keys for credit agencies

**Type:** New Feature
**Impact:** Informational
**Area:** Credit Reporting

**What:** A new `POST /companies/{companyId}/credit-agencies/{creditAgencyId}/regenerate-ssh-keys` endpoint rotates a credit agency's SFTP SSH keypair when `sftpAccessMethod` is `keys`, returning the updated credit agency object with the new key references. The response exposes `sftpSSHPeachPublicKey` and `sftpSSHPeachPrivateKey` as read-only fields.

**Why it matters:** Lets you rotate credit-bureau SFTP credentials on a normal cadence (or in response to a suspected compromise) without involving Peach support, supporting standard key-rotation hygiene for credit reporting integrations.

**How to use it:** `POST` to the endpoint with no body. The response includes the regenerated key references; share the new public key with the receiving bureau through their normal key-update process. Requires the same admin-scoped authorization as other credit-agency endpoints. See the [Credit Agencies API reference](/api-docs/api-public#tag/Credit-Agencies).

#### New endpoints to view and bulk-update dynamic fee type caps per loan type

**Type:** New Feature
**Impact:** Informational
**Area:** Loan Configuration

**What:** Two new endpoints, `GET` and `PATCH /companies/{companyId}/loan-types/{loanTypeId}/dynamic-fee-types/caps`, let you read and bulk-update cap-logic configuration across all dynamic fee types on a loan type in a single request. The `GET` accepts an optional `capType` query parameter to filter results by cap category.

**Why it matters:** Replaces the previous per-fee-type configuration loop with a single batch operation, useful when you're configuring or auditing fee caps across many dynamic fee types on the same loan product.

**How to use it:** `GET` returns the list of dynamic fee types on the loan type with their current `capLogic`; `PATCH` accepts a list of `{ dynamicFeeTypeId, capLogic }` entries to apply in one transaction.

#### Loan tape records use `null` status to indicate in-progress generation

**Type:** New Feature
**Impact:** Informational
**Area:** Data & Reporting

**What:** The `LoanTapeRecord.status` field is now nullable. A freshly-created record returns `status: null` to indicate that generation is in progress; the worker writes the terminal `Succeeded`, `Failed`, or `Created` state when generation completes. Previously the server defaulted new records to `Failed`, which made freshly-triggered jobs look failed while still running.

**Why it matters:** Lets you correctly distinguish "still generating" from "generation failed" when polling for loan tape status, instead of treating an in-progress record as a failed one.

**How to use it:** Handle `status: null` as the in-progress state in your polling logic; treat `Failed` only when the field is explicitly set to that value. The OpenAPI spec documents the null state alongside the existing enum values. See the [Loan Tape Records reference](/api-docs/api-public#tag/Loan-Tapes).

### Improvements

#### `GET /companies/{companyId}/loan-tapes/{loanTapeId}/records` is now documented in the OpenAPI spec

**Type:** Improvement
**Impact:** Informational
**Area:** Data & Reporting · Developer Tools

**What:** The `GET /companies/{companyId}/loan-tapes/{loanTapeId}/records` endpoint is now visible in the rendered API documentation. The endpoint itself has existed and been functional, but was missing the OpenAPI tag that surfaces it in the docs hub. `POST` and `PUT` on the same path remain undocumented because they are worker-internal only.

**Why it matters:** If you've been calling `GET` against this endpoint based on the response shape from other Loan Tape APIs, you can now point at the documented schema directly instead of inferring it.

**How to use it:** No code changes needed. See the newly-rendered [Loan Tape Records reference](/api-docs/api-public#tag/Loan-Tapes).

#### Statement BSTIR: events occurring after a day's interest accrual are lumped into the next local date

**Type:** Improvement
**Impact:** Informational
**Area:** Statements & Compliance

**What:** For loans using the new interest timestamp, non-interest events whose timestamp falls after a day's interest accrual run (such as a backdated transaction recorded at 23:59:59 local time) now shift into the next local date for statement BSTIR aggregation, instead of affecting the accrual day's interest balances. The aggregation also now sorts ledger entry pairs deterministically.

**Why it matters:** Produces more stable statement BSTIR and interest totals when backdated events arrive after the day's accrual has already run, instead of retroactively perturbing accrued interest.

**How to use it:** No action needed — applies automatically to loans on the new interest timestamp. If you reconcile statement BSTIR against your own ledger, the values should now match more closely on days where backdated events were posted late.

#### Canceling autopay no longer cancels same-day scheduled transactions

**Type:** Improvement
**Impact:** Informational
**Area:** Payments

**What:** When you cancel autopay on a loan, scheduled autopay transactions whose `scheduledDate` is today (in the loan type's local timezone) are no longer canceled. The associated `AutopayExpectedPayment` records for those same-day transactions are also preserved. All other scheduled autopay transactions (non-today) continue to be canceled as before.

**Why it matters:** Borrowers who cancel autopay on the same day a payment is scheduled to run still see that already-scheduled payment process, instead of having it disappear mid-day with no replacement.

**How to use it:** No action needed — applies automatically when autopay is canceled. If your application surfaces upcoming autopay transactions to borrowers, expect the same-day transaction to remain present after cancellation.

#### Metro2 "AU" special comment is restricted to specific settlement service credit types

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Reporting

**What:** The Metro2 "Account Paid in Full for Less than Full Balance" (AU) special comment is now triggered only when the clearing service credit is one of `BadDebt`, `SettlementOfDebt`, or `SettlementOfDebtNoLoss`. Previously, a broader set of service credit types could trigger AU, including some that did not represent settlement events.

**Why it matters:** Brings AU reporting into alignment with its intended Metro2 semantics, so charged-off or paid-off zero-balance loans only carry the AU comment when they were actually settled below full balance.

**How to use it:** No action needed — applies automatically to credit reporting output. If you reconcile bureau submissions against expected AU codes, the comment now appears more narrowly than before.

### Bug Fixes

#### `POST` case create returns `200` when `outcome` is provided in the request body

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where passing `outcome` (for example `"noOutcome"`) in a case create request body crashed with `500 Internal Server Error` because the value was not normalized to the expected format. Case create requests with an `outcome` field now return `200 OK` and persist the case correctly.

#### `POST /people/{personId}/cases` returns `400` on `borrowerIds`/`people` mismatch instead of crashing with `500`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where including `borrowerIds` or `people` in the case create request body — both fields are documented in the OpenAPI spec but were not wired into the handler — caused a `500` server error. The handler now accepts these fields when they match the path borrower (and ignores them), or returns `400 Bad Request` on any mismatch.

#### Loan tape worker no longer crashes on SFTP retry after compression

**Type:** Bug Fix
**Impact:** Informational
**Area:** Data & Reporting

Fixed an issue where, after an SFTP upload failure on a compressed loan tape, the retry attempt failed because cleanup from the prior attempt had already removed the temporary upload data. The retry path now preserves the data needed for subsequent attempts, so compressed-tape retries complete correctly instead of leaving records stuck in `created` status.

#### Twilio per-conversation webhook returns `503` (retryable) when the `Interaction` row is missing

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications

Fixed an issue where the Twilio per-conversation webhook could return an unhandled error when the associated interaction record was missing. The webhook now logs a warning and returns `503 Service Unavailable`, which Twilio's retry policy handles as a transient failure.

#### Roles permissions endpoint returns `400` when `actions` is missing

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where a roles permissions request with a missing `actions` field returned a server error instead of a validation error. The endpoint now returns `400 Bad Request` when `actions` is not provided.

#### SCRA chunk processor is idempotent on duplicate file upload

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance

Fixed an issue where re-uploading the same SCRA monitoring file could cause duplicate chunk processing. Duplicate uploads are now handled idempotently, reusing existing artifacts instead of reprocessing.

#### Autopay amount-options no longer flicker hidden during the `defaultType` query race in the Agent Portal

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue in the Agent Portal where the autopay amount-options list could briefly disappear when `defaultType` was still loading from a query, leaving the agent with no visible amount choices until the query settled. The options now stay visible during the load and re-evaluate once `defaultType` resolves.

#### `interestAdjustment` service credit type removed from the Issue Service Credit dropdown

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue in the Agent Portal where the Issue Service Credit form offered `interestAdjustment` as a selectable service credit type, which the backend does not accept on this flow. The option has been removed from the dropdown; agents previously selecting it would have hit a backend rejection on submit.

#### Six verified discrepancies in the Credit Reporting docs corrected

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Credit Reporting

Fixed six documentation discrepancies that integrators following the Credit Reporting docs would have encountered as real implementation bugs: an incorrect HTTP method, URL path, and `deletedReason` enum on the delete-credit-reporting API example; an incorrect mention of bankruptcy in the loss-credit-type list; a missing `rewards` service credit type in the calculations table; an incorrect `effective_date` field name in the Date of Last Payment pseudocode (should be `display_date`); an out-of-order closed-and-zero-balance check in the account-status algorithm; and a `sftpAccessMethod` field documented as required when it is in fact optional with a default. If you have implemented against any of these docs sections, review your code against the corrected versions.

## Week of May 4, 2026

This week adds a public Plaid credentials endpoint, plus Docs Hub llms.txt support and fixes across statements, refunds, and change-due-dates.

### New Features

#### New public `POST /companies/{companyId}/plaid/credentials` endpoint for updating Plaid integration credentials

**Type:** New Feature
**Impact:** Informational
**Area:** Developer Tools · Borrowers

**What:** A new public endpoint, `POST /companies/{companyId}/plaid/credentials`, updates a company's encrypted Plaid integration credentials. The request body requires both `clientId` and `secret`. Previously, Plaid credential updates were only available through internal Peach admin tooling.

**Why it matters:** Lets you rotate or update your Plaid integration credentials directly via the public API as part of normal credential-rotation hygiene, without involving Peach support for each change.

**How to use it:** Send `POST /companies/{companyId}/plaid/credentials` with `{ "clientId": "...", "secret": "..." }` as the request body. The endpoint requires the same admin-scoped authorization as other company-configuration endpoints; non-admin tokens receive `403 Forbidden`. Returns `204 No Content` on success.

### Improvements

#### Docs Hub publishes `llms.txt` for AI assistant navigation; feedback widget and SEO improvements

**Type:** Improvement
**Impact:** Informational
**Area:** Developer Tools

**What:** The Peach Docs Hub now publishes an `llms.txt` file at its root, following the emerging convention for surfacing documentation structure to AI coding assistants (Claude Code, Cursor, Copilot, and others) so they can navigate Peach documentation efficiently when answering integration questions. A feedback widget has also been added to all Docs Hub pages, and SEO indexing has been improved.

**Why it matters:** Engineers using AI coding tools to integrate with Peach can now point those tools at Peach's documentation and get more reliable navigation, reducing the rate at which AI assistants invent endpoint names or misremember field shapes.

**How to use it:** No action needed — applies automatically to anyone accessing the Docs Hub. The `llms.txt` file is at the root of the Docs Hub; the feedback widget appears as a button on every page.

### Bug Fixes

#### LOC statement `total_purchases_for_this_period` reconciles with the summary box when disputed purchases are present

**Type:** Bug Fix
**Impact:** Informational
**Area:** Statements & Compliance · Loan Lifecycle

Fixed an issue where LOC statements containing disputed purchases could produce a summary box where `total_purchases_for_this_period` did not match the sum of individual draws' purchase totals, triggering `summaryBoxMismatch` validation failures in the statement check pipeline.

#### `POST /expected-payments` in preview mode no longer deadlocks against concurrent change-due-dates requests

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle

Fixed an issue where `POST /expected-payments` (change-due-dates) requests with `previewMode=true` bypassed the reamortization Redis lock, allowing concurrent preview-plus-non-preview or preview-plus-preview requests for the same loan to deadlock via circular Postgres `ShareLock` dependencies on foreign-key constraint checks.

#### Canceling a Refund v2 also cancels its associated service credit transaction

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where canceling a Refund v2 left its associated service credit transaction (`refund.refund_transaction`) in its previous status, producing inconsistent ledger state where the refund was canceled but the corresponding credit transaction lived on.

## Week of April 27, 2026

This week clarifies the recommended `fields=minimal` value on the loans-list endpoint, adds credit-reporting improvements, and fixes eight bugs across statements, payments, and portals.

### Improvements

#### `fields=minimal` is the recommended value for the `fields` parameter on `GET /loans`

**Type:** Improvement
**Impact:** Informational
**Area:** Developer Tools

**What:** The `fields` query parameter on `GET /loans` now documents `minimal` as the canonical value. The legacy `idsOnly` value continues to work as an alias — the response shape is identical — but `minimal` is the value to use going forward. Note that the internal `GET /companies/{companyId}/loans` endpoint accepts only `minimal` and does not honor the `idsOnly` alias.

**Why it matters:** If you're writing new code against `GET /loans`, use `fields=minimal`. Existing code using `fields=idsOnly` continues to work unchanged.

**How to use it:** Pass `fields=minimal` instead of `fields=idsOnly` on `GET /loans` requests.

#### Credit reporting status preserves historical `reportingEndDate` when it falls in a prior month

**Type:** Improvement
**Impact:** Informational
**Area:** Credit Reporting

**What:** When a stop event is processed against a loan whose `CreditReportingStatus.reportingEndDate` already falls in a previous month (relative to the loan's local current month), Peach now preserves the existing end date instead of overwriting it. The associated `LoanCreditReportingStoppedEvent` is also not re-fired in this case.

**Why it matters:** Avoids retroactively changing historical credit reporting stop dates when a stop event arrives late, keeping bureau-reporting audit trails consistent with what was previously submitted.

**How to use it:** No action needed — applies automatically. If you reconcile credit reporting stop dates against historical bureau submissions, the dates should now remain stable once they pass into a prior month.

### Bug Fixes

#### Statements endpoint rejects external IDs (`ext-` prefix) with `400`

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Statements & Compliance

Fixed an issue where the statements endpoint accepted `ext-` prefixed identifiers for `statementPubId` and produced server errors or undefined behavior when the prefix didn't match the expected public ID format. The endpoint now returns `400 Bad Request` for any `statementPubId` value beginning with `ext-`, with an error message indicating that external IDs are not supported on this endpoint.

If your integration has been passing `ext-` prefixed values to the statements endpoint, switch to the corresponding public statement IDs (which can be retrieved from the relevant loan or person resource). The OpenAPI parameter description has been clarified to document the accepted ID format.

#### `GET /events` returns `404` (not `422`) for unresolved external-ID filters

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where `GET /events` filter values like `personId=ext-someExternalId` were routed through public-ID decoding instead of external-ID resolution, returning `422 InvalidPublicId` even for syntactically valid external identifiers. These requests now resolve external IDs correctly when they exist, and return `404 Not Found` when they don't.

#### Custom payment plan creation returns `400` when `paymentPlanType` is missing

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Loan Lifecycle

Fixed an issue where custom payment plan creation requests omitting the `paymentPlanType` field could crash with a server error during plan processing. Requests missing `paymentPlanType` now return `400 Bad Request` with the message "Must specify `paymentPlanType`."

If your custom payment plan flow ever omitted `paymentPlanType` — relying on an implicit default or expecting the server to infer it — update the request to send a valid value before posting.

#### Installment loans activated late no longer produce a first period where `dueDate` equals `startDate`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle

Fixed an issue in installment loan schedule generation where loans created from expected payments at origination could produce a first period whose `dueDate` equaled or preceded the loan's `startDate` when activation was delayed, producing a zero-day or negative-length first billing period.

#### Amortization request building correctly sets `originationFeeAprCalcOverride` for predefined loans

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Configuration

Fixed an issue in amortization request building where predefined-loan defaulting overwrote `originationFeeChargeLogic` instead of setting `originationFeeAprCalcOverride`, producing incorrect amortization output for loans that relied on predefined-loan defaults during request construction.

#### New transactions are skipped for inactive companies across autopay, scheduled transactions, and ACH updates

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where autopay scheduling, scheduled-transaction dispatch, and initiated-ACH status updates could continue processing transactions for companies whose status had been set to `inactive`. These workers now check company status, skip processing for inactive companies, and log the skip rather than initiating new transactions.

#### "Peach Support" sidebar link in the Agent Portal opens reliably

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue where the "Peach Support" link in the Agent Portal sidebar — which routes through a Zendesk SSO token refetch — could be blocked by browser popup heuristics or land on an invalid URL when the token fetch was slow.

#### Purchase disputes on migrated LOC loans use `originalDrawId` instead of the static migration `drawId`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Loan Lifecycle · Servicing & Operations

Fixed an issue in the Agent Portal where opening or listing purchase disputes for purchases on migrated line-of-credit loans hit `400 Bad Request` because the request used `purchase.drawId` (which points to a static migration draw) rather than `purchase.migration.originalDrawId`.

## Week of April 20, 2026

This week brings configurable per-loan-type fee ordering and fixes across origination and webhooks.

### New Features

#### Configurable fee-bucket ordering per loan type with `paymentWaterfall.feesOrder`

**Type:** New Feature
**Impact:** Informational
**Area:** Loan Configuration

**What:** A new optional `paymentWaterfall.feesOrder` setting on loan types specifies the order in which fee buckets are drawn from during `apply_payments`. Previously, payment application used a fixed fee-iteration order across all loan types.

**Why it matters:** Lets you tune which fee categories are paid down first for a given loan product — for example, prioritizing dispute-related fees over late fees on a credit card product, or vice versa — without code-level changes.

**How to use it:** Set `paymentWaterfall.feesOrder` to an ordered array of unique fee category values when creating or updating a loan type via the Loan Types API. Loan types without an explicit `feesOrder` continue to use the existing default ordering.

### Improvements

#### Autopay enrollment skips the signed-agreement requirement for external payment instruments

**Type:** Improvement
**Impact:** Informational
**Area:** Loan Configuration · Payments

**What:** Autopay enrollment no longer requires `agreementDocumentId` when the selected payment instrument is marked `isExternal: true`. Non-external instruments still require the signed agreement document, and `previewMode` continues to bypass the requirement for both.

**Why it matters:** External payment instruments are processed outside Peach's ACH network and typically have authorization captured by the client through a separate mechanism, so requiring a Peach-stored agreement document for them was duplicative.

**How to use it:** When enrolling autopay with an external instrument, omit `agreementDocumentId`; enrollment will succeed without it. Existing flows for non-external instruments are unchanged.

#### `sftpAchConfirmationFileNameRegex` accepts `null` on payment processors

**Type:** Improvement
**Impact:** Informational
**Area:** Payments

**What:** The `sftpAchConfirmationFileNameRegex` field on payment processor resources is now nullable; clients can explicitly send `null` to indicate no ACH confirmation filename pattern is in use. Previously the field rejected `null` and required a string value.

**Why it matters:** Payment processors that don't generate confirmation files (or that use a fixed filename rather than a pattern) no longer need a placeholder regex.

**How to use it:** Send `sftpAchConfirmationFileNameRegex: null` on `POST` or `PATCH` requests to the payment processor endpoint when no pattern matching is needed. Existing string values continue to work as before.

#### Agent Portal surfaces statements whose PDF is unavailable, marked "PDF missing"

**Type:** Improvement
**Impact:** Informational
**Area:** Statements & Compliance · Servicing & Operations

**What:** The Agent Portal and CRM borrower documents views now display every statement on a loan, including statements whose PDF document hasn't been generated or is otherwise missing. These appear in the list with a "PDF missing" indicator, and download/mail actions are disabled for them. Previously, statements without a `documentDescriptorId` were filtered out of the view entirely. The statements list also now paginates through all historical years rather than capping at the first page.

**Why it matters:** Agents can see that a statement period exists even when the rendered PDF is unavailable, instead of being unable to distinguish a suppressed statement from a missing one. Multi-year loan histories are no longer truncated in the portal view.

**How to use it:** No action needed — applies automatically to the Agent Portal CRM documents dialog and the loan-level Statements view. If you encounter a "PDF missing" entry that you expect to be renderable, the underlying statement record exists but no PDF was generated; check the document descriptor via the API to confirm whether PDF generation succeeded for that period.

### Bug Fixes

#### Negative `promoRates` are rejected at loan and draw origination

**Type:** Bug Fix
**Impact:** Recommended Action
**Area:** Loan Configuration

Fixed an issue where loan and draw origination accepted negative values for `promoRates`, producing invalid promo-rate configurations downstream. Origination requests with negative `promoRates` now return `400 Bad Request` with a message identifying the rejected value, while negative non-promo spread rates remain accepted as before.

If your origination flow was passing negative `promoRates` — whether intentionally to model spread-style discounts or inadvertently as part of a default-zero-then-decrement path — update the request to use non-negative values before sending. Existing loans created with negative promo rates prior to this fix are not affected.

#### `GET /events` returns `400` (not `500`) for malformed external-ID filters

**Type:** Bug Fix
**Impact:** Informational
**Area:** Developer Tools

Fixed an issue where `GET /events` filter values like `personId=ext-` (an `ext-` prefix with no ID after it) returned `500 Internal Server Error` instead of a client-error response. These requests now return `400 Bad Request` with a parameter-specific message identifying the malformed value and which filter parameter contained it.

#### Inbound Twilio voice webhooks no longer 500 when caller ID is suppressed

**Type:** Bug Fix
**Impact:** Informational
**Area:** Communications

Fixed an issue where inbound Twilio voice webhooks returned `500 Internal Server Error` when the caller's `From` value was caller-ID-suppressed (e.g., `Anonymous`, `Restricted`) or otherwise non-numeric. These calls now return `200 OK` and create an `Interaction` record with no `contact_id` or `person_id` attached, and a warning is logged for the unparseable phone value.

## Week of April 13, 2026

This week brings configuration improvements for NSF fees, bug fixes for address persistence and autopay, and new error-codes documentation.

### New Features

#### New Error Codes & Error Handling reference page

**Type:** New Feature
**Impact:** Informational
**Area:** Developer Tools

A new reference page documents Peach's error response schema, eleven common error scenarios with troubleshooting steps, and best practices for error handling in client integrations. Previously, error responses were undocumented in the public API reference.

Use the page when implementing retry logic, surfacing errors to borrowers or agents, or triaging unexpected API responses. Applies automatically - no action needed.

See the [Error Codes & Error Handling reference](/developer-tools/error-codes) for current behavior.

### Improvements

#### NSF dynamic fees support `passedAtOrigination` amount logic

**Type:** Improvement
**Impact:** Informational
**Area:** Loan Configuration

NSF dynamic fee types now accept `amountLogic.type=passedAtOrigination`, alongside the existing `fixed` option. Previously, NSF fees only supported a fixed amount configured on the loan type.

This lets you set NSF fee amounts per loan at origination time - for example, when fee size depends on borrower-specific terms - instead of forcing a single fixed value across every loan of a given type.

Configure `amountLogic.type=passedAtOrigination` when adding an NSF entry under the loan type's dynamic fees, then pass the per-loan amount during loan creation.

#### LOC migration period start dates are validated against the loan's activation date

**Type:** Improvement
**Impact:** Informational
**Area:** Loan Configuration

LOC migration requests now reject configurations where the migration period's `startDate` is earlier than the LOC's `activated_at` date, returning a validation error instead of accepting the request. Previously, migrations could create period data that pre-dated the loan itself, producing inconsistent billing-cycle records.

If a migration that previously succeeded now returns a validation error, adjust the migration period `startDate` so it falls on or after the LOC `activated_at` timestamp.

#### Replica v3 migration guide documents Amazon S3 Push Delivery

**Type:** Improvement
**Impact:** Informational
**Area:** Data & Reporting

The Replica v3 Technical Migration Guide now includes the full Amazon S3 Push Delivery section, mirroring the equivalent section in the Data Delivery Setup Guide. If you are migrating to Data Replica v3 with S3 as your delivery target, the OIDC provider configuration, IAM role setup, and bucket prerequisites are now covered inline in the migration guide.

See the [Replica v3 Technical Migration Guide](/release-notes/change-notices/replica-v3-migration-guide).

### Bug Fixes

#### Inline `personAddress` payloads now persist `postalCode`, `countyOrRegion`, and `POBox`

**Type:** Bug Fix
**Impact:** Informational
**Area:** Borrowers

Fixed an issue where loans created with an inline `personAddress` payload — rather than a referenced `personAddressId` — silently dropped the `postalCode`, `countyOrRegion`, and `POBox` fields.

#### Legal representative address updates now persist every address field

**Type:** Bug Fix
**Impact:** Informational
**Area:** Borrowers

Fixed an issue where updating a legal representative through the create or update endpoints did not normalize the `address` payload through the same deserializer used at create time, causing fields such as `timezone` to be dropped on update.

#### Final autopay amount on installment loans is no longer inflated when payments are processed but not yet settled

**Type:** Bug Fix
**Impact:** Informational
**Area:** Payments

Fixed an issue where the autopay recalculation on installment loans could inflate the final autopay amount when an autopay payment had been processed but not yet settled, particularly when autopay dates did not align with expected payment due dates.

#### Bulk operation detail rows in the CRM show counts derived from operation totals

**Type:** Bug Fix
**Impact:** Informational
**Area:** Servicing & Operations

Fixed an issue in the CRM where the *Successful*, *Failed*, and *Ineligible* rows on a bulk operation's detail page displayed the number of currently loaded results instead of the operation's true totals.

## 2026 Q1 — Released 04.10.2026

### Loan Management & Borrower Portal

- **White labeled borrower experience based on loan type** [New Feature] — Allow lenders to support multiple white-labeled Borrower Portal experiences based on their loan type configurations. Lenders that operate with multiple brands can have customized branding, support information, and UI elements for their loan types. For reference, please see this [Docs Hub guide](/white-labeling).
- **Issue rewards service credit transaction** [Improvement] — Allow lenders to issue "rewards" service credits type and optionally provide a custom name for that service credit transaction. For reference, please see this [API endpoint](https://docs.peachfinance.com/api-docs/api-public/transactions).
  - *Related training: [Borrower Portal - Agent-only View and Tools > Loan Options - Agent-only - Issue credit (updated)](/servicing-operations/agent-only-tools/agent-tools-overview)*
- **Enhanced Metro2 credit reporting logic related to bankruptcy** [Improvement] — Several updates to Peach's credit bureau reporting specifically around "Actual Payment Amount", "Account Status", "Payment History Profile", "Consumer Information Indicator", "FCRA Compliance / Date of First Delinquency", and terminal reporting logic. These changes ensure more accurate Metro2 reporting during the loan's bankruptcy lifecycle. For reference, please see this [Docs Hub guide](/credit-reporting).
- **Enhanced line of credit `paidOff` transition logic** [Improvement] — Refined the loan status transition logic to prevent line of credit loans from transitioning to `paidOff` status if there is an active Bankruptcy case (`case.status` = `initiated`, `processing`, `reopened`). A line of credit will only transition to `paidOff` when the line is closed, the balance is $0, there are no pending purchases or transactions, and there are no active Bankruptcy cases associated with the line.
- **Refined charge-off management** [Improvement] — Allow lenders to update the `chargedOffReason` on charged off loans. The following charged off reasons are supported: `term`, `bankruptcy`, `fraudulent`, `legal`. For reference, please see this [API endpoint](https://docs.peachfinance.com/api-docs/api-public/loans).
- **Future dynamic fee suppression for loans with active SCRA plan** [Improvement] — Allows lenders to suppress future dynamic fees when `isCancelFees=true`. This means in addition to waiving all past fees within the SCRA period, Peach will proactively prevent any future dynamic fees from being charged for the remainder of the active plan duration. This eliminates the need for manual future fee waivers for both installment and line of credit loans. For reference, please see this [API endpoint](https://docs.peachfinance.com/api-docs/api-public/scra).
- **Set and manage SCRA plans for lines of credit** [New Feature] — Allow lenders to create and manage SCRA plans on line of credit loans using the "Set line of credit SCRA terms" and "Manage line of credit SCRA terms" tools in the Agent-view of the Borrower Portal. When creating an SCRA plan, agents can set a new annual interest rate, an effective date, an end date, optionally waive all fees, and send a notice to the borrower. When managing an existing SCRA plan, agents can update the start date and end date of the plan. For reference, please see this [API endpoint](https://docs.peachfinance.com/api-docs/api-public/scra).
  - *Related training: [Borrower Portal - Agent-only View and Tools > Loan Options - Agent-only - Set SCRA terms (new)](/servicing-operations/agent-only-tools/agent-tools-overview)*
  - *Related training: [Borrower Portal - Agent-only View and Tools > Loan Options - Agent-only - Manage SCRA terms (new)](/servicing-operations/agent-only-tools/agent-tools-overview)*
- **Fail multiple transactions in a single API call** [New Feature] — Allow lenders to fail multiple transactions on a loan in a single request, triggering exactly one replay instead of one per transaction. This is significantly faster for lenders who process bulk ACH returns or need to fail several transactions on the same loan at once. The endpoint accepts an array of transactions with failure reason, optional processor details, and optional ACH return code. Supports `sync=true` to wait for the replay to complete. For reference, please see this [API endpoint](https://docs.peachfinance.com/api-docs/api-public/transactions).
- **Enhanced line of credit Purchase status transitions** [Improvement] — Allow lenders to change line of credit Purchase status from declined→authorized and settled→canceled.


### Admin Portal

- **New Admin Portal layout** [New Feature] — A new sidebar-based layout is now the default for the Admin Portal. The new layout replaces the top navigation bar with a sidebar that organizes features into sections: Workforce (Teams, Employees, Roles), Customer Messaging (Templates, Repayment Engine), Loan Types, Dynamic Fee Types, API Keys, Loan Labels, and Company Config. To return to the legacy layout, click the option at the bottom left of the sidebar. Capital Markets (Investors, Settlement Instruments) will be added to the sidebar in a subsequent update.
  - *Related training: [Admin Portal - Overview (updated)](/servicing-operations/admin-portal/admin-portal-overview)*
- **Employee assignment to investors** [New Feature] — Allow lenders to assign employees to one or more investors. If an employee is assigned to one or more investors, they can access all loans linked to those investors; if they are not assigned to any investor, they can access all loans across the company. This controls employee access to loan portfolios across the Peach system.
  - *Related training: [Admin Portal - Employee Management (new)](/servicing-operations/admin-portal/admin-portal-overview)*
- **Templates redesign** [New Feature] — Allow lenders to create both custom and loan-type-specific templates. The redesigned interface introduces a searchable template list with column management, a side panel with Template, Code, and Details tabs, and a new editor that displays all supported template variables by subject so that lenders know which variables can be used when drafting the content of each template. Additional features include export all templates, PDF preview with sample data rendering, and search filtering.
  - *Related training: [Admin Portal - Customer Messaging - Templates (updated)](/servicing-operations/admin-portal/admin-portal-overview)*
- **Repayment engine redesign** [New Feature] — Allow lenders to create, update, and delete repayment engine configurations for the 16 subjects offered today. Additional features include an updated main view, side panel, column management, and search filtering.
  - *Related training: [Admin Portal - Customer Messaging - Repayment Engine (updated)](/servicing-operations/admin-portal/admin-portal-overview)*
- **Company config redesign** [New Feature] — Allow lenders to view and manage their company configuration. Lenders can view the full configuration in a structured field view or raw JSON code view, and edit a subset of fields including UI elements, task management, support details, communication settings, and links.
  - *Related training: [Admin Portal - Company Config (new)](/servicing-operations/admin-portal/admin-portal-overview)*
- **Investors and settlement instruments management** [New Feature] — Allow lenders to create and manage their own investors and settlement instruments directly from the Admin Portal. Lenders can create investors with legal name, external ID, contact information, mailing address, and a default investor designation. Each investor can have one or more settlement instruments, which represent bank accounts where Peach settles payment proceeds. Both views include search filtering and column management. For reference, please see the [Investors](https://docs.peachfinance.com/api-docs/api-public/investors) and [Settlement Instruments](https://docs.peachfinance.com/api-docs/api-public/settlement-instruments) API endpoints.
  - *Related training: [Admin Portal - Capital Markets - Investors (new)](/servicing-operations/admin-portal/admin-portal-overview)*
  - *Related training: [Admin Portal - Capital Markets - Settlement Instruments (new)](/servicing-operations/admin-portal/admin-portal-overview)*