Skip to main content
PUT
cURL

Overview

Partially update a loan by its external reference ID. Only the fields that changed need to be sent — omitted fields are left unchanged.

Collection balance updates

Use PUT /loans/{id}, where id is your external loan ID, with the company API key in X-API-Key and this entire JSON payload:
current_balance is the outstanding balance including accrued interest. It is an absolute USD amount, not an increment. Send no interest, timestamp, update ID, classification, or other loan fields in this request. The snake_case spelling is required. Decimal strings are recommended; amounts must be finite, nonnegative, at cent precision, and no greater than 99999999.99.

Scope and stopping updates

This feed is available only to explicitly approved integrations; contact Finosu to confirm eligibility for your authenticated account before sending updates. Each request must identify a single unambiguous, active, company-owned loan. Send collection accounts only, never charge-off accounts. Your system owns the category; Finosu adds no category field and does not infer that category from stored chargeoffDate or chargeoffAmount. Those boarding fields do not block this feed and remain unchanged. Your integration must stop publishing once Finosu receives any full or partial payment or a payment plan is created. Finosu also enforces this locally: uploads return 409 while money is pending, after confirmed/returned/refunded payment activity, or after plan creation. A failed attempt that never received money does not by itself freeze accrual. Hidden/deleted history cannot remove the freeze. These checks run under the same loan lock used for direct payment reservations and plan creation; partner notification delivery is not the only protection against a late upload. The last accepted external amount becomes the enrolled loan’s local calculation basis. Later successful payments reduce it exactly once; pending payments reduce only today’s available-to-pay amount. Returns restore the local cash deduction without automatically authorizing interest resumption. Accepted plan totals remain fixed. The internal totalBalance, boarding fields and ledger transactions are not rewritten by this feed. Loans not enrolled retain their existing calculations. Staff currentTotalBalance remains the existing internal-ledger display; it is not relabeled as the external amount. For reconciliation, distinguish that value from the accepted current_balance and the borrower-payable amount after local cash.

Ordering and retries

There is no sender timestamp or idempotency key in this contract. Updates are applied in serialized server-receipt order, not source-effective order. Each accepted request records an audit snapshot, including equal amounts; retries can add audit rows but cannot add the amount to the balance. The response includes the latest accepted current_balance; totalBalance remains the independent internal field. Your integration must serialize uploads per loan (one outstanding request), stop and discard queued/retried uploads when a payment/plan notification arrives, and never retry an old value after a newer one. A timeout is ambiguous; do not assume the upload failed. Finosu cannot distinguish a delayed old value from a fresh one once updates are allowed again. Lifecycle protection rejects packets during a freeze; it is not an end-to-end freshness guarantee after resumption.

Resumption and rollout gates

The agreed resume cases are a Finosu-side plan cancellation, or a qualifying return after plan completion. These are not generic permission to restart uploads:
  • Cancellation resumption requires an explicit Finosu lifecycle signal, a durable delivery receipt, and a fresh balance that starts a new local deduction baseline. The historical PaymentPlanCancelled wire contract must be reconfirmed with your integration team; its new sender is disabled until that contract/rollout setting is approved. For a v2-enrolled loan with financial history linked to any payment plan, cancellation itself returns 409 for manual review before changing the plan. Removing that agreement without historical plan-payment/credit accounting could overstate the payable amount. Paid-plan cancellation and later return/resumption need separate v2 accounting support; merely holding uploads is not sufficient. An unpaid current plan is not by itself eligible: any transaction history linked to any of the loan’s plans (including failed, returned, prior or deleted rows), or any loan-credit ledger history, still requires manual review. Cancellation also checks active servicing, company scope, other active plans, and processing or scheduled terminal payments. Non-enrolled loans are unchanged.
  • Return-based resumption is agreed intent, not operationally available in this implementation. It requires a separate implementation and confirmation of the hard/soft return mapping and which outcomes resume accrual. Neither rollout flag enables it. Existing retry recommendations are not an interest-accrual policy. Raw return codes/reasons remain unchanged.
  • Before any authorized resume, discard all pre-freeze pending uploads/retries. The single-field payload cannot prove a source epoch or distinguish their lateness.
Until the cancellation rollout requirements are met, cancellation does not reopen balance admission; subsequent balance uploads return 409. Returns never authorize resumption in this implementation. Do not resume solely because a plan is inactive, a payment returned, a webhook was queued, or a previous upload succeeded. Finosu must deploy compatible API and payment-worker readers before enrolling loans. Snapshot and enrollment evidence must be preserved on rollback; stop new submissions rather than deleting it. Historical enrollment requires a reviewed migration; this endpoint performs no schema migration or historical backfill. New uploads are disabled by default and require separate enablement by Finosu after reader compatibility is confirmed. Disabling uploads does not stop local payments or existing enrolled-balance readers. Cancellation-based resumption has its own separate rollout setting, which remains disabled until your integration team reconfirms the cancellation signal and the gated lifecycle is accepted. While uploads are disabled, the API returns 409 without changing the balance, enrollment, or snapshots. Publishing this documentation does not enable either capability or establish eligibility for your account.

Fraud

Use fraud on this endpoint because fraud belongs to one exact loan, not the customer generally. true records the fraud claim, stops servicing for FRAUD_CLAIM, blocks all communication channels, and cancels pending communications and scheduled payments for this loan. false clears the fraud fact and removes only fraud-owned holds; another active compliance restriction continues to control servicing and channel blocks. Repeating the current value is idempotent. Omitted or null makes no change. Do not combine fraud with servicingStatus, stopServicingReason, noCallReason, noTextReason, noEmailReason, or isVisibleInBorrowerPortal; those fields are owned by the fraud cascade for that request. If duplicate live records share the external loan ID, a fraud update returns 409 rather than choosing an arbitrary loan.

Immutable Fields

The following fields cannot be changed via this endpoint:
  • id — The external loan reference (used as the path parameter)
  • customerId — The customer linkage
  • amountDue — The origination amount set at creation

Servicing Status Transitions

Setting servicingStatus to NOT_SERVICING via this endpoint also cancels all scheduled payments and communications for the loan, matching the behavior of POST /loans/{id}/cancel-servicing. You can optionally include stopServicingReason (defaults to API_REQUEST). For stopping servicing specifically, the dedicated POST /loans/{id}/cancel-servicing endpoint remains the primary path.

Request Body

Only send the fields you want to update:
Fraud on the exact loan:
Transition to NOT_SERVICING:

Error Responses

Authorizations

X-API-Key
string
header
required

Path Parameters

id
string
required

External reference ID of the loan

Body

application/json

Fields to update

Partial update. id, customerId, amountDue cannot be changed. Collection-balance requests for explicitly approved integrations contain only current_balance (outstanding including accrued interest). No interest, timestamp, update ID or category. Payment/plan activity freezes uploads. Receipts cannot prove source freshness; see Update Loan for ordering, resume gates and rollout requirements.

current_balance

Collection-only outstanding USD balance for explicitly approved integrations including accrued interest. Send this field alone. Nonnegative, finite, at most 99999999.99, at cent precision. No source timestamp or replay identity is provided.

type
enum<string>
Available options:
CASH_ADVANCE,
PERSONAL_LOAN,
INSTALLMENT_LOAN
applicationStatus
enum<string>
Available options:
PENDING,
APPROVED,
FUNDED,
WITHDRAWN,
REJECTED
originalFundedAmount
number
originalTotalOwed
number
interestRate
number
apr
number
originationDate
string<date>
startDate
string<date>
totalBalance
number
payoffAmount
number
totalPayoffAmount
number
balanceAtTransfer
number
preTransferPayments
number
dueDate
string<date>
servicingStatus
enum<string>
Available options:
ACTIVE,
NOT_SERVICING
stopServicingReason
string
isSettled
boolean
chargeoffDate
string<date>
chargeoffAmount
number
collectionsReportingSegment
enum<string> | null

Optional reporting classification. Omitted or null leaves the stored value unchanged.

Available options:
COLLECTIONS,
CHARGEOFF,
null
autopayEnabled
boolean
noCallReason
string
noTextReason
string
noEmailReason
string
isVisibleInBorrowerPortal
boolean
daysPastDueAtBoarding
integer
daysSinceOriginationAtBoarding
integer
externalLmsMetadata
object
fraud
boolean | null

Set or clear the fraud claim on this exact loan. Omitted or null makes no change. The fraud cascade owns servicing and channel-block fields.

Response

Loan updated

id
string
required

External loan reference ID

customerId
string
required

External customer reference ID

amountDue
string
required

Decimal value serialized as a JSON string.

dueDate
string
required
current_balance
string | null

Latest accepted raw external balance; local payments are deducted separately. Internal totalBalance is unchanged.

type
string | null
applicationStatus
string | null
originalFundedAmount
string | null

Decimal value serialized as a JSON string; null when unavailable.

originalTotalOwed
string | null

Decimal value serialized as a JSON string; null when unavailable.

interestRate
string | null

Decimal value serialized as a JSON string; null when unavailable.

apr
string | null

Decimal value serialized as a JSON string; null when unavailable.

originationDate
string<date> | null
startDate
string<date> | null
totalBalance
string | null

Decimal value serialized as a JSON string; null when unavailable.

payoffAmount
string | null

Decimal value serialized as a JSON string; null when unavailable.

totalPayoffAmount
string | null

Decimal value serialized as a JSON string; null when unavailable.

balanceAtTransfer
string | null

Decimal value serialized as a JSON string; null when unavailable.

preTransferPayments
string | null

Decimal value serialized as a JSON string; null when unavailable.

servicingStatus
string | null
stopServicingReason
string | null
isSettled
boolean | null
chargeoffDate
string | null
chargeoffAmount
string | null

Decimal value serialized as a JSON string; null when unavailable.

collectionsReportingSegment
enum<string> | null

Optional reporting classification; null when the loan is not classified.

Available options:
COLLECTIONS,
CHARGEOFF,
null
autopayEnabled
boolean | null
noCallReason
string | null
noTextReason
string | null
noEmailReason
string | null
isVisibleInBorrowerPortal
boolean | null
daysPastDueAtBoarding
integer | null
daysSinceOriginationAtBoarding
integer | null
externalLmsMetadata
object | null
portfolioId
string<uuid> | null
paymentPlanMinPercentage
string | null

Decimal value serialized as a JSON string; null when unavailable.

paymentPlanMaxPercentage
string | null

Decimal value serialized as a JSON string; null when unavailable.

taskType
string | null
fraud
boolean

Whether this exact loan has a fraud claim