cURL
curl --request POST \
--url https://api.finosu.com/ach-returns/batch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"returns": [
{
"customerId": "<string>",
"loanId": "<string>",
"paymentId": "<string>",
"systemSource": "<string>",
"paymentDate": "2023-11-07T05:31:56Z",
"paymentReverseDate": "2023-11-07T05:31:56Z",
"paymentReversed": true,
"paymentReverseReasonCode": "<string>",
"paymentReverseComments": "<string>",
"paymentType": "<string>",
"paymentAmount": 123,
"achSubmittedDate": "2023-11-07T05:31:56Z",
"achSettlementDate": "2023-11-07T05:31:56Z",
"achStatus": "<string>",
"achReturnCode": "<string>",
"achReturnDate": "2023-11-07T05:31:56Z",
"achReturnReason": "<string>",
"achCorrectionCode": "<string>",
"achCorrectedAbaNumber": "<string>",
"achCorrectedAccountNumber": "<string>",
"achCorrectionDate": "2023-11-07T05:31:56Z",
"debitStatus": "<string>",
"debitDeclineReason": "<string>",
"overallReturnCode": "<string>",
"isMetadataError": false
}
]
}
'import requests
url = "https://api.finosu.com/ach-returns/batch"
payload = { "returns": [
{
"customerId": "<string>",
"loanId": "<string>",
"paymentId": "<string>",
"systemSource": "<string>",
"paymentDate": "2023-11-07T05:31:56Z",
"paymentReverseDate": "2023-11-07T05:31:56Z",
"paymentReversed": True,
"paymentReverseReasonCode": "<string>",
"paymentReverseComments": "<string>",
"paymentType": "<string>",
"paymentAmount": 123,
"achSubmittedDate": "2023-11-07T05:31:56Z",
"achSettlementDate": "2023-11-07T05:31:56Z",
"achStatus": "<string>",
"achReturnCode": "<string>",
"achReturnDate": "2023-11-07T05:31:56Z",
"achReturnReason": "<string>",
"achCorrectionCode": "<string>",
"achCorrectedAbaNumber": "<string>",
"achCorrectedAccountNumber": "<string>",
"achCorrectionDate": "2023-11-07T05:31:56Z",
"debitStatus": "<string>",
"debitDeclineReason": "<string>",
"overallReturnCode": "<string>",
"isMetadataError": False
}
] }
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({
returns: [
{
customerId: '<string>',
loanId: '<string>',
paymentId: '<string>',
systemSource: '<string>',
paymentDate: '2023-11-07T05:31:56Z',
paymentReverseDate: '2023-11-07T05:31:56Z',
paymentReversed: true,
paymentReverseReasonCode: '<string>',
paymentReverseComments: '<string>',
paymentType: '<string>',
paymentAmount: 123,
achSubmittedDate: '2023-11-07T05:31:56Z',
achSettlementDate: '2023-11-07T05:31:56Z',
achStatus: '<string>',
achReturnCode: '<string>',
achReturnDate: '2023-11-07T05:31:56Z',
achReturnReason: '<string>',
achCorrectionCode: '<string>',
achCorrectedAbaNumber: '<string>',
achCorrectedAccountNumber: '<string>',
achCorrectionDate: '2023-11-07T05:31:56Z',
debitStatus: '<string>',
debitDeclineReason: '<string>',
overallReturnCode: '<string>',
isMetadataError: false
}
]
})
};
fetch('https://api.finosu.com/ach-returns/batch', 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/ach-returns/batch",
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([
'returns' => [
[
'customerId' => '<string>',
'loanId' => '<string>',
'paymentId' => '<string>',
'systemSource' => '<string>',
'paymentDate' => '2023-11-07T05:31:56Z',
'paymentReverseDate' => '2023-11-07T05:31:56Z',
'paymentReversed' => true,
'paymentReverseReasonCode' => '<string>',
'paymentReverseComments' => '<string>',
'paymentType' => '<string>',
'paymentAmount' => 123,
'achSubmittedDate' => '2023-11-07T05:31:56Z',
'achSettlementDate' => '2023-11-07T05:31:56Z',
'achStatus' => '<string>',
'achReturnCode' => '<string>',
'achReturnDate' => '2023-11-07T05:31:56Z',
'achReturnReason' => '<string>',
'achCorrectionCode' => '<string>',
'achCorrectedAbaNumber' => '<string>',
'achCorrectedAccountNumber' => '<string>',
'achCorrectionDate' => '2023-11-07T05:31:56Z',
'debitStatus' => '<string>',
'debitDeclineReason' => '<string>',
'overallReturnCode' => '<string>',
'isMetadataError' => false
]
]
]),
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/ach-returns/batch"
payload := strings.NewReader("{\n \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\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/ach-returns/batch")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.finosu.com/ach-returns/batch")
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 \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"total_processed": 123,
"successful": 123,
"failed": 123,
"results": [
{
"success": true,
"payment_id": "<string>",
"message": "<string>",
"payment_method_disabled": true
}
]
}{
"detail": "<string>"
}{
"detail": "<string>"
}Payments
Submit ACH Returns (Batch)
Process a batch independently and inspect each result; HTTP 200 does not mean every item succeeded.
POST
/
ach-returns
/
batch
cURL
curl --request POST \
--url https://api.finosu.com/ach-returns/batch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"returns": [
{
"customerId": "<string>",
"loanId": "<string>",
"paymentId": "<string>",
"systemSource": "<string>",
"paymentDate": "2023-11-07T05:31:56Z",
"paymentReverseDate": "2023-11-07T05:31:56Z",
"paymentReversed": true,
"paymentReverseReasonCode": "<string>",
"paymentReverseComments": "<string>",
"paymentType": "<string>",
"paymentAmount": 123,
"achSubmittedDate": "2023-11-07T05:31:56Z",
"achSettlementDate": "2023-11-07T05:31:56Z",
"achStatus": "<string>",
"achReturnCode": "<string>",
"achReturnDate": "2023-11-07T05:31:56Z",
"achReturnReason": "<string>",
"achCorrectionCode": "<string>",
"achCorrectedAbaNumber": "<string>",
"achCorrectedAccountNumber": "<string>",
"achCorrectionDate": "2023-11-07T05:31:56Z",
"debitStatus": "<string>",
"debitDeclineReason": "<string>",
"overallReturnCode": "<string>",
"isMetadataError": false
}
]
}
'import requests
url = "https://api.finosu.com/ach-returns/batch"
payload = { "returns": [
{
"customerId": "<string>",
"loanId": "<string>",
"paymentId": "<string>",
"systemSource": "<string>",
"paymentDate": "2023-11-07T05:31:56Z",
"paymentReverseDate": "2023-11-07T05:31:56Z",
"paymentReversed": True,
"paymentReverseReasonCode": "<string>",
"paymentReverseComments": "<string>",
"paymentType": "<string>",
"paymentAmount": 123,
"achSubmittedDate": "2023-11-07T05:31:56Z",
"achSettlementDate": "2023-11-07T05:31:56Z",
"achStatus": "<string>",
"achReturnCode": "<string>",
"achReturnDate": "2023-11-07T05:31:56Z",
"achReturnReason": "<string>",
"achCorrectionCode": "<string>",
"achCorrectedAbaNumber": "<string>",
"achCorrectedAccountNumber": "<string>",
"achCorrectionDate": "2023-11-07T05:31:56Z",
"debitStatus": "<string>",
"debitDeclineReason": "<string>",
"overallReturnCode": "<string>",
"isMetadataError": False
}
] }
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({
returns: [
{
customerId: '<string>',
loanId: '<string>',
paymentId: '<string>',
systemSource: '<string>',
paymentDate: '2023-11-07T05:31:56Z',
paymentReverseDate: '2023-11-07T05:31:56Z',
paymentReversed: true,
paymentReverseReasonCode: '<string>',
paymentReverseComments: '<string>',
paymentType: '<string>',
paymentAmount: 123,
achSubmittedDate: '2023-11-07T05:31:56Z',
achSettlementDate: '2023-11-07T05:31:56Z',
achStatus: '<string>',
achReturnCode: '<string>',
achReturnDate: '2023-11-07T05:31:56Z',
achReturnReason: '<string>',
achCorrectionCode: '<string>',
achCorrectedAbaNumber: '<string>',
achCorrectedAccountNumber: '<string>',
achCorrectionDate: '2023-11-07T05:31:56Z',
debitStatus: '<string>',
debitDeclineReason: '<string>',
overallReturnCode: '<string>',
isMetadataError: false
}
]
})
};
fetch('https://api.finosu.com/ach-returns/batch', 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/ach-returns/batch",
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([
'returns' => [
[
'customerId' => '<string>',
'loanId' => '<string>',
'paymentId' => '<string>',
'systemSource' => '<string>',
'paymentDate' => '2023-11-07T05:31:56Z',
'paymentReverseDate' => '2023-11-07T05:31:56Z',
'paymentReversed' => true,
'paymentReverseReasonCode' => '<string>',
'paymentReverseComments' => '<string>',
'paymentType' => '<string>',
'paymentAmount' => 123,
'achSubmittedDate' => '2023-11-07T05:31:56Z',
'achSettlementDate' => '2023-11-07T05:31:56Z',
'achStatus' => '<string>',
'achReturnCode' => '<string>',
'achReturnDate' => '2023-11-07T05:31:56Z',
'achReturnReason' => '<string>',
'achCorrectionCode' => '<string>',
'achCorrectedAbaNumber' => '<string>',
'achCorrectedAccountNumber' => '<string>',
'achCorrectionDate' => '2023-11-07T05:31:56Z',
'debitStatus' => '<string>',
'debitDeclineReason' => '<string>',
'overallReturnCode' => '<string>',
'isMetadataError' => false
]
]
]),
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/ach-returns/batch"
payload := strings.NewReader("{\n \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\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/ach-returns/batch")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.finosu.com/ach-returns/batch")
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 \"returns\": [\n {\n \"customerId\": \"<string>\",\n \"loanId\": \"<string>\",\n \"paymentId\": \"<string>\",\n \"systemSource\": \"<string>\",\n \"paymentDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReverseDate\": \"2023-11-07T05:31:56Z\",\n \"paymentReversed\": true,\n \"paymentReverseReasonCode\": \"<string>\",\n \"paymentReverseComments\": \"<string>\",\n \"paymentType\": \"<string>\",\n \"paymentAmount\": 123,\n \"achSubmittedDate\": \"2023-11-07T05:31:56Z\",\n \"achSettlementDate\": \"2023-11-07T05:31:56Z\",\n \"achStatus\": \"<string>\",\n \"achReturnCode\": \"<string>\",\n \"achReturnDate\": \"2023-11-07T05:31:56Z\",\n \"achReturnReason\": \"<string>\",\n \"achCorrectionCode\": \"<string>\",\n \"achCorrectedAbaNumber\": \"<string>\",\n \"achCorrectedAccountNumber\": \"<string>\",\n \"achCorrectionDate\": \"2023-11-07T05:31:56Z\",\n \"debitStatus\": \"<string>\",\n \"debitDeclineReason\": \"<string>\",\n \"overallReturnCode\": \"<string>\",\n \"isMetadataError\": false\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"total_processed": 123,
"successful": 123,
"failed": 123,
"results": [
{
"success": true,
"payment_id": "<string>",
"message": "<string>",
"payment_method_disabled": true
}
]
}{
"detail": "<string>"
}{
"detail": "<string>"
}Request field names
Use camelCase request fields. Legacy snake_case names remain accepted, including within batches. If both names for a field are supplied, the camelCase value takes precedence. Response field names remain unchanged.Overview
This batch endpoint allows you to submit multiple ACH return records from external loan management systems (LMS) in a single API request for improved efficiency. Each return in the batch is processed independently with detailed individual results, making it ideal for processing daily ACH return files from banks or bulk syncing from your LMS system.ID Mapping
The endpoint uses the same reference ID mapping as the single ACH return endpoint:- customerId - Your customer reference ID
- loanId - Your loan reference ID
- paymentId - Maps to the ACH payment’s processor transaction ID
2026-09-30T12:00:00Z.
Optional date/time fields may be omitted or null.
Request Body Format
The batch endpoint accepts an array of ACH return records wrapped in areturns field:
{
"returns": [
{
"customerId": "CUST123",
"loanId": "LOAN456",
"paymentId": "PMT789",
"paymentDate": "2024-01-15T10:00:00Z",
"paymentAmount": "100.00",
"achReturnCode": "R01",
"achReturnDate": "2024-01-18T10:00:00Z",
"achReturnReason": "Insufficient Funds"
},
{
"customerId": "CUST124",
"loanId": "LOAN457",
"paymentId": "PMT790",
"paymentDate": "2024-01-15T10:00:00Z",
"paymentAmount": "150.00",
"achReturnCode": "R03",
"achReturnDate": "2024-01-18T10:00:00Z",
"achReturnReason": "No Account/Unable to Locate Account"
}
]
}
Individual Return Schema
Each object in thereturns array follows the same schema as the single ACH return endpoint:
Identifiers (Required):
customerId- Customer reference ID from your LMSloanId- Loan reference ID from your LMSpaymentId- The processor transaction ID for the ACH payment
systemSource- Source system identifierpaymentDate- Date payment was madepaymentAmount- Payment amount in dollars, as a JSON number or decimal stringpaymentType- Type of paymentpaymentReversed- Boolean indicating if payment was reversedpaymentReverseDate- Date payment was reversedpaymentReverseReasonCode- Code indicating reversal reasonpaymentReverseComments- Additional comments
achSubmittedDate- Date ACH was submittedachSettlementDate- Date ACH settledachStatus- External ACH status; numeric values and strings are accepted, with integration-specific mapping
achReturnCode- ACH return code, such as R01achReturnDate- Date of ACH returnachReturnReason- Human-readable return reason
achCorrectionCode- ACH correction codeachCorrectedAbaNumber- Corrected ABA routing numberachCorrectedAccountNumber- Corrected account numberachCorrectionDate- Date correction was received
debitStatus- Debit card transaction statusdebitDeclineReason- Reason for debit card decline
overallReturnCode- Combined return code from ACH or debit
Response Format
The batch endpoint returns detailed results for each ACH return processed:{
"success": true,
"total_processed": 2,
"successful": 2,
"failed": 0,
"results": [
{
"success": true,
"payment_id": "PMT789",
"message": "ACH return information successfully recorded",
"payment_method_disabled": null
},
{
"success": true,
"payment_id": "PMT790",
"message": "ACH return information successfully recorded",
"payment_method_disabled": null
}
]
}
Response Fields
- success -
trueif ALL returns were processed successfully,falseif any failed - total_processed - Total number of returns in the batch
- successful - Number of successfully processed returns
- failed - Number of failed returns
- results - Array of individual results for each return
- success - Whether this specific return was processed successfully
- payment_id - The payment ID from the request for easy matching
- message - Success or error message for this specific return
Partial Success Handling
The batch endpoint uses partial success handling to ensure maximum processing:- Individual failures don’t stop processing - If one return fails, the remaining returns are still processed
- Detailed error messages - Each failed return includes its specific error message
- Transaction isolation - Each return is processed in its own transaction to prevent one failure from affecting others
- Overall success flag - The top-level
successfield istrueonly if all returns succeeded
Example: Partial Failure Response
{
"success": false,
"total_processed": 3,
"successful": 2,
"failed": 1,
"results": [
{
"success": true,
"payment_id": "PMT789",
"message": "ACH return information successfully recorded",
"payment_method_disabled": null
},
{
"success": false,
"payment_id": "PMT790",
"message": "404: Customer with reference_id 'CUST999' not found",
"payment_method_disabled": null
},
{
"success": true,
"payment_id": "PMT791",
"message": "ACH return information successfully recorded",
"payment_method_disabled": null
}
]
}
payment_method_disabled in the response is a boolean or null when not applicable.
What the Endpoint Does
For each ACH return in the batch, Finosu:- Locates the records using the external reference IDs
-
Updates PaymentTransaction with:
- Payment reversal information (if applicable)
- Status change to RETURNED if ACH return exists
-
Updates AchPayment (if exists) with:
- ACH transaction dates
- Status mapping from your external status
-
Creates ACHReturnHistory when return information is present, with:
- ACH return code and reason
- ACH correction/NOC data
- Risk assessment tracking
- Action taken metadata
-
Triggers NSF revocation check (for R01/R09 returns):
- Automatically revokes payment methods after 2 consecutive NSF returns
When to Use Batch vs Single
Use the batch endpoint when:- Processing daily ACH return files from your bank
- Syncing multiple returns from your LMS system
- You have more than 5-10 returns to submit
- You want to minimize API calls for efficiency
- Processing real-time individual returns
- You only have 1-2 returns to submit
- You need simpler error handling
- Testing or debugging individual returns
Error Handling
A valid, authenticated batch returns HTTP status 200 OK, with detailed success/failure information in the response body for each individual return. Individual return errors may include:- 404 NOT FOUND - Customer, loan, or payment not found with provided IDs
- 422 UNPROCESSABLE CONTENT - ACH payment does not belong to the specified loan, or has no associated payment method
- 500 INTERNAL SERVER ERROR - Server error during processing
results array in the response to see which returns succeeded and which failed.
Authentication
Authentication via X-API-Key header:- API key is company-scoped
- Must be obtained from Finosu
- Same authentication as single ACH return endpoint
Example Usage
This endpoint is typically used for:- Daily bank reconciliation - Process ACH return files from your bank
- Bulk LMS sync - Sync multiple return records from your loan management system
- Scheduled jobs - Automated daily/weekly return processing workflows
401; invalid request structure returns 422.
A 200 batch response does not mean every item succeeded; inspect success,
successful, failed, and each entry in results. Item failures are reported
in the response body rather than as the HTTP status of the entire batch.
An active return-note delivery can cause an item to fail with a 503 message while the batch response remains 200. Retry the failed item later.
A validation failure for an individual payment is reported with a 422: message prefix in its result; the batch HTTP status remains 200. Unexpected processing failures use a Failed to process ACH return: message prefix without a status-code prefix. Inspect each item’s success value; do not rely on numeric message prefixes alone.Body
application/json
Batch request schema for multiple ACH returns from external LMS. Accepts an array of ACH return records for efficient bulk processing. Use camelCase fields; legacy snake_case aliases are also accepted. If both spellings are supplied, camelCase takes precedence.
Response
Batch processing results.
Response schema for batch ACH return submission.