Authentication for this flow. Call POST /api/Auth/Token with your Main-Token and X-OTP to obtain a JWT, then send Authorization: Bearer <JWT> on every other call — only the token call needs a TOTP code. Your base URL and credentials are issued at onboarding.
Prerequisites
Complete these once per customer before running the flow below. They are not part of the numbered steps.
PREOnboard the consumerPOST
/api/Consumer

Create the consumer on your vendor account. consumer1 is the primary applicant and consumer2 is an optional co-applicant. Set consumerType to Business and supply businessInfo with its principals for a business consumer.

Request Body Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
consumerTypeenumREQUIREDIndividual or Business.
accountStatusenumREQUIREDActive, Cancelled, Completed, OnHold or OnHoldRequest.
affiliateIdintREQUIREDYour affiliate ID, issued at onboarding.
feeSplitGroupIdintREQUIREDFee split group the consumer is enrolled under.
consumer1objectREQUIREDPrimary consumer on the account.see fields below
consumer1.firstNamestringREQUIREDLegal first name.
consumer1.lastNamestringREQUIREDLegal last name.
consumer1.taxIdstringREQUIREDSSN, 9 digits, no dashes.
consumer1.dateOfBirthdateREQUIREDDate of birth, YYYY-MM-DD.
consumer1.addressstringREQUIREDStreet address.
consumer1.citystringREQUIREDCity.
consumer1.statestringREQUIREDTwo-letter state abbreviation.
consumer1.zipstringREQUIREDZIP code.
consumer1.phonestringREQUIREDPrimary contact number.
consumer1.emailstringREQUIREDContact email. Statement and notice delivery uses this address.
additionalPhonestringoptionalSecondary contact number.
curl --request POST \ --url 'https://FQDN/api/Consumer' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json' \ --data '[ { "consumerType": "Individual", "accountStatus": "Active", "affiliateId": 20, "feeSplitGroupId": 3, "consumer1": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "1980-01-15", "address": "123 Main St", "city": "Anytown", "state": "CA", "zip": "90001", "phone": "555-123-4567", "email": "john.doe@example.com" } } ]'
const options = { method: 'POST', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' }, body: JSON.stringify([ { "consumerType": "Individual", "accountStatus": "Active", "affiliateId": 20, "feeSplitGroupId": 3, "consumer1": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "1980-01-15", "address": "123 Main St", "city": "Anytown", "state": "CA", "zip": "90001", "phone": "555-123-4567", "email": "john.doe@example.com" } } ]) }; fetch('https://FQDN/api/Consumer', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Consumer" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } payload = [ { "consumerType": "Individual", "accountStatus": "Active", "affiliateId": 20, "feeSplitGroupId": 3, "consumer1": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "1980-01-15", "address": "123 Main St", "city": "Anytown", "state": "CA", "zip": "90001", "phone": "555-123-4567", "email": "john.doe@example.com" } } ] resp = requests.post(url, headers=headers, json=payload) print(resp.json())
{ "isSuccess": true, "results": [ { "request": { ... }, "isSuccess": true, "errorMessage": [] } ] }
consumerType
Individual or Business.
consumer1 / consumer2
Primary applicant and optional co-applicant.
feeSplitGroupId
From GET /api/Lookup/FeeSplitGroup.
Returns
consumerId — the account number used on every later call.
PREAdd the creditorPOST
/api/Creditor

Register the creditor addresses you will settle against. Each is validated and de-duplicated — if the address already exists the existing creditor UID is returned instead of a duplicate. Results come back per creditor, so partial failures are visible alongside successes.

Request Body Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
namestringREQUIREDCreditor name.
addressstringREQUIREDStreet address line 1.
address2stringoptionalStreet address line 2 (suite, unit, etc.).
citystringREQUIREDCity.
statestringREQUIREDTwo-letter state abbreviation.
zipstringREQUIREDZIP code.
curl --request POST \ --url 'https://FQDN/api/Creditor' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json' \ --data '[ { "name": "Capital One", "address": "1600 Capital One Drive", "address2": "", "city": "McLean", "state": "VA", "zip": "22102" } ]'
const options = { method: 'POST', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' }, body: JSON.stringify([ { "name": "Capital One", "address": "1600 Capital One Drive", "address2": "", "city": "McLean", "state": "VA", "zip": "22102" } ]) }; fetch('https://FQDN/api/Creditor', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Creditor" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } payload = [ { "name": "Capital One", "address": "1600 Capital One Drive", "address2": "", "city": "McLean", "state": "VA", "zip": "22102" } ] resp = requests.post(url, headers=headers, json=payload) print(resp.json())
{ "isSuccess": true, "results": [ { "request": { ... }, "isSuccess": true, "errorMessage": [] } ] }
state
Validated against known state codes.
Returns
creditorAddressUid — required by Add Settlement.
  • 1
    YouSchedule payment drafts
    POST /Drafts
  • RAMFiExecute ACH draft
    RAMFi drafts the consumer bank
  • BanksConsumer bank debited
    clears ~2 business days
  • 2
  • RAMFiFlag returns / hold
    RAMFi reports NSF, sets Hold
  • 3
    YouSettle with the creditor
    POST /Settlement
  • RAMFiDisburse settlement
    RAMFi sends to creditor
  • BanksCreditor credited
    settlement complete
  • 4
    YouRefund remainder
    POST /Consumer/Refunds
  • RAMFiDisburse to consumer
    RAMFi refunds the balance
Show full interaction diagram
Your ApplicationRAMFiBanks (Consumer / Creditor)1Schedule recurring draftcall POST /DraftsExecute ACH draftRAMFi drafts the consumer bankConsumer bank debitedclears ~2 business days2Monitor returnscall GET /Reporting/ConsumerReturnsFlag returns / holdRAMFi reports NSF, sets Hold3Pay the creditorcall POST /SettlementDisburse settlementRAMFi sends to creditorCreditor creditedsettlement complete4Refund remaindercall POST /Consumer/RefundsDisburse to consumerRAMFi refunds the balance

Settlement lifecycle. App-lane boxes are API calls; RAMFi runs KYC, executes drafts, flags returns, and disburses. The Banks lane shows where money settles.

Your application orchestrates; Reliant performs. Every call below runs against Reliant. Reliant holds the funds, drafts the consumer, issues settlement payments to creditors, and tracks returns and fees. Your app issues the requests; it never holds funds.
Funding the program: store the consumer’s bank details with POST /api/Consumer/ConsumerBankInfo, then post the payment schedule with POST /api/Drafts. Each draft accrues a savingsAmount that funds later settlements.
🔄
Consumer Status Lifecycle
How a consumer moves between account status values, based on documented transitions.
POST /api/ConsumerActiveOnHoldCompletedCancelledACH draft returnedPUT /ConsumerStatus → ActivePUT /ConsumerStatus → CompletedPUT /ConsumerStatus → CancelledStatuses are sent and returned as names: Active, Cancelled, Completed, OnHold.

Consumer account status transitions. A returned draft moves the consumer to OnHold; PUT /api/Consumer/ConsumerStatus restores Active and also ends the account as Completed or Cancelled.

ℹ️
Account status values: Active, Cancelled, Completed, OnHold — sent and returned as names. Only an Active consumer is eligible to be drafted.

Steps
1Schedule the payment draftsPOST
/api/Drafts

Post the consumer’s payment schedule. Each draft splits into fee buckets plus a savingsAmount that accrues toward settlements. Send the whole schedule in one array; each row is validated independently.

Query Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
keepUnpaidPaymentsbooleanREQUIREDKeep drafts already scheduled but not yet paid. Send false to replace the schedule outright.
Request Body Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
consumerIdintREQUIREDConsumer the schedule belongs to.
draftIdintREQUIREDSend 0 for a new draft; an existing ID updates that draft.
paymentDatedatetimeREQUIREDDate the draft is pulled from the consumer's bank account.
totalPaymentAmountnumberREQUIREDTotal drafted on this date — fees plus savings.
savingsAmountnumberREQUIREDPortion held in the consumer's trust account toward settlements.
fee1AmountnumberoptionalFirst fee component.
fee2AmountnumberoptionalSecond fee component.
returnedbooleanoptionalLeave false when scheduling; set by the platform if the draft is returned.
extendedIdstringoptionalYour own reference for this draft. Echoed back on returns and reporting.
isAdHocbooleanoptionaltrue for a one-off draft outside the recurring schedule.
curl --request POST \ --url 'https://FQDN/api/Drafts' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json' \ --data '[ { "consumerId": 1001, "draftId": 0, "paymentDate": "2026-08-15T00:00:00", "fee1Amount": 75.00, "fee2Amount": 25.00, "savingsAmount": 150.00, "totalPaymentAmount": 250.00, "returned": false, "extendedId": "DRAFT-2026-12345", "isAdHoc": false } ]'
const options = { method: 'POST', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' }, body: JSON.stringify([ { "consumerId": 1001, "draftId": 0, "paymentDate": "2026-08-15T00:00:00", "fee1Amount": 75.00, "fee2Amount": 25.00, "savingsAmount": 150.00, "totalPaymentAmount": 250.00, "returned": false, "extendedId": "DRAFT-2026-12345", "isAdHoc": false } ]) }; fetch('https://FQDN/api/Drafts', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Drafts" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } payload = [ { "consumerId": 1001, "draftId": 0, "paymentDate": "2026-08-15T00:00:00", "fee1Amount": 75.00, "fee2Amount": 25.00, "savingsAmount": 150.00, "totalPaymentAmount": 250.00, "returned": false, "extendedId": "DRAFT-2026-12345", "isAdHoc": false } ] resp = requests.post(url, headers=headers, json=payload) print(resp.json())
{ "isSuccess": true, "results": [ { "request": { ... }, "isSuccess": true, "errorMessage": [] } ] }
draftId
0 for a new draft.
savingsAmount
Portion accruing toward settlements.
totalPaymentAmount
Fees + savings for that date.
isAdHoc
true for a one-off outside the schedule.
2Monitor returnsGET
/api/Reporting/ConsumerReturns

Poll for drafts that failed after initiation (NSF, closed account). A return carries the reason in notes and any companyReturnFee assessed. Resolve the underlying issue before the next scheduled draft.

Query Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
datedateREQUIREDReport date, YYYY-MM-DD. Returns are reported one day at a time.
curl --request GET \ --url 'https://FQDN/api/Reporting/ConsumerReturns' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json'
const options = { method: 'GET', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' } }; fetch('https://FQDN/api/Reporting/ConsumerReturns', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Reporting/ConsumerReturns" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } resp = requests.get(url, headers=headers) print(resp.json())
[ { "consumerId": "1001", "name": "John Doe", "amount": 250.00, "debitDate": "06/14/2026", "notes": "Insufficient funds", "returnDate": "06/15/2026", "companyReturnFee": 25.00, "pmtNumber": 4, "totalDraftFees": 75.00, "paymentId": "PMT-12345" } ]
notes
Return reason, e.g. Insufficient funds.
companyReturnFee
Fee assessed for the return.
pmtNumber
Which scheduled payment returned.
3Settle with the creditorPOST
/api/Settlement

Pay the creditor from accrued savings. paymentType selects the rail — RamCheck (physical check, 3+ business days), EftAch (2+ business days), Wire (same-day, 12:00 PM Pacific cutoff) or PayByPhone. EftAch and Wire additionally require the payee bank fields.

Request Body Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
settlementIdintREQUIREDSend 0 for a new settlement.
accountNumberintREQUIREDConsumer ID the settlement is paid from.
paymentAmountnumberREQUIREDAmount paid to the creditor on this leg.
paymentDatedatetimeREQUIREDDate the payment is due to the creditor.
paymentTypeenumREQUIREDRamCheck, WireTransfer, EftAch, MoneyOrder, PayByPhone or AchDebt.
payeeNamestringREQUIREDWho the payment is made out to — often a collection agency rather than the original creditor.
creditorAddressUidintREQUIREDCreditor address UID returned when the creditor was added.
payeeConsumerAccountNumberstringREQUIREDThe consumer's account number with the creditor.
creditorNamestringREQUIREDOriginal creditor name.
referenceNumberstringREQUIREDYour reference for this settlement.
debtAmountnumberoptionalOriginal debt balance, for reporting.
totalFeeAmountnumberoptionalTotal fees applied to this settlement.
curl --request POST \ --url 'https://FQDN/api/Settlement' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json' \ --data '[ { "settlementId": 0, "accountNumber": 1001, "paymentAmount": 550.00, "paymentDate": "2026-08-15T00:00:00", "paymentType": "RamCheck", "payeeName": "ABC Collections", "creditorAddressUid": 101, "payeeConsumerAccountNumber": "CL-123456", "creditorName": "Capital One", "referenceNumber": "SET-2026-5001", "debtAmount": 1200.00, "totalFeeAmount": 150.00 } ]'
const options = { method: 'POST', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' }, body: JSON.stringify([ { "settlementId": 0, "accountNumber": 1001, "paymentAmount": 550.00, "paymentDate": "2026-08-15T00:00:00", "paymentType": "RamCheck", "payeeName": "ABC Collections", "creditorAddressUid": 101, "payeeConsumerAccountNumber": "CL-123456", "creditorName": "Capital One", "referenceNumber": "SET-2026-5001", "debtAmount": 1200.00, "totalFeeAmount": 150.00 } ]) }; fetch('https://FQDN/api/Settlement', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Settlement" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } payload = [ { "settlementId": 0, "accountNumber": 1001, "paymentAmount": 550.00, "paymentDate": "2026-08-15T00:00:00", "paymentType": "RamCheck", "payeeName": "ABC Collections", "creditorAddressUid": 101, "payeeConsumerAccountNumber": "CL-123456", "creditorName": "Capital One", "referenceNumber": "SET-2026-5001", "debtAmount": 1200.00, "totalFeeAmount": 150.00 } ] resp = requests.post(url, headers=headers, json=payload) print(resp.json())
{ "isSuccess": true, "results": [ { "request": { ... }, "isSuccess": true, "errorMessage": [] } ] }
settlementId
0 for a new settlement.
accountNumber
The consumerId.
paymentType
Sent as the name: RamCheck, EftAch, Wire, PayByPhone.
creditorAddressUid
From Add Creditor.
payeeBank* fields
Required for EftAch and Wire only.
4Refund the remainderPOST
/api/Consumer/Refunds

Return any unused balance to the consumer once the program completes or is cancelled.

Request Body Parameters — enter values to build the request
FieldTypeRequiredDescriptionValue
consumerIdintREQUIREDConsumer receiving the refund.
fundingSourceIdintREQUIREDFunding source the refund is drawn from.
amountnumberREQUIREDAmount to refund.
scheduleDatedatetimeREQUIREDDate the refund is released.
refundMethodenumREQUIREDACH, Check, OvernightCheck or ConsumerTrust.
extendedIdstringREQUIREDYour reference for this refund.
tCodestringoptionalTransaction code, when your program uses one.
tSubCodeintoptionalTransaction sub-code.
curl --request POST \ --url 'https://FQDN/api/Consumer/Refunds' \ --header 'Authorization: Bearer <JWT>' \ --header 'Content-Type: application/json' \ --data '[ { "consumerId": 1001, "amount": 250.00, "fundingSourceId": 1, "refundMethod": "ACH", "tCode": "R", "tSubCode": 1, "extendedId": "REFUND-2026-12345" } ]'
const options = { method: 'POST', headers: { 'Authorization': 'Bearer <JWT>', 'Content-Type': 'application/json' }, body: JSON.stringify([ { "consumerId": 1001, "amount": 250.00, "fundingSourceId": 1, "refundMethod": "ACH", "tCode": "R", "tSubCode": 1, "extendedId": "REFUND-2026-12345" } ]) }; fetch('https://FQDN/api/Consumer/Refunds', options) .then(r => r.json()) .then(console.log);
import requests url = "https://FQDN/api/Consumer/Refunds" headers = { "Authorization": "Bearer <JWT>", "Content-Type": "application/json" } payload = [ { "consumerId": 1001, "amount": 250.00, "fundingSourceId": 1, "refundMethod": "ACH", "tCode": "R", "tSubCode": 1, "extendedId": "REFUND-2026-12345" } ] resp = requests.post(url, headers=headers, json=payload) print(resp.json())
{ "isSuccess": true, "results": [ { "request": { ... }, "isSuccess": true, "errorMessage": [] } ] }
refundMethod
Rail used to return the funds.
extendedId
Your reconciliation reference.
Returns loop: a returned draft moves the consumer to OnHold. Resolve the underlying issue, then PUT /api/Consumer/ConsumerStatus back to Active before the next scheduled draft.
RAMFi Developer Documentation · Version 1.1