Skip to main content
POST
cURL

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.

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 strictly positive (> 0).

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 (no settlement discount). For XRiver loans, when both percentages are omitted at creation and originalFundedAmount, preTransferPayments, and totalBalance are all provided, the settlement band is computed server-side: if originalFundedAmount - preTransferPayments exceeds 65% of totalBalance, the loan is pay-in-full only; otherwise it gets a 65%–90% settlement band. Sending the percentage pair explicitly overrides this. The band is set once at creation — later updates never 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

Origination amount due. Must be positive. Immutable after creation.

Example:

125

dueDate
string<date>
required

Next payment date (YYYY-MM-DD)

Example:

"2026-05-01"

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
isSettled
boolean
chargeoffDate
string<date>

Must be paired with chargeoffAmount

chargeoffAmount
number

Must be paired with chargeoffDate

Required range: x >= 0
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
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). Both min+max required together. NULL = pay-in-full.

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

Max settlement percentage (0-1). Both min+max required together. NULL = pay-in-full.

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

Schedule task type (e.g. Collections). Defaults to Collections for JustLoans.

Example:

"Collections"

Response

Existing loan updated

id
string

External loan reference ID

customerId
string

External customer reference ID

type
string
applicationStatus
string
originalFundedAmount
number
originalTotalOwed
number
interestRate
number
apr
number
originationDate
string<date>
startDate
string<date>
totalBalance
number
payoffAmount
number
totalPayoffAmount
number
balanceAtTransfer
number
preTransferPayments
number
amountDue
number
dueDate
string
servicingStatus
string
stopServicingReason
string
isSettled
boolean
chargeoffDate
string
chargeoffAmount
number
autopayEnabled
boolean
noCallReason
string
noTextReason
string
noEmailReason
string
isVisibleInBorrowerPortal
boolean
daysPastDueAtBoarding
integer
daysSinceOriginationAtBoarding
integer
externalLmsMetadata
object
portfolioId
string<uuid>
paymentPlanMinPercentage
number
paymentPlanMaxPercentage
number
taskType
string