Send the list to POST /customers/batch with scheduleMode: "enroll".
Finosu stores the upload, divides it into internal chunks, and enrolls each
application using the same cadence and validation rules as
individual enrollment.
Your integration does not need to make one request per CSV row.
Use one company API key per list. That key selects the company and its configured
portfolio; body fields cannot select a different company or enable another cadence.
Send a list
Use a stable Idempotency-Key header for the whole list and a stable
idempotencyKey in each row for that enrollment operation. These are different
keys with different purposes. Keep customer and application references consistent
with previous CSV uploads.
The example combines two modes. Each must be enabled for the authenticated
company. Unsupported modes fail for the affected rows; they do not enable new
portfolio capabilities. Returning borrowers without oneOff can include
daysSincePaidOff for the existing returning cadence.
Row fields follow the enrollment field contract,
plus the required idempotencyKey. Row-level scheduleMode can be omitted;
if present it must be "enroll". The outer scheduleMode is always required.
Send isTest for test enrollments. The legacy test field is deprecated and removed on
25 October 2026, the same deadline as customer creation and single enrollment. Either
spelling is accepted until then; conflicting values or explicit null flags fail only the
affected row. Omitting both defaults to false.
Always send the outer scheduleMode: "enroll". The existing customer-create
workflow uses this URL without a mode. Enrollment row keys without the outer
mode are rejected to prevent accidental customer-create processing.
See Batch API reference for the shared
request schema and playground.
Acceptance and progress
A successful submission returns HTTP 202, Location, and a job ID:
Poll the Location URL with the same company’s API key. Start with a few seconds
between polls and increase the interval for longer-running jobs.
The batch status endpoint returns:
status: pending, processing, completed, failed, or cancelled.
processed: successfully handled rows, including saved receipt replays and
applications that were already scheduled.
failed: rejected rows or rows that exhausted processing retries.
progressPercentage: handled rows divided by the submitted count.
results: outcomes ordered by the original zero-based index. Each includes
customerId, loanId, status, replayed, and retryable. Successful rows
include the origination receipt; failures include code and message.
failures: the failed rows with their original index, customer reference,
and message, for compatibility with existing batch clients.
Results appear as rows finish. A terminal completed job can have failed rows
when at least one row succeeded; always inspect failed and results. A job
with no successful rows ends as failed. A failure before the source can be read
may have empty customer/application references; its original index still
identifies the row in your submitted list.
A saved schedule does not mean a call has connected. Use the receipt’s
scheduledCallId to inspect the current call status.
Receipts are scheduling snapshots, not current borrower eligibility.
Retry without duplicate enrollments
- Submission timeout or
503: retry the identical ordered list with the
same header key. If accepted previously, the same job is returned with
Idempotency-Replayed: true. A changed list under that key returns 409.
JSON object-key order is ignored; array order and submitted values must match.
- Worker interruption: Finosu resumes processing and skips committed row
results. Enrollment and its result are committed together.
- Retryable failed row: submit that row in a new list with a new header
key, retaining its original row
idempotencyKey and payload. Replaying a
terminal list returns the existing job; it does not restart failed rows.
- Invalid row: correct the data and submit a new list. A rejected validation
does not consume an enrollment receipt. If a key has already produced a saved
receipt, changing its enrollment payload returns a conflict.
- Contact or application conflict: review the reason before resubmitting.
Enrollment cannot clear DNC or restart a finished/paused cadence.
Row keys share the individual enrollment key namespace within the company. A
row submitted through batch and the single-record endpoint with the same key
and normalized enrollment fields returns the same enrollment receipt. Use a
separate row key for each distinct enrollment operation; do not reuse it for
unrelated customers or applications.
Limits and processing behavior
- Up to 10,000 records per request and 10 MiB of serialized customer
data. Split larger lists into multiple batches with separate header keys.
- Up to 10 batch submissions per minute per company, including submission
retries. Honor
Retry-After on 429 and 503.
- Finosu processes internal chunks of 25 records in the background. The
single-record endpoint’s 60-request/minute quota does not apply per batch row.
- Rows and chunks can finish out of order. The list is not one transaction:
valid rows can succeed while others fail. Do not depend on list order to apply
multiple changes to the same customer.
- Invalid envelopes return
422 before queuing. Oversized customer data returns
413. Invalid enrollment fields, disabled modes and application conflicts are
reported per row after acceptance.
- The normal scheduler still enforces contact restrictions, calling hours,
phone rotation and the configured transfer routing. Batch intake does not
change those settings or imply immediate calls.
Batch enrollment does not replace the funded/stop workflow or enable LMS notes
and flags. See funded applications.