Free tools / SEPA & NACHA Payment File API
Validate a NACHA (ACH) file online
Drop a US ACH file in NACHA format below. You get every record checked, the batch and file totals recomputed, and each problem with its line, column and a plain explanation, before the bank rejects the file.
- Free, no sign-up
- Your file is never stored
- Deterministic: no AI guesswork
Try it now
The demo runs the same validation as the API. Your file is read in memory and discarded right after. Please do not upload a real file with real account numbers: use a test file or one of the samples.
The live demo needs JavaScript, which seems to be switched off. The sample tabs show the engine's real output without it.
Free: 5 runs a day, no sign-up. Files that cannot be read do not count.
A PPD payroll file (three credits) generated by the API from a three-line CSV. Every check passes. Names, accounts and routing numbers are made up.
ach-ppd-payroll.ach 950 bytes · NACHA PPD
Input file
101 07400001012345678902610210900A094101SAMPLE BANK ACME PAYROLL INC
5220ACME PAYROLL 1234567890PPDPAYROLL 261023 1074000010000001
6221210003584400123456 0000185000 MARIA LOPEZ 1074000010000001
705OCTOBER SALARY 00010000001
63202200006277-1290 0000231045 SAM O'BRIEN 1074000010000002
705OCTOBER SALARY 00010000002
6220610001599100022 0000167520 LEE CHEN 0074000010000003
822000000500204000560000000000000000005835651234567890 074000010000001
9000001000001000000050020400056000000000000000000583565
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
Validation result
VALID 0 errors · 0 warnings
- ACME PAYROLL INC
- 2026-10-21
- Batches · entries
- 1 · 3
- Total debit
- 0.00 USD
- Total credit
- 5835.65 USD
No problems found. Record lengths, routing check digits, trace numbers, entry hash, totals and block count all pass.
JSON response POST /v1/ach/validate
{
"format": "nacha",
"valid": true,
"error_count": 0,
"warning_count": 0,
"summary": {
"immediate_destination": "074000010",
"immediate_destination_name": "SAMPLE BANK",
"immediate_origin": "1234567890",
"immediate_origin_name": "ACME PAYROLL INC",
"file_creation_date": "2026-10-21",
"file_id_modifier": "A",
"batches": 1,
"entries": 3,
"addenda": 2,
"returns": 0,
"notifications_of_change": 0,
"total_debit": "0.00",
"total_credit": "5835.65",
"balanced": false,
"sec_codes": [
"PPD"
],
"lines": 10
},
"issues": []
}
A PPD debit file written by an independent ACH library. Structure and totals pass; two lines without their trailing spaces and the old effective date are reported as warnings. Test file from the open-source Moov ACH project (Apache-2.0), unmodified.
ach-ppd-debit-moov.ach 891 bytes · NACHA PPD
Input file
101 23138010401210428821906240000A094101Federal Reserve Bank My Bank Name
5225Name on Account 121042882 PPDREG.SALARY 190625 1121042880000001
62723138010412345678 0100000000 Receiver Account Name 0121042880000001
82250000010023138010000100000000000000000000121042882 121042880000001
9000001000001000000010023138010000100000000000000000000
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
Validation result
VALID 0 errors · 3 warnings
- My Bank Name
- 2019-06-24
- Batches · entries
- 1 · 1
- Total debit
- 1000000.00 USD
- Total credit
- 0.00 USD
WARNING · RECORD_LENGTH line 1 The line has 75 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files.
WARNING · EFFECTIVE_DATE_PAST line 2, col 70-75 The effective date 2019-06-25 is in the past; the ACH operator will settle on the next possible banking day.
WARNING · RECORD_LENGTH line 5 The line has 55 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files.
JSON response POST /v1/ach/validate
{
"format": "nacha",
"valid": true,
"error_count": 0,
"warning_count": 3,
"summary": {
"immediate_destination": "231380104",
"immediate_destination_name": "Federal Reserve Bank",
"immediate_origin": "0121042882",
"immediate_origin_name": "My Bank Name",
"file_creation_date": "2019-06-24",
"file_id_modifier": "A",
"batches": 1,
"entries": 1,
"addenda": 0,
"returns": 0,
"notifications_of_change": 0,
"total_debit": "1000000.00",
"total_credit": "0.00",
"balanced": false,
"sec_codes": [
"PPD"
],
"lines": 10
},
"issues": [
{
"severity": "warning",
"rule": "RECORD_LENGTH",
"line": 1,
"found": 75,
"message": "The line has 75 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files."
},
{
"severity": "warning",
"rule": "EFFECTIVE_DATE_PAST",
"line": 2,
"field": "effective_entry_date",
"column": "70-75",
"found": "190625",
"message": "The effective date 2019-06-25 is in the past; the ACH operator will settle on the next possible banking day."
},
{
"severity": "warning",
"rule": "RECORD_LENGTH",
"line": 5,
"found": 55,
"message": "The line has 55 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files."
}
]
}
The same kind of file with a wrong routing check digit in the entry: the receiving bank would return it (R28). Test file from the open-source Moov ACH project (Apache-2.0), unmodified.
ach-ppd-wrong-check-digit-moov.ach 891 bytes · NACHA PPD
Input file
101 23138010401210428821906240000A094101Federal Reserve Bank My Bank Name
5225Name on Account 121042882 PPDREG.SALARY 190625 1121042880000001
62723138010512345678 0100000000 Receiver Account Name 0121042880000001
82250000010023138010000100000000000000000000121042882 121042880000001
9000001000001000000010023138010000100000000000000000000
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
Validation result
INVALID 1 error · 3 warnings
- My Bank Name
- 2019-06-24
- Batches · entries
- 1 · 1
- Total debit
- 1000000.00 USD
- Total credit
- 0.00 USD
WARNING · RECORD_LENGTH line 1 The line has 75 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files.
WARNING · EFFECTIVE_DATE_PAST line 2, col 70-75 The effective date 2019-06-25 is in the past; the ACH operator will settle on the next possible banking day.
ERROR · ROUTING_CHECK_DIGIT line 3, col 12 231380105 is not a valid routing number: with these first 8 digits the check digit would be 4.
WARNING · RECORD_LENGTH line 5 The line has 55 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files.
JSON response POST /v1/ach/validate
{
"format": "nacha",
"valid": false,
"error_count": 1,
"warning_count": 3,
"summary": {
"immediate_destination": "231380104",
"immediate_destination_name": "Federal Reserve Bank",
"immediate_origin": "0121042882",
"immediate_origin_name": "My Bank Name",
"file_creation_date": "2019-06-24",
"file_id_modifier": "A",
"batches": 1,
"entries": 1,
"addenda": 0,
"returns": 0,
"notifications_of_change": 0,
"total_debit": "1000000.00",
"total_credit": "0.00",
"balanced": false,
"sec_codes": [
"PPD"
],
"lines": 10
},
"issues": [
{
"severity": "warning",
"rule": "RECORD_LENGTH",
"line": 1,
"found": 75,
"message": "The line has 75 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files."
},
{
"severity": "warning",
"rule": "EFFECTIVE_DATE_PAST",
"line": 2,
"field": "effective_entry_date",
"column": "70-75",
"found": "190625",
"message": "The effective date 2019-06-25 is in the past; the ACH operator will settle on the next possible banking day."
},
{
"severity": "error",
"rule": "ROUTING_CHECK_DIGIT",
"line": 3,
"field": "check_digit",
"column": "12",
"found": "5",
"expected": "4",
"message": "231380105 is not a valid routing number: with these first 8 digits the check digit would be 4."
},
{
"severity": "warning",
"rule": "RECORD_LENGTH",
"line": 5,
"found": 55,
"message": "The line has 55 characters instead of 94; trailing spaces seem to be missing. Many banks reject such files."
}
]
}
A file of returned WEB debits, as a bank sends it back. The API's returns endpoint lists each return with its code explained. Test file from the open-source Moov ACH project (Apache-2.0), unmodified.
ach-return-web-moov.ach 949 bytes · NACHA WEB
Input file
101 091400606 6910001341810170306A094101FIRST BANK & TRUST ASF APPLICATION SUPERVI
5200CoinLion 123456789 WEBTRANSFER 000101 1091000010000001
626091400606123456789 0000012354MjMxNDAwMjAtOGQPaul Jones S 1091000017611242
799R01091400600000001 09100001 091000017611242
82000000020009140060000000012354000000000000 123456789 091000010000001
5200CoinLion 123456789 WEBTRANSFER 000101 1021000020000002
621091400606867530999999 0000004565NmRjZTJmMzItMGNBob Marley S 1021000029461242
799R03091400600000003 02100002 021000029461242
82000000020009140060000000000000000000004565 123456789 021000020000002
9000002000001000000040018280120000000012354000000004565
Validation result
VALID 0 errors · 3 warnings
- ASF APPLICATION SUPERVI
- 2018-10-17
- Batches · entries
- 2 · 2
- Returns · changes
- 2 · 0
- Total debit
- 123.54 USD
- Total credit
- 45.65 USD
WARNING · EFFECTIVE_DATE_PAST line 2, col 70-75 The effective date 2000-01-01 is in the past; the ACH operator will settle on the next possible banking day.
WARNING · PURCHASE_DESCRIPTION line 2, col 54-63 Since 2026-03-20 WEB debits for online purchases of goods must use the description PURCHASE. Ignore this if these debits are not purchases (e.g. subscriptions or bills).
INFO · SERVICE_CLASS_200 line 2, col 2-4 Mixed service class 200 with debits only; some banks expect 225.
WARNING · EFFECTIVE_DATE_PAST line 6, col 70-75 The effective date 2000-01-01 is in the past; the ACH operator will settle on the next possible banking day.
INFO · SERVICE_CLASS_200 line 6, col 2-4 Mixed service class 200 with credits only; some banks expect 220.
JSON response POST /v1/ach/validate
{
"format": "nacha",
"valid": true,
"error_count": 0,
"warning_count": 3,
"summary": {
"immediate_destination": "091400606",
"immediate_destination_name": "FIRST BANK & TRUST",
"immediate_origin": "691000134",
"immediate_origin_name": "ASF APPLICATION SUPERVI",
"file_creation_date": "2018-10-17",
"file_id_modifier": "A",
"batches": 2,
"entries": 2,
"addenda": 2,
"returns": 2,
"notifications_of_change": 0,
"total_debit": "123.54",
"total_credit": "45.65",
"balanced": false,
"sec_codes": [
"WEB"
],
"lines": 10
},
"issues": [
{
"severity": "warning",
"rule": "EFFECTIVE_DATE_PAST",
"line": 2,
"field": "effective_entry_date",
"column": "70-75",
"found": "000101",
"message": "The effective date 2000-01-01 is in the past; the ACH operator will settle on the next possible banking day."
},
{
"severity": "warning",
"rule": "PURCHASE_DESCRIPTION",
"line": 2,
"field": "company_entry_description",
"column": "54-63",
"found": "TRANSFER",
"expected": "PURCHASE",
"message": "Since 2026-03-20 WEB debits for online purchases of goods must use the description PURCHASE. Ignore this if these debits are not purchases (e.g. subscriptions or bills)."
},
{
"severity": "info",
"rule": "SERVICE_CLASS_200",
"line": 2,
"field": "service_class_code",
"column": "2-4",
"found": "200",
"message": "Mixed service class 200 with debits only; some banks expect 225."
},
{
"severity": "warning",
"rule": "EFFECTIVE_DATE_PAST",
"line": 6,
"field": "effective_entry_date",
"column": "70-75",
"found": "000101",
"message": "The effective date 2000-01-01 is in the past; the ACH operator will settle on the next possible banking day."
},
{
"severity": "info",
"rule": "SERVICE_CLASS_200",
"line": 6,
"field": "service_class_code",
"column": "2-4",
"found": "200",
"message": "Mixed service class 200 with credits only; some banks expect 220."
}
]
}
JSON response POST /v1/ach/returns
{
"returns": 2,
"notifications_of_change": 0,
"other_entries": 0,
"returned_amount": "169.19",
"by_code": {
"R01": 1,
"R03": 1
},
"items": [
{
"kind": "return",
"code": "R01",
"title": "Insufficient funds",
"explanation": "The account did not have enough money for the debit.",
"action": "You may try again up to two more times within 180 days of the original effective date.",
"retry_allowed": true,
"original_trace_number": "091400600000001",
"original_rdfi": "09100001",
"date_of_death": null,
"addenda_information": "",
"addenda_line": 4,
"entry": {
"batch": 1,
"line": 3,
"sec_code": "WEB",
"company_name": "CoinLion",
"company_identification": "123456789",
"description": "TRANSFER",
"effective_date": "2000-01-01",
"transaction_code": "26",
"type": "debit",
"account_type": "checking",
"prenote": false,
"routing": "091400606",
"account": "123456789",
"amount": "123.54",
"name": "Paul Jones",
"identification_number": "MjMxNDAwMjAtOGQ",
"trace_number": "091000017611242"
}
},
{
"kind": "return",
"code": "R03",
"title": "No account / unable to locate account",
"explanation": "The account number does not exist at this bank, or does not match the name.",
"action": "Check the account number and routing number with the receiver.",
"retry_allowed": false,
"original_trace_number": "091400600000003",
"original_rdfi": "02100002",
"date_of_death": null,
"addenda_information": "",
"addenda_line": 8,
"entry": {
"batch": 2,
"line": 7,
"sec_code": "WEB",
"company_name": "CoinLion",
"company_identification": "123456789",
"description": "TRANSFER",
"effective_date": "2000-01-01",
"transaction_code": "21",
"type": "credit",
"account_type": "checking",
"prenote": false,
"routing": "091400606",
"account": "867530999999",
"amount": "45.65",
"name": "Bob Marley",
"identification_number": "NmRjZTJmMzItMGN",
"trace_number": "021000029461242"
}
}
],
"note": "Explanations are our own summaries, not the text of the Nacha Operating Rules."
}
How it works
- Export the ACH file from your payroll, accounting or banking software. It is a plain-text file with 94-character lines, often
.achor.txt. - Drop it into the box above, or try one of the sample files. Tick the option if your bank wants balanced batches.
- Read the report: each problem has its rule, its line and column, and an explanation. The API returns the same report as JSON.
What is checked
| Area | Checks |
|---|---|
| File | 94-character records, printable ASCII, record order, padding to blocks of 10; CRLF, LF and unbroken files are read alike |
| File header | constants, immediate destination (routing check digit), immediate origin (routing number or 1 + EIN) |
| Batches | service class 200 / 220 / 225 and that it matches the entries, SEC code, required company fields |
| Dates | effective date valid, not in the past, not a weekend or Federal Reserve holiday (warnings) |
| Entries | transaction codes, prenotes and zero-dollar entries with amount 0, routing check digit (3-7-1), account number, Same Day ACH limit $1,000,000 (warning) |
| Addenda | addenda indicator, count, type, sequence numbers |
| Trace numbers | unique and ascending |
| Totals | batch and file control: entry and addenda count, entry hash (last 10 digits), debit and credit totals, block count, matching header fields |
| SEC rules | TEL debits only (except REVERSAL), WEB payment type code, 2026 descriptions: PAYROLL for PPD wage credits, PURCHASE for WEB purchase debits (warnings) |
| Optional | balanced batches |
Sample files marked “Moov” are unmodified test files from the open-source Moov ACH project (Apache License 2.0). The payroll sample was generated by the API from made-up data. Not affiliated with Nacha.
Questions
Which files can be checked?
Any NACHA file. The full rules are checked for PPD, CCD, WEB, TEL, CTX and COR batches; for other SEC codes (such as IAT) the structure and the totals are checked.
Does a valid report mean my bank will accept the file?
It means the file follows the NACHA file format and the rules listed below. Banks can add their own requirements (balanced files, an offset account, cut-off times), and routing numbers are checked by their check digit only, not against the Federal Reserve directory.
Should I upload a real payment file?
Please don’t. The file is not stored, but a real ACH file holds names and account numbers. Use a test file, a copy with made-up account numbers, or the sample files on this page. The API is the place for real files.
What is the difference between an error and a warning?
Errors break the file format or a rule and usually lead to a rejected file or entry. Warnings point to things that are allowed but worth a look: an effective date in the past or on a weekend, missing trailing spaces, possible duplicate entries, the 2026 descriptions PAYROLL and PURCHASE.
Is this tool from Nacha?
No. It is not affiliated with Nacha. The checks follow the public NACHA file format and Nacha’s public announcements; the explanations are our own.
Is my file stored?
No. It is processed in memory and discarded right after the report is sent back. See the privacy notice.
Need it in your own software?
The same engine is available as an API: whole files instead of a preview, every export format, automation.
Related tools
pain.001 validator
Check a pain.001 or pain.008 file against the ISO 20022 schema and the EPC rules, with every problem explained.
pain.001.001.03 to .09
Migrate 2009 SEPA files to the 2019 versions, checked against the new schema and the SEPA rules.
CSV to NACHA
Turn a payroll or vendor CSV into a NACHA file that passes every check before it goes to the bank.