Skip to main content
POST
cURL
Your system owns the collection/charge-off category; no separate category field is required. Boarding does not itself authorize balance uploads. The collection-only feed is disabled by default and is available only after Finosu enables its rollout gate for explicitly approved integrations. Contact Finosu to confirm eligibility for your authenticated account. Eligible loans must be active, unambiguously identified and company-owned, and pass the payment/plan-history checks. Your system must still exclude charge-off accounts. Finosu does not infer your account category from stored chargeoffDate or chargeoffAmount; those boarding fields neither block the balance feed nor establish collection status. See Update Loan for the one-field current_balance contract, all eligibility checks and the 409 rollout response. Existing charge-off fields remain available for their existing purposes. Boarding and batch payloads retain their existing totalBalance behavior.

Overview

Create or update (upsert) a loan pushed from an external partner. The loan is keyed on the combination of customerId and id (your external loan reference). If an active loan with the same external reference already exists for the customer, it is updated in place; otherwise a new loan is created. This endpoint is designed for collections intake — all loans must be created with servicingStatus: ACTIVE. Pushing more than a handful of loans at once? Use Create Loans (Batch) instead — it takes any number of loans per request with the same per-loan schema and the same semantics.

Upsert Behavior

POST /loans is an upsert. If you push a loan that already exists (matched on id + customerId among active loans), we update the existing record. Soft-deleted or deactivated (NOT_SERVICING) loans are not matched — a new active loan is created instead.
  • New loan: Returns 201 Created
  • Existing loan updated: Returns 200 OK
  • Concurrent duplicate: Returns 409 Conflict

Required Fields

Validation Rules

Balance fields (non-negative)

All monetary fields must be >= 0 when provided: totalBalance, originalFundedAmount, originalTotalOwed, totalPayoffAmount, payoffAmount, balanceAtTransfer, preTransferPayments, chargeoffAmount. amountDue must be non-negative (>= 0). A zero value is accepted only when chargeoffDate and chargeoffAmount are also provided. The amount and dueDate are stored on the loan, but no initial scheduled-payment obligation is created. dueDate is the date the loan first became overdue (its earliest unpaid installment); this is what our platform uses to track delinquency, not the next upcoming installment. For a charged-off loan with no scheduled installment, dueDate is the last missed contractual due date. If that date is unavailable, send chargeoffDate. The borrower’s next payroll date is not a loan due date and must not be sent in this field.

Delinquency date

delinquencyDate states explicitly when the loan became delinquent: its earliest unpaid installment. Send delinquencyDate, dueDate, or both; at least one is required. When both are sent, delinquencyDate is used as the loan’s due date, on both create and upsert. The response dueDate always reflects the stored due date. delinquencyDate must be a YYYY-MM-DD date and must not be in the future. A future or malformed value returns 422. If you send delinquencyDate without daysPastDueAtBoarding, we compute daysPastDueAtBoarding when the loan is created, as the number of days from delinquencyDate to the day we board the loan. A daysPastDueAtBoarding you send is always kept. It is set once at creation and is not recalculated on upsert.

Rate fields

interestRate and apr must be non-negative. Values are stored as decimals where 1.0 = 100%. High-interest loans can have values above 1.0 (e.g. 6.49 = 649% APR).

Chargeoff pairing

chargeoffDate and chargeoffAmount must both be set or both omitted. Setting only one returns a validation error.

Settlement percentages pairing

paymentPlanMinPercentage and paymentPlanMaxPercentage must both be set or both omitted. When set, both must be between 0 and 1, and min <= max. When both are omitted (null), the loan is pay-in-full only unless the authenticated lender has an approved creation-time derivation policy. Approved creation-time derivation policies are account-specific. When enabled, they may use originalFundedAmount, preTransferPayments, and totalBalance to determine the settlement band and any principal-recovery floor. Contact your Finosu account manager for the policy configured for your account; do not assume a policy is enabled. Providing both percentages explicitly overrides automatic derivation. For accounts with a derivation policy, missing inputs or values unusable by that policy result in pay-in-full treatment after request validation succeeds. Values that violate request validation, such as negative monetary amounts, return HTTP 422 instead. The band is set once at creation; later updates do not recompute it.

Portfolio ID

portfolioId must be a valid UUID when provided. If omitted, defaults to the configured portfolio for your company.

Servicing status

servicingStatus must be ACTIVE on loan creation. To stop servicing on an existing loan, you can either upsert with servicingStatus: NOT_SERVICING (which also updates any other loan fields in the same call) or use the dedicated POST /loans/{id}/cancel-servicing endpoint. Both cancel all scheduled payments and communications.

Schedule creation

A collections schedule is automatically created on new loans based on the specified taskType. The customer must have a valid IANA timezone set. taskType defaults to Collections if not specified.

Request Body

Error Responses

Authorizations

X-API-Key
string
header
required

Body

application/json

Loan data

id
string
required

Your stable loan reference ID

Example:

"LOAN-12345"

customerId
string
required

External reference of a previously-pushed customer

Example:

"CUST-001"

originationDate
string<date>
required

Required. Date the loan was originated.

Example:

"2026-04-01"

totalBalance
number
required

Required. Current outstanding balance.

Required range: x >= 0
Example:

425

amountDue
number
required

The amount the borrower has left to pay; equals totalBalance when the full balance is placed for collection. Charged-off loans with no scheduled installment may send 0 when chargeoffDate and chargeoffAmount are provided. Must be non-negative and is immutable after creation. A zero amount does not create an initial scheduled-payment obligation.

Required range: x >= 0
Example:

425

servicingStatus
enum<string>
required

Must be ACTIVE on create. Use cancel-servicing endpoint to stop.

Available options:
ACTIVE
type
enum<string>
Available options:
CASH_ADVANCE,
PERSONAL_LOAN,
INSTALLMENT_LOAN
applicationStatus
enum<string>
Available options:
PENDING,
APPROVED,
FUNDED,
WITHDRAWN,
REJECTED
originalFundedAmount
number
Required range: x >= 0
Example:

500

originalTotalOwed
number
Required range: x >= 0
Example:

650

interestRate
number

Non-negative decimal where 1.0 = 100% (e.g. 6.49 = 649%)

Required range: x >= 0
Example:

0.2999

apr
number

Non-negative decimal where 1.0 = 100%

Required range: x >= 0
Example:

0.355

startDate
string<date>
payoffAmount
number
Required range: x >= 0
totalPayoffAmount
number
Required range: x >= 0
balanceAtTransfer
number
Required range: x >= 0
preTransferPayments
number
Required range: x >= 0
dueDate
string<date>

Date the loan first became overdue (its earliest unpaid installment), not the next upcoming installment. For a charged-off loan with amountDue 0, the last missed contractual due date, or chargeoffDate when that date is unavailable. Do not send the borrower's next payroll date. Required unless delinquencyDate is provided; when both are sent, delinquencyDate is used.

Example:

"2026-05-01"

delinquencyDate
string<date>

Date the loan is delinquent from as of placement: its earliest unpaid installment. Required unless dueDate is provided. When both are sent, delinquencyDate is used as the loan's due date, and the response dueDate reflects it. Must be YYYY-MM-DD and not in the future.

Example:

"2026-05-01"

isSettled
boolean
chargeoffDate
string<date>

Must be paired with chargeoffAmount

chargeoffAmount
number

Must be paired with chargeoffDate

Required range: x >= 0
collectionsReportingSegment
enum<string> | null

Optional reporting classification. Omit when the loan is not classified. On an upsert of an existing loan, omission or null preserves the stored value.

Available options:
COLLECTIONS,
CHARGEOFF,
null
autopayEnabled
boolean
Example:

true

noCallReason
enum<string>
Available options:
CUSTOMER_OPT_OUT,
LEGAL_HOLD,
BANKRUPT,
INCARCERATED,
DECEASED,
MILITARY,
FRAUD,
AGENCY_REQUEST,
COMPLAINT,
WRONG_NUMBER,
OTHER
noTextReason
enum<string>
Available options:
CUSTOMER_OPT_OUT,
LEGAL_HOLD,
BANKRUPT,
INCARCERATED,
DECEASED,
MILITARY,
FRAUD,
AGENCY_REQUEST,
COMPLAINT,
WRONG_NUMBER,
OTHER
noEmailReason
enum<string>
Available options:
CUSTOMER_OPT_OUT,
LEGAL_HOLD,
BANKRUPT,
INCARCERATED,
DECEASED,
MILITARY,
FRAUD,
AGENCY_REQUEST,
COMPLAINT,
WRONG_NUMBER,
OTHER
isVisibleInBorrowerPortal
boolean
Example:

true

daysPastDueAtBoarding
integer

Days past due when the loan is placed. If omitted and delinquencyDate is sent, it is computed on create as the days from delinquencyDate to the boarding date. Set once at creation.

Required range: x >= 0
daysSinceOriginationAtBoarding
integer
Required range: x >= 0
externalLmsMetadata
object
portfolioId
string<uuid>

Portfolio UUID for payment processor routing

paymentPlanMinPercentage
number

Min settlement percentage (0-1). Min and max must be supplied together. When both are omitted, the loan is pay-in-full unless an approved lender-specific creation policy derives a band.

Required range: 0 <= x <= 1
paymentPlanMaxPercentage
number

Max settlement percentage (0-1). Min and max must be supplied together. When both are omitted, the loan is pay-in-full unless an approved lender-specific creation policy derives a band.

Required range: 0 <= x <= 1
taskType
string

Schedule task type (e.g. Collections). Defaults to Collections when omitted.

Example:

"Collections"

Response

Existing 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