curl --request POST \
--url https://api.finosu.com/loans \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"id": "LOAN-12345",
"customerId": "CUST-001",
"originationDate": "2026-04-01",
"totalBalance": 425,
"amountDue": 425,
"servicingStatus": "ACTIVE",
"originalFundedAmount": 500,
"originalTotalOwed": 650,
"interestRate": 0.2999,
"apr": 0.355,
"startDate": "2023-12-25",
"payoffAmount": 1,
"totalPayoffAmount": 1,
"balanceAtTransfer": 1,
"preTransferPayments": 1,
"dueDate": "2026-05-01",
"delinquencyDate": "2026-05-01",
"isSettled": true,
"chargeoffDate": "2023-12-25",
"chargeoffAmount": 1,
"autopayEnabled": true,
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 1,
"daysSinceOriginationAtBoarding": 1,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": 0.5,
"paymentPlanMaxPercentage": 0.5,
"taskType": "Collections"
}
'import requests
url = "https://api.finosu.com/loans"
payload = {
"id": "LOAN-12345",
"customerId": "CUST-001",
"originationDate": "2026-04-01",
"totalBalance": 425,
"amountDue": 425,
"servicingStatus": "ACTIVE",
"originalFundedAmount": 500,
"originalTotalOwed": 650,
"interestRate": 0.2999,
"apr": 0.355,
"startDate": "2023-12-25",
"payoffAmount": 1,
"totalPayoffAmount": 1,
"balanceAtTransfer": 1,
"preTransferPayments": 1,
"dueDate": "2026-05-01",
"delinquencyDate": "2026-05-01",
"isSettled": True,
"chargeoffDate": "2023-12-25",
"chargeoffAmount": 1,
"autopayEnabled": True,
"isVisibleInBorrowerPortal": True,
"daysPastDueAtBoarding": 1,
"daysSinceOriginationAtBoarding": 1,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": 0.5,
"paymentPlanMaxPercentage": 0.5,
"taskType": "Collections"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'LOAN-12345',
customerId: 'CUST-001',
originationDate: '2026-04-01',
totalBalance: 425,
amountDue: 425,
servicingStatus: 'ACTIVE',
originalFundedAmount: 500,
originalTotalOwed: 650,
interestRate: 0.2999,
apr: 0.355,
startDate: '2023-12-25',
payoffAmount: 1,
totalPayoffAmount: 1,
balanceAtTransfer: 1,
preTransferPayments: 1,
dueDate: '2026-05-01',
delinquencyDate: '2026-05-01',
isSettled: true,
chargeoffDate: '2023-12-25',
chargeoffAmount: 1,
autopayEnabled: true,
isVisibleInBorrowerPortal: true,
daysPastDueAtBoarding: 1,
daysSinceOriginationAtBoarding: 1,
externalLmsMetadata: {},
portfolioId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
paymentPlanMinPercentage: 0.5,
paymentPlanMaxPercentage: 0.5,
taskType: 'Collections'
})
};
fetch('https://api.finosu.com/loans', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.finosu.com/loans",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'LOAN-12345',
'customerId' => 'CUST-001',
'originationDate' => '2026-04-01',
'totalBalance' => 425,
'amountDue' => 425,
'servicingStatus' => 'ACTIVE',
'originalFundedAmount' => 500,
'originalTotalOwed' => 650,
'interestRate' => 0.2999,
'apr' => 0.355,
'startDate' => '2023-12-25',
'payoffAmount' => 1,
'totalPayoffAmount' => 1,
'balanceAtTransfer' => 1,
'preTransferPayments' => 1,
'dueDate' => '2026-05-01',
'delinquencyDate' => '2026-05-01',
'isSettled' => true,
'chargeoffDate' => '2023-12-25',
'chargeoffAmount' => 1,
'autopayEnabled' => true,
'isVisibleInBorrowerPortal' => true,
'daysPastDueAtBoarding' => 1,
'daysSinceOriginationAtBoarding' => 1,
'externalLmsMetadata' => [
],
'portfolioId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'paymentPlanMinPercentage' => 0.5,
'paymentPlanMaxPercentage' => 0.5,
'taskType' => 'Collections'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.finosu.com/loans"
payload := strings.NewReader("{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.finosu.com/loans")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.finosu.com/loans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"customerId": "<string>",
"amountDue": "<string>",
"dueDate": "<string>",
"current_balance": "<string>",
"type": "<string>",
"applicationStatus": "<string>",
"originalFundedAmount": "<string>",
"originalTotalOwed": "<string>",
"interestRate": "<string>",
"apr": "<string>",
"originationDate": "2023-12-25",
"startDate": "2023-12-25",
"totalBalance": "<string>",
"payoffAmount": "<string>",
"totalPayoffAmount": "<string>",
"balanceAtTransfer": "<string>",
"preTransferPayments": "<string>",
"servicingStatus": "<string>",
"stopServicingReason": "<string>",
"isSettled": true,
"chargeoffDate": "<string>",
"chargeoffAmount": "<string>",
"collectionsReportingSegment": "COLLECTIONS",
"autopayEnabled": true,
"noCallReason": "<string>",
"noTextReason": "<string>",
"noEmailReason": "<string>",
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 123,
"daysSinceOriginationAtBoarding": 123,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": "<string>",
"paymentPlanMaxPercentage": "<string>",
"taskType": "<string>",
"fraud": true
}{
"id": "<string>",
"customerId": "<string>",
"amountDue": "<string>",
"dueDate": "<string>",
"current_balance": "<string>",
"type": "<string>",
"applicationStatus": "<string>",
"originalFundedAmount": "<string>",
"originalTotalOwed": "<string>",
"interestRate": "<string>",
"apr": "<string>",
"originationDate": "2023-12-25",
"startDate": "2023-12-25",
"totalBalance": "<string>",
"payoffAmount": "<string>",
"totalPayoffAmount": "<string>",
"balanceAtTransfer": "<string>",
"preTransferPayments": "<string>",
"servicingStatus": "<string>",
"stopServicingReason": "<string>",
"isSettled": true,
"chargeoffDate": "<string>",
"chargeoffAmount": "<string>",
"collectionsReportingSegment": "COLLECTIONS",
"autopayEnabled": true,
"noCallReason": "<string>",
"noTextReason": "<string>",
"noEmailReason": "<string>",
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 123,
"daysSinceOriginationAtBoarding": 123,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": "<string>",
"paymentPlanMaxPercentage": "<string>",
"taskType": "<string>",
"fraud": true
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}Create Loan
Create or update (upsert) a loan pushed from an external partner. The loan is keyed on (customer, externalReference). Returns 201 on create, 200 on update.
curl --request POST \
--url https://api.finosu.com/loans \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"id": "LOAN-12345",
"customerId": "CUST-001",
"originationDate": "2026-04-01",
"totalBalance": 425,
"amountDue": 425,
"servicingStatus": "ACTIVE",
"originalFundedAmount": 500,
"originalTotalOwed": 650,
"interestRate": 0.2999,
"apr": 0.355,
"startDate": "2023-12-25",
"payoffAmount": 1,
"totalPayoffAmount": 1,
"balanceAtTransfer": 1,
"preTransferPayments": 1,
"dueDate": "2026-05-01",
"delinquencyDate": "2026-05-01",
"isSettled": true,
"chargeoffDate": "2023-12-25",
"chargeoffAmount": 1,
"autopayEnabled": true,
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 1,
"daysSinceOriginationAtBoarding": 1,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": 0.5,
"paymentPlanMaxPercentage": 0.5,
"taskType": "Collections"
}
'import requests
url = "https://api.finosu.com/loans"
payload = {
"id": "LOAN-12345",
"customerId": "CUST-001",
"originationDate": "2026-04-01",
"totalBalance": 425,
"amountDue": 425,
"servicingStatus": "ACTIVE",
"originalFundedAmount": 500,
"originalTotalOwed": 650,
"interestRate": 0.2999,
"apr": 0.355,
"startDate": "2023-12-25",
"payoffAmount": 1,
"totalPayoffAmount": 1,
"balanceAtTransfer": 1,
"preTransferPayments": 1,
"dueDate": "2026-05-01",
"delinquencyDate": "2026-05-01",
"isSettled": True,
"chargeoffDate": "2023-12-25",
"chargeoffAmount": 1,
"autopayEnabled": True,
"isVisibleInBorrowerPortal": True,
"daysPastDueAtBoarding": 1,
"daysSinceOriginationAtBoarding": 1,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": 0.5,
"paymentPlanMaxPercentage": 0.5,
"taskType": "Collections"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
id: 'LOAN-12345',
customerId: 'CUST-001',
originationDate: '2026-04-01',
totalBalance: 425,
amountDue: 425,
servicingStatus: 'ACTIVE',
originalFundedAmount: 500,
originalTotalOwed: 650,
interestRate: 0.2999,
apr: 0.355,
startDate: '2023-12-25',
payoffAmount: 1,
totalPayoffAmount: 1,
balanceAtTransfer: 1,
preTransferPayments: 1,
dueDate: '2026-05-01',
delinquencyDate: '2026-05-01',
isSettled: true,
chargeoffDate: '2023-12-25',
chargeoffAmount: 1,
autopayEnabled: true,
isVisibleInBorrowerPortal: true,
daysPastDueAtBoarding: 1,
daysSinceOriginationAtBoarding: 1,
externalLmsMetadata: {},
portfolioId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
paymentPlanMinPercentage: 0.5,
paymentPlanMaxPercentage: 0.5,
taskType: 'Collections'
})
};
fetch('https://api.finosu.com/loans', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.finosu.com/loans",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'id' => 'LOAN-12345',
'customerId' => 'CUST-001',
'originationDate' => '2026-04-01',
'totalBalance' => 425,
'amountDue' => 425,
'servicingStatus' => 'ACTIVE',
'originalFundedAmount' => 500,
'originalTotalOwed' => 650,
'interestRate' => 0.2999,
'apr' => 0.355,
'startDate' => '2023-12-25',
'payoffAmount' => 1,
'totalPayoffAmount' => 1,
'balanceAtTransfer' => 1,
'preTransferPayments' => 1,
'dueDate' => '2026-05-01',
'delinquencyDate' => '2026-05-01',
'isSettled' => true,
'chargeoffDate' => '2023-12-25',
'chargeoffAmount' => 1,
'autopayEnabled' => true,
'isVisibleInBorrowerPortal' => true,
'daysPastDueAtBoarding' => 1,
'daysSinceOriginationAtBoarding' => 1,
'externalLmsMetadata' => [
],
'portfolioId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'paymentPlanMinPercentage' => 0.5,
'paymentPlanMaxPercentage' => 0.5,
'taskType' => 'Collections'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.finosu.com/loans"
payload := strings.NewReader("{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.finosu.com/loans")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.finosu.com/loans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"id\": \"LOAN-12345\",\n \"customerId\": \"CUST-001\",\n \"originationDate\": \"2026-04-01\",\n \"totalBalance\": 425,\n \"amountDue\": 425,\n \"servicingStatus\": \"ACTIVE\",\n \"originalFundedAmount\": 500,\n \"originalTotalOwed\": 650,\n \"interestRate\": 0.2999,\n \"apr\": 0.355,\n \"startDate\": \"2023-12-25\",\n \"payoffAmount\": 1,\n \"totalPayoffAmount\": 1,\n \"balanceAtTransfer\": 1,\n \"preTransferPayments\": 1,\n \"dueDate\": \"2026-05-01\",\n \"delinquencyDate\": \"2026-05-01\",\n \"isSettled\": true,\n \"chargeoffDate\": \"2023-12-25\",\n \"chargeoffAmount\": 1,\n \"autopayEnabled\": true,\n \"isVisibleInBorrowerPortal\": true,\n \"daysPastDueAtBoarding\": 1,\n \"daysSinceOriginationAtBoarding\": 1,\n \"externalLmsMetadata\": {},\n \"portfolioId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"paymentPlanMinPercentage\": 0.5,\n \"paymentPlanMaxPercentage\": 0.5,\n \"taskType\": \"Collections\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"customerId": "<string>",
"amountDue": "<string>",
"dueDate": "<string>",
"current_balance": "<string>",
"type": "<string>",
"applicationStatus": "<string>",
"originalFundedAmount": "<string>",
"originalTotalOwed": "<string>",
"interestRate": "<string>",
"apr": "<string>",
"originationDate": "2023-12-25",
"startDate": "2023-12-25",
"totalBalance": "<string>",
"payoffAmount": "<string>",
"totalPayoffAmount": "<string>",
"balanceAtTransfer": "<string>",
"preTransferPayments": "<string>",
"servicingStatus": "<string>",
"stopServicingReason": "<string>",
"isSettled": true,
"chargeoffDate": "<string>",
"chargeoffAmount": "<string>",
"collectionsReportingSegment": "COLLECTIONS",
"autopayEnabled": true,
"noCallReason": "<string>",
"noTextReason": "<string>",
"noEmailReason": "<string>",
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 123,
"daysSinceOriginationAtBoarding": 123,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": "<string>",
"paymentPlanMaxPercentage": "<string>",
"taskType": "<string>",
"fraud": true
}{
"id": "<string>",
"customerId": "<string>",
"amountDue": "<string>",
"dueDate": "<string>",
"current_balance": "<string>",
"type": "<string>",
"applicationStatus": "<string>",
"originalFundedAmount": "<string>",
"originalTotalOwed": "<string>",
"interestRate": "<string>",
"apr": "<string>",
"originationDate": "2023-12-25",
"startDate": "2023-12-25",
"totalBalance": "<string>",
"payoffAmount": "<string>",
"totalPayoffAmount": "<string>",
"balanceAtTransfer": "<string>",
"preTransferPayments": "<string>",
"servicingStatus": "<string>",
"stopServicingReason": "<string>",
"isSettled": true,
"chargeoffDate": "<string>",
"chargeoffAmount": "<string>",
"collectionsReportingSegment": "COLLECTIONS",
"autopayEnabled": true,
"noCallReason": "<string>",
"noTextReason": "<string>",
"noEmailReason": "<string>",
"isVisibleInBorrowerPortal": true,
"daysPastDueAtBoarding": 123,
"daysSinceOriginationAtBoarding": 123,
"externalLmsMetadata": {},
"portfolioId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"paymentPlanMinPercentage": "<string>",
"paymentPlanMaxPercentage": "<string>",
"taskType": "<string>",
"fraud": true
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}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 ofcustomerId 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
| Field | Type | Description |
|---|---|---|
id | string | Your stable loan reference ID. Must be unique per customer among active loans. |
customerId | string | Must match the id used when the customer was pushed via POST /customers. |
amountDue | number | 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 also provided. Must be non-negative. Immutable after creation — cannot be changed on subsequent upserts. |
dueDate | string | Date the loan first became overdue (YYYY-MM-DD): its earliest unpaid installment, not the next upcoming one. 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. |
delinquencyDate | string | Date the loan is delinquent from as of placement (YYYY-MM-DD): its earliest unpaid installment. Required unless dueDate is provided. When both are sent, delinquencyDate is used. See Delinquency date. |
servicingStatus | string | Must be ACTIVE on create. On upsert, can be set to NOT_SERVICING to stop servicing. |
totalBalance | number | Current outstanding balance. Must be non-negative. |
originationDate | string | Date the loan was originated (YYYY-MM-DD). Required for cadence policy. |
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 specifiedtaskType. The customer must have a valid IANA timezone set. taskType defaults to Collections if not specified.
Request Body
{
"id": "LOAN-12345",
"customerId": "CUST-001",
"type": "CASH_ADVANCE",
"applicationStatus": "FUNDED",
"originalFundedAmount": 500.00,
"originalTotalOwed": 650.00,
"interestRate": 0.2999,
"apr": 0.3550,
"originationDate": "2026-04-01",
"startDate": "2026-04-01",
"totalBalance": 425.00,
"payoffAmount": 425.00,
"amountDue": 425.00,
"dueDate": "2026-05-01",
"delinquencyDate": "2026-05-01",
"servicingStatus": "ACTIVE",
"autopayEnabled": true,
"isVisibleInBorrowerPortal": true,
"portfolioId": "3607837d-2daf-4772-90db-638a2fa008df",
"paymentPlanMinPercentage": 0.60,
"paymentPlanMaxPercentage": 0.80,
"taskType": "Collections"
}
Error Responses
| Status Code | Description |
|---|---|
| 404 | Customer with the given customerId not found |
| 409 | Concurrent duplicate — another request created the same loan |
| 422 | Invalid enum value, servicingStatus not ACTIVE on create, mismatched amountDue on upsert, invalid timezone, negative balance/rate, unpaired chargeoff/settlement fields, future or malformed delinquencyDate, neither dueDate nor delinquencyDate sent, invalid UUID, or missing required field |
| 500 | Internal server error |
Body
Loan data
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.
x >= 0425
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.
"2026-05-01"
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.
"2026-05-01"
Response
Existing loan updated