Skip to main content
POST
Report the outcomes of your debits via CSV upload

Report Payment Results (CSV)

Upload a CSV of debit outcomes: which debits settled, which were returned, and why. Use it for debits Rightfoot cannot read from your payment processor itself, such as debits run from your LMS or through a processor you have not connected. Each row is matched to a borrower and recorded as if Rightfoot had read it from your payment processor. Results you upload show up in Retrieve Payment Results, and a return you report affects that borrower’s monitoring.

Key Information

File Size Limit: 10 MB
Content-Type: multipart/form-data, with the file in a part named file
Encoding: UTF-8
Preview: dryRun=true returns the full report and writes nothing

CSV Format

One row per debit. Headers are case-insensitive, and spaces and punctuation are read as underscores, so Payment Date is the same column as payment_date. The file must have an amount, status, date and return code column, plus at least one of authorizer_unique_id or reference. A cell can be blank when it does not apply. For example, return_code and returned_at are blank on a settled debit. Blank rows and summary rows (no identifier and no status, such as a totals line) are skipped. Cells containing #N/A, N/A or - are read as blank.
You can also upload a Rightfoot balance export with your own outcome columns added. Add payment_status, payment_amount, payment_date, settled_at, returned_at and return_code to the export and upload it as-is. Its own Status column holds the balance-check status, so your payment_status column takes precedence over it.

Statuses

Values are case-insensitive. A row with any other status is rejected and listed in problems.

Return codes

On a returned or late_return row, return_code must be a NACHA R-code. R01, r01, R1 and R01 - Insufficient Funds are all read as R01. The text insufficient funds is also read as R01, and payment stopped as R08. A return with any other text, a blank cell or 0 is rejected: without the code, Rightfoot cannot tell whether the borrower may be debited again. A settled row must not have a return code. On other statuses, a code is stored as you sent it.

Validation

Each row is checked on its own. A row that fails is rejected and every reason is listed in problems. The rest of the file is still recorded, so fix the rejected rows and upload them again. A row is rejected when:
  • a required value is missing or can’t be read: amount, status, submitted_at, an identifier, or the outcome date and return code its status requires
  • settled_at or returned_at is earlier than submitted_at, or more than a day in the future
  • a late_return has a returned_at earlier than its settled_at
  • a settled row has a return_code

What a reported return does

A return you report counts the same as one Rightfoot reads from your payment processor:
  • R01 and R09 (insufficient or uncollected funds): the borrower stays eligible, and Rightfoot can retry the debit when there is enough in the account.
  • Any other return code stops monitoring for that borrower. NACHA does not allow a debit to be re-presented after these codes without corrective action, such as a new authorization or a different account.
This applies only to rows matched to an enrolled borrower.

Matching

A row with an authorizer_unique_id is matched to that borrower. A row with only a reference is matched when the reference identifies the borrower, for example when it contains their authorizer_unique_id. If a reference does not clearly identify one borrower, Rightfoot leaves the row unmatched rather than guessing. An unmatched row is still stored. It is counted in needsAttention and listed in problems as a warning. To match it, upload the row again with the authorizer_unique_id filled in.

Re-sending a file

Re-uploading is safe. Rows are keyed on reference, so the same debit is never recorded twice:
  • A row whose status differs from the last one recorded for that reference records the new status. A debit can therefore go from sent to settled to late_return over successive files.
  • A row identical to what is already recorded changes nothing. If Rightfoot recorded the status without a date, the row’s settled_at or returned_at fills it in. A date already recorded is never changed.
  • A row whose outcome date is earlier than the latest recorded outcome for its reference is ignored and listed as a warning, so an old export cannot overwrite newer results. A row with an undated status, such as sent, never replaces a settled or returned outcome.
Within one file, duplicate rows for the same reference are counted once. If two rows for the same reference disagree, all rows for that reference are rejected.
Send a reference on every row. A row without one is keyed on borrower, amount and date. Two debits to the same borrower for the same amount on the same day would then be recorded as one.

Reading the report

A file that can be parsed always returns 200. Check the report rather than the status code:
  • dataRowCount is the number of data rows found in the file. rowCount is how many of those were accepted, and matched and needsAttention split the accepted rows by whether a borrower was found.
  • Each entry in problems has a severity. An error row was not recorded, and warning means the row was recorded but something was ignored, or it is unmatched. A row can have several error entries, one per issue. A row of 0 is a problem with the file as a whole, such as missing columns.
400 is returned only when the file is rejected before any row is read: it is over 10 MB, or it is not UTF-8 text.

Authorizations

Authorization
string
header
required

Authentication to the API is performed via Bearer Token Authentication. Provide your API key as the bearer token in the Authorization header.

All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.

Query Parameters

dryRun
boolean
default:false

Validate and match the file without writing anything.

Body

multipart/form-data
file
file
required

CSV of debit outcomes, one row per debit. See the column reference on this page.

Response

The file was processed. Check needsAttention and problems: a row can be stored but unmatched, or skipped entirely.

format
enum<string>

How the file was read. annotated_export is a Rightfoot balance export with your outcome columns added; anything else is generic.

Available options:
generic,
annotated_export
rowCount
integer

Rows accepted for matching and recording.

dataRowCount
integer

Data rows found in the file, excluding blank and summary rows.

matched
integer

Accepted rows matched to a borrower.

needsAttention
integer

Accepted rows Rightfoot could not match to a borrower. They are stored, and re-uploading them with an authorizer_unique_id matches them.

dryRun
boolean

Echoes the dryRun parameter. When true, nothing was written.

rows
object[]

One entry per accepted row.

problems
object[]

Everything that needs your attention. An error row was not recorded; a warning row was recorded, but something was ignored or it is unmatched. row is 0 for a problem with the file as a whole.