Autopay
Enroll a borrower-authorized instrument, initiate one payment per due obligation under explicit timing and amount policies, and govern failures with per-rail return-code policy.
Autopay is a policy-driven payment initiator. It reads the current due obligation and creates a normal payment intent with source: "AUTOPAY"; it never posts directly to the ledger or bypasses payment validation and restrictions. Each loan has at most one current enrollment at /v1/loans/{loanId}/autopay.
Enrollment lifecycle
Amount policies
amountPolicy.type |
Draw amount | Typical use |
|---|---|---|
FULL_DUE |
All currently due components at initiation. | Statement-noticed variable amounts, like Harbor. |
MIN_DUE |
The minimum due for the target installment after posted activity. | Keeping an account current without sweeping extra charges. |
FIXED |
The authorized fixedAmount (with currency), capped by current eligibility. |
Voluntary recurring overpayment or a payment plan. |
FIXED does not silently rise to cover a larger amount due, and FULL_DUE is accepted only when the product’s statement lead leaves room for the ten-day advance notice described below.
Timing policy
timingPolicy states exactly when a draw is initiated relative to each due date:
initiateDaysBeforeDue—how many days ahead the payment intent is created;businessDayConvention—PRECEDING,FOLLOWING, orNONEwhen the computed date lands on a non-business day; andonScheduleChange—FOLLOW_NEW_SCHEDULEto track a rescheduled due date automatically, orREVIEW_REQUIREDto hold draws for human review after a schedule change.
Enroll Harbor
Harbor Personal Loan
Fixed-rate installment loan
- Contract principal
- $8,400.00
- Nominal rate
- 13.25% fixed
- Term
- 18 monthly payments
- Prepaid origination fee
- $252.00
- Payment
- $517.14
- Disclosed APR
- 17.291%
curl -X POST "$BASE/v1/loans/7204/autopay" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: harbor-autopay-enrollment-01" \
-d '{
"instrumentId": 704,
"authorizationRef": "evd_JUN_AP_73",
"timingPolicy": { "initiateDaysBeforeDue": 0, "businessDayConvention": "FOLLOWING" },
"amountPolicy": { "type": "FULL_DUE" }
}'
The command envelope ({ "resourceId": 31 }) confirms enrollment; GET /v1/loans/7204/autopay returns the canonical state:
{
"loanRef": "7204",
"status": "ACTIVE",
"instrument": { "instrumentId": 704, "maskedDisplay": "••6789" },
"timingPolicy": { "initiateDaysBeforeDue": 0, "businessDayConvention": "FOLLOWING", "onScheduleChange": "FOLLOW_NEW_SCHEDULE" },
"amountPolicy": { "type": "FULL_DUE" },
"authorizationRef": "evd_JUN_AP_73",
"consecutiveFailureCount": 0,
"effectiveDate": "2026-08-21"
}
The instrument must be ACTIVE and VERIFIED and belong to the borrower. Each cycle, autopay re-reads the due facts, instrument status, and restrictions, then creates one idempotently keyed payment intent per enrollment and due obligation—scheduler retries cannot create a duplicate draw. A manual payment that already covers the installment suppresses the draw; autopay does not send a $0 request or charge the original schedule amount anyway.
Regulation E authorization and notice
authorizationRef is required at enrollment: it references the borrower’s preauthorized-transfer authorization evidence, and no draw is initiated without it. For transfers that vary in amount, Regulation E § 1005.10(d) describes advance notice of the amount and date, generally at least 10 days before the scheduled transfer.
The due-date statement is the notice artifact for FULL_DUE enrollments, which is why enrollment is coupled to the product’s statementLeadDays: a lead shorter than the notice window rejects the enrollment rather than producing draws without compliant notice. Cancelling autopay is treated as a Regulation E revocation.
Pause, resume, and cancel
POST /v1/loans/{loanId}/autopay/pause, …/resume, and …/cancel each require a reasonCode from the closed catalog, with an optional comment:
BORROWER_REQUEST · STAFF_REQUEST · PAYMENT_RETURN_ACCOUNT_OWNERSHIP · RESTRICTION_CASCADE · FAILURE_POLICY · LOAN_CLOSED · REVIEW_RESOLVED · OTHER_DOCUMENTED
Pause stops initiation but keeps the enrollment and its authorization. Resume works from PAUSED or REVIEW_REQUIRED and clears the review reason and failure count; missed cycles are not automatically swept into catch-up draws. Cancel works from any state, cancels the enrollment’s pending unsubmitted payment intents, and is the revocation of record. A request that would repeat the current state is a successful no-op, and human calls carry the LendEasy-Case header when case management is enabled. Restrictions cascade too: an AUTOPAY_HOLD or COLLECTIONS_HOLD pauses the enrollment in the same transaction, and deactivating the instrument moves it into review.
Failure policies
How a returned draw is handled is tenant-level, per-rail policy—not product configuration. GET /v1/autopay/failure-policies returns the current policy for each rail, and PUT /v1/autopay/failure-policies/{rail} (rail ACH or CARD) replaces one rail’s policy in full:
{
"automaticRetry": true,
"retryAfterBusinessDays": 2,
"maxRetryAttempts": 2,
"maxConsecutiveFailedCycles": 3,
"runNextScheduledCycle": true,
"exhaustionAction": "REVIEW_REQUIRED",
"returnCodes": [
{ "returnCode": "R01", "retryAllowed": true, "instrumentAction": "KEEP", "autopayAction": "CONTINUE", "caseAction": "NONE", "recommendedAction": "NONE", "treatAsUnauthorized": false },
{ "returnCode": "R10", "retryAllowed": false, "instrumentAction": "INVALIDATE", "autopayAction": "CANCELLED", "caseAction": "OPEN_PAYMENT_FAILURE", "recommendedAction": "CANCEL_AUTOPAY", "treatAsUnauthorized": true }
]
}
Each return-code row decides retry eligibility, the instrument’s fate (KEEP or INVALIDATE), the enrollment reaction (CONTINUE, REVIEW_REQUIRED, or CANCELLED), whether a payment-failure case opens, and whether the code is treated as an unauthorized-debit claim. The base fields govern retry pacing and exhaustion: the enrollment’s consecutiveFailureCount accumulates until maxConsecutiveFailedCycles triggers the exhaustionAction. An unknown return code always fails closed into review and blocks secondary automation.
What to monitor
- draws initiated versus due obligations;
- draws suppressed by prior manual payments;
- statement lead versus the notice window on
FULL_DUEenrollments; - settlement and return rates by rail and instrument;
- consecutive failures and enrollments in
REVIEW_REQUIRED; and - return codes falling through to the fail-closed review path.
An active enrollment that skips an eligible due date, or two intents for the same due obligation, is an invariant breach and raises a reconciliation incident.