[{"data":1,"prerenderedAt":875},["ShallowReactive",2],{"blog-\u002Fblog\u002Fbai2-file-format-explained":3,"blog-related-\u002Fblog\u002Fbai2-file-format-explained":850,"blog-surround-\u002Fblog\u002Fbai2-file-format-explained":874},{"id":4,"title":5,"audience":6,"body":9,"cluster":797,"conversionGoal":798,"cornerstone":799,"date":800,"description":801,"draft":799,"extension":802,"factCheckedAt":800,"faq":803,"featured":799,"language":798,"meta":816,"minRead":817,"navigation":818,"order":819,"originalAsset":798,"path":820,"pillar":821,"primaryKeyword":822,"publicationOrder":823,"relatedProject":798,"releaseScope":824,"reviewCycle":825,"reviewMethod":826,"reviewStatus":827,"reviewedAt":800,"reviewedBy":828,"searchIntent":829,"seo":830,"sources":831,"stem":844,"tags":845,"type":128,"updated":798,"__hash__":849},"blog\u002Fblog\u002Fbai2-file-format-explained.md","BAI2 File Format: Records, Type Codes and How to Read One",[7,8],"treasury-system-lead","solution-architect",{"type":10,"value":11,"toc":784},"minimark",[12,41,53,58,72,75,100,119,122,132,135,139,152,158,194,201,205,212,218,225,228,262,266,285,355,366,369,470,477,481,488,494,505,529,533,554,558,561,585,592,596,603,671,687,691,699,703,756,763,766],[13,14,15,19,20,25,26,30,31,35,36,40],"p",{},[16,17,18],"strong",{},"A BAI2 file is a comma-delimited flat file of numbered records nested three envelopes deep: an 01 file header, one or more 02 group headers, an 03 account record carrying balances as three-digit type codes, 16 records for transaction detail, 88 continuations wherever a record runs long, and 49\u002F98\u002F99 trailers that close each envelope with a control total."," If you're choosing between statement formats, that's the ",[21,22,24],"a",{"href":23},"\u002Fblog\u002Fbank-statement-formats-mt940-camt053-bai2","MT940 vs camt.053 vs BAI2 comparison","; if your file is tagged SWIFT text or XML, you want the ",[21,27,29],{"href":28},"\u002Fblog\u002Fmt940-format-tags-explained","MT940 tag walkthrough"," or the ",[21,32,34],{"href":33},"\u002Fblog\u002Fcamt-053-structure-and-fields","camt.053 field walkthrough",". This post is the third of the trio: for the day a ",[37,38,39],"code",{},".bai"," file from a US bank is in front of you and you need to know what each record and code holds — verified against the BAI specification itself and two banks' published implementation guides (HSBC's and SouthState Bank's), because as always the bank guide, not the standard, is the contract.",[13,42,43,44,48,49,52],{},"One naming point first, because the search results are a mess. \"BAI2\" is not a second file format that replaced a first one called BAI — it is Version 2 of BAI's ",[45,46,47],"em",{},"Cash Management Balance Reporting Specifications",", and the version-number field in every file header literally says ",[37,50,51],{},"2",". The lineage since: BAI handed the copyright to Accredited Standards Committee X9 in 2008, ANSI approved the successor standard BTRS in 2012, and X9 versioned it straight to \"BTR3\" in 2016 precisely so the numbering would read as a continuation of BAI2. BTRS readers were designed to accept BAI2 files (with exceptions where codes were deleted or repurposed); a BAI2 reader cannot accept a BTRS file. In the field, the guides your banks publish still say BAI2, which is why this post does too.",[54,55,57],"h2",{"id":56},"the-shape-of-the-file","The shape of the file",[13,59,60,61,64,65,64,68,71],{},"The specification organizes data into three envelopes — ",[16,62,63],{},"account"," inside ",[16,66,67],{},"group",[16,69,70],{},"file",". A group holds accounts from one originator institution with one as-of-date; a file can hold many groups, which is how a concentration bank forwards other banks' data to you in a single transmission. That's a structural difference from MT940, where every message is one account's statement: a BAI2 importer must be written for the multi-account, multi-group, multi-originator case on day one.",[13,73,74],{},"The syntax is three rules:",[76,77,78,82,89],"ul",{},[79,80,81],"li",{},"Fields are delimited by commas.",[79,83,84,85,88],{},"A slash ",[37,86,87],{},"\u002F"," ends a logical record (with a text-field exception we'll get to — it's the format's nastiest corner).",[79,90,91,92,95,96,99],{},"Defaulted optional fields are shown by adjacent delimiters — ",[37,93,94],{},",,"," mid-record, ",[37,97,98],{},",\u002F"," at the end.",[13,101,102,103,106,107,110,111,114,115,118],{},"Amounts have ",[16,104,105],{},"no decimal point",". The currency code in force (from the 02 or 03 record) determines the implied decimals — two for most currencies, zero for some such as JPY — so ",[37,108,109],{},"5525116638"," in a USD account is $55,251,166.38. And amounts on detail and summary records are ",[16,112,113],{},"always positive or unsigned",": direction lives in the type code, not in a sign. Only status (balance) amounts can carry a ",[37,116,117],{},"-",".",[13,120,121],{},"A minimal real file, from SouthState Bank's guide:",[123,124,129],"pre",{"className":125,"code":127,"language":128},[126],"language-text","01,053200983,053200983,241210,1228,1,,,2\u002F\n02,,063114030,1,241209,,USD,2\u002F\n03,9999999999991,USD,015,69627820,0,,045,69627820,0,,100,0,0,,400,8949876,0,\u002F\n16,506,8949876,,,,TRANSFER TO COMMERCIAL ANALYSIS ACCOUNT 9999999999992\u002F\n49,157155392,3\u002F\n98,245520532,1,5\u002F\n99,245520532,1,7\u002F\n","text",[37,130,127],{"__ignoreMap":131},"",[13,133,134],{},"(Structure per SouthState's published sample, trimmed to its first account with the trailer record counts adjusted to match; the control totals are the bank's printed figures — checksums, not balances, as the trailer section below explains.)",[54,136,138],{"id":137},"_01-and-02-the-headers","01 and 02 — the headers",[13,140,141,144,145,147,148,151],{},[16,142,143],{},"01 File Header"," — sender ID, receiver ID, file creation date (YYMMDD), file creation time in military format, a file identification number that must be unique per creation date, optional physical record length and block size, and the version number: ",[37,146,51],{},". Two field-level traps worth wiring in. Times run 0000–2400, and the spec itself warns that ",[45,149,150],{},"some processors use 9999 to indicate end-of-day — be prepared to recognize it",". And the file ID is your duplicate-file detector: same sender, same date, same file ID means you've been sent the same file twice.",[13,153,154,157],{},[16,155,156],{},"02 Group Header"," — optional ultimate receiver, the originator (US institutions are identified by ABA routing number, foreign ones by SWIFT BIC or another agreed identifier), a group status, the as-of-date, optional as-of-time, optional currency code (default USD — this is a US format to its bones), and an as-of-date modifier. The two enumerations:",[159,160,161,174],"table",{},[162,163,164],"thead",{},[165,166,167,171],"tr",{},[168,169,170],"th",{},"Field",[168,172,173],{},"Values",[175,176,177,186],"tbody",{},[165,178,179,183],{},[180,181,182],"td",{},"Group status",[180,184,185],{},"1 = update, 2 = deletion, 3 = correction, 4 = test only",[165,187,188,191],{},[180,189,190],{},"As-of-date modifier",[180,192,193],{},"1 = interim previous-day, 2 = final previous-day, 3 = interim same-day, 4 = final same-day",[13,195,196,197,200],{},"The modifier is how one format serves both jobs camt splits into camt.053 and camt.052: a previous-day BAI2 file (modifier 2) is your end-of-day statement, an interim same-day file (modifier 3) is your intraday feed. HSBC's implementation increments the file ID for each intraday transmission and resets it daily. And group status 3 — correction — means ",[45,198,199],{},"replace previously sent data","; an importer that appends corrections instead of replacing them double-counts the day.",[54,202,204],{"id":203},"_03-the-account-record-where-the-balances-live","03 — the account record, where the balances live",[13,206,207,208,211],{},"The 03 record identifies the account and then carries the day's balance and summary figures as a repeating series of field groups: ",[16,209,210],{},"type code, amount, item count, funds type"," — again and again until the record (or its 88 continuations) runs out. The account number is alphanumeric, leading zeros significant. This is the record the whole cash position is built from, and here it is in HSBC's worked example:",[123,213,216],{"className":214,"code":215,"language":128},[126],"03,260093320000,USD,010,5525116638,,\u002F\n88,015,6105839257,,,040,5524958738,,,045,6105681357,,\u002F\n88,100,784117150,,,102,,18,\u002F\n88,400,203394531,,,402,,63,\u002F\n",[37,217,215],{"__ignoreMap":131},[13,219,220,221,224],{},"Read the first line with the repeating-group rule: account ",[37,222,223],{},"260093320000",", currency USD, then type code 010 (opening ledger) with amount $55,251,166.38, item count and funds type defaulted. The continuations add 015 (closing ledger), 040\u002F045 (opening\u002Fclosing available), then the summaries — 100 total credits with 102 giving the count of credits (18), 400 total debits with 402 the count (63). Everything you need for a position and a completeness check, in four lines.",[13,226,227],{},"The rules attached to this record are exactly the ones parsers get wrong:",[76,229,230,239,245,251],{},[79,231,232,235,236,118],{},[16,233,234],{},"Status amounts may be signed negative; summary amounts may not."," An overdrawn opening ledger arrives as ",[37,237,238],{},"010,-500000",[79,240,241,244],{},[16,242,243],{},"Item count and funds type are for summary codes only"," and must be defaulted (adjacent commas) after a status code.",[79,246,247,250],{},[16,248,249],{},"Only one amount per status or summary code"," may stand per account per as-of-date. Detail codes have no such limit.",[79,252,253,254,257,258,261],{},"An 03 can also carry ",[16,255,256],{},"no data at all"," — ",[37,259,260],{},"03,5765432,,,,,\u002F"," is legal, an account number serving only to anchor the 16 records that follow.",[54,263,265],{"id":264},"the-type-code-system","The type-code system",[13,267,268,269,272,273,276,277,280,281,284],{},"Every figure in an 03 and every transaction in a 16 is classified by a three-digit ",[16,270,271],{},"type code"," from BAI's uniform list — and all three digits are significant, so a parser that strips leading zeros turns opening ledger (010) into nonsense. Codes come in three kinds: ",[16,274,275],{},"status"," (a balance at a point in time), ",[16,278,279],{},"summary"," (a total of activity, may carry an item count), and ",[16,282,283],{},"detail"," (one transaction). The ranges, from the specification:",[159,286,287,297],{},[162,288,289],{},[165,290,291,294],{},[168,292,293],{},"Range",[168,295,296],{},"Meaning",[175,298,299,307,315,323,331,339,347],{},[165,300,301,304],{},[180,302,303],{},"001–099",[180,305,306],{},"Account status (balances, float)",[165,308,309,312],{},[180,310,311],{},"100",[180,313,314],{},"Total Credits summary",[165,316,317,320],{},[180,318,319],{},"101–399",[180,321,322],{},"Credit summary and detail codes",[165,324,325,328],{},[180,326,327],{},"400",[180,329,330],{},"Total Debits summary",[165,332,333,336],{},[180,334,335],{},"401–699",[180,337,338],{},"Debit summary and detail codes",[165,340,341,344],{},[180,342,343],{},"700–799",[180,345,346],{},"Loan summary and detail codes",[165,348,349,352],{},[180,350,351],{},"900–999",[180,353,354],{},"Customized, bank-defined codes",[13,356,357,358,361,362,365],{},"So ",[16,359,360],{},"credit vs debit is a property of the code range"," — the amount itself is unsigned. Two more special cases: code 890 is a non-monetary detail code whose text field carries free-form messages (",[37,363,364],{},"16,890,,,,,detail reports will be delayed until 11:00 AM."," is the spec's own example), and the 900 range is explicitly a free-for-all — BAI assigned nothing there, banks define their own, and HSBC's guide duly fills it with dozens of US- and UK-specific codes. If your parser meets a 9xx code, the answer is in that bank's guide and nowhere else.",[13,367,368],{},"The status codes you'll actually build a cash position from, per the specification's Appendix A:",[159,370,371,383],{},[162,372,373],{},[165,374,375,378,380],{},[168,376,377],{},"Code",[168,379,296],{},[168,381,382],{},"When you see it",[175,384,385,396,407,418,428,438,448,459],{},[165,386,387,390,393],{},[180,388,389],{},"010",[180,391,392],{},"Opening Ledger",[180,394,395],{},"End-of-day and intraday",[165,397,398,401,404],{},[180,399,400],{},"015",[180,402,403],{},"Closing Ledger",[180,405,406],{},"End-of-day",[165,408,409,412,415],{},[180,410,411],{},"030",[180,413,414],{},"Current Ledger",[180,416,417],{},"Intraday",[165,419,420,423,426],{},[180,421,422],{},"040",[180,424,425],{},"Opening Available",[180,427,395],{},[165,429,430,433,436],{},[180,431,432],{},"045",[180,434,435],{},"Closing Available",[180,437,406],{},[165,439,440,443,446],{},[180,441,442],{},"060",[180,444,445],{},"Current Available",[180,447,417],{},[165,449,450,453,456],{},[180,451,452],{},"063",[180,454,455],{},"Total Float",[180,457,458],{},"Where the bank reports float",[165,460,461,464,467],{},[180,462,463],{},"072",[180,465,466],{},"1-Day Float",[180,468,469],{},"With 074 (2+ days) and 075 (3+ days)",[13,471,472,473,476],{},"The end-of-day\u002Fintraday columns follow HSBC's implementation table: its previous-day files carry 010\u002F015\u002F040\u002F045, its intraday files 010\u002F030\u002F040\u002F060 — no closing balances, because the day isn't closed. Ledger vs available is the same booked-versus-usable distinction as MT940's :62F: against :64:, or camt.053's CLBD against CLAV, except BAI2 goes further and itemizes the float that separates them. And the code lists are genuinely bank-specific in the small print: SouthState labels 010\u002F015 \"Starting Balance\" and \"Ending Balance\" — same codes, its own names — and reports a fixed subset of about thirty detail codes, while HSBC publishes hundreds, with per-country reinterpretations (115 is a lockbox deposit in the US and an India lockbox deposit in its India implementation). Print the code, then look it up in ",[45,474,475],{},"that bank's"," guide.",[54,478,480],{"id":479},"_16-the-transaction-detail-record","16 — the transaction detail record",[13,482,483,484,487],{},"One booked transaction per record, six fields: ",[16,485,486],{},"type code, amount, funds type, bank reference number, customer reference number, text."," From SouthState's guide:",[123,489,492],{"className":490,"code":491,"language":128},[126],"16,475,119480,,910211979,35705,Check Paid\u002F\n",[37,493,491],{"__ignoreMap":131},[13,495,496,497,500,501,504],{},"Type code 475 is Check Paid — a 4xx code, so a debit — for $1,194.80; funds type defaulted; the bank's reference is 910211979; and the customer reference is 35705, which for code 475 is the check number. That last mapping is in the specification itself: for detail codes 474, 475 and 395, the customer reference number carries the check number. For payments you originated, the customer reference is where your own reference comes back — BAI2's version of the reconciliation round trip that MT940 runs through :61: subfield 7 and camt.053 through ",[37,498,499],{},"EndToEndId",". HSBC populates ",[37,502,503],{},"NONREF"," when it has nothing, same convention as SWIFT.",[13,506,507,508,510,511,514,515,517,518,521,522,524,525,528],{},"The ",[16,509,128],{}," field is the format's free-text tail — the counterparty names and descriptions that don't fit anywhere structured — and it comes with the file format's sharpest edge: text ",[16,512,513],{},"must not begin with a slash but may contain slashes and commas after the first character",", and per the specification the end of a text field is marked not by a ",[37,516,87],{}," but by ",[45,519,520],{},"the beginning of the next record",". HSBC's guide states it flatly: the ",[37,523,87],{}," is not used when the record ends in text. SouthState's examples, as printed above, ",[45,526,527],{},"do"," end text with a slash. Both banks publish BAI2; a parser that hard-codes either convention breaks on the other. Split the file on line boundaries and record codes, treat everything after the fifth comma as text, and treat a trailing slash as content you may need to trim per bank.",[54,530,532],{"id":531},"_88-continuation-the-record-that-isnt-one","88 — continuation, the record that isn't one",[13,534,535,536,538,539,541,542,545,546,549,550,553],{},"An 88 record continues the previous record — any type, including another 88 — in exactly the same format, picking up at the field where the previous physical line stopped. Three rules from the specification: a non-text field may never be split across records; a record about to be continued ends in ",[37,537,87],{}," (not ",[37,540,98],{},"); and a text field ",[45,543,544],{},"can"," split anywhere — HSBC's example wraps a counterparty name mid-word, ",[37,547,548],{},"…POWER CONVERSION PRAVITE LIMITE"," continued by ",[37,551,552],{},"88,D",". So an 88 is not a data record at all: your parser's first pass should splice 88s onto their parents to rebuild logical records, and only then parse fields. Most real-world balance records arrive as an 03 plus two or three 88s — the HSBC example above is the normal case, not the exception.",[54,555,557],{"id":556},"_49-98-99-trailers-and-the-arithmetic-they-hand-you","49, 98, 99 — trailers and the arithmetic they hand you",[13,559,560],{},"Each envelope closes with a trailer, and each trailer carries a control total and a record count:",[76,562,563,573,579],{},[79,564,565,568,569,572],{},[16,566,567],{},"49 Account Trailer"," — the algebraic sum of ",[45,570,571],{},"every amount field"," in the preceding 03 and its 16\u002F88 records, plus a count of records including the 03 and the 49 itself.",[79,574,575,578],{},[16,576,577],{},"98 Group Trailer"," — sum of the account control totals; number of accounts (03 records); number of records in the group.",[79,580,581,584],{},[16,582,583],{},"99 File Trailer"," — sum of the group control totals; number of groups; number of records in the file.",[13,586,587,588,591],{},"Note what the account control total is: balances ",[45,589,590],{},"and"," transactions summed together — opening ledger plus closing ledger plus total credits plus each detail amount, one number. It is meaningless as money, and that's fine; it's a checksum, not a balance. Two things are excluded: amounts inside funds-type availability fields, and item counts. Recompute all three levels on import and reject the file on mismatch — this is BAI2's equivalent of the MT940 balance-chain check, and it catches truncation before the truncation becomes a wrong cash position. The balance continuity check (previous 015 equals today's 010) isn't a stated rule of the format the way :60a:\u002F:62a: chaining is in MT940, but it's the same free detector, and I'd wire it in regardless.",[54,593,595],{"id":594},"the-funds-type-field","The funds-type field",[13,597,598,599,602],{},"The odd one out among the fields, because it's ",[16,600,601],{},"composite"," — one field that can expand into several, changing the record's field count. It reports availability of the amount it follows:",[159,604,605,616],{},[162,606,607],{},[165,608,609,611,613],{},[168,610,377],{},[168,612,296],{},[168,614,615],{},"What follows",[175,617,618,629,639,650,661],{},[165,619,620,623,626],{},[180,621,622],{},"Z",[180,624,625],{},"Unknown (default)",[180,627,628],{},"Nothing",[165,630,631,634,637],{},[180,632,633],{},"0, 1, 2",[180,635,636],{},"Whole amount available in 0 \u002F 1 \u002F 2+ days",[180,638,628],{},[165,640,641,644,647],{},[180,642,643],{},"V",[180,645,646],{},"Value dated",[180,648,649],{},"Value date (YYMMDD), then optional value time",[165,651,652,655,658],{},[180,653,654],{},"S",[180,656,657],{},"Distributed availability",[180,659,660],{},"Three amounts: immediate, one-day, two-or-more-days",[165,662,663,666,668],{},[180,664,665],{},"D",[180,667,657],{},[180,669,670],{},"A count, then that many day\u002Famount pairs",[13,672,357,673,676,677,679,680,683,684,686],{},[37,674,675],{},"16,115,10000000,S,5000000,4000000,1000000\u002F"," is a $100,000 lockbox deposit of which $50,000 is available now, $40,000 tomorrow and $10,000 in two or more days — and the record is suddenly three fields longer than the plain-vanilla case. ",[37,678,643],{}," with a date is how value-dated entries arrive (",[37,681,682],{},"…,V,040701,1300,…"," in the spec's example). A fixed-position parser dies here; the funds-type code must drive how many fields you consume next. Availability amounts can be signed (float adjustments), are excluded from control totals, and — the spec is explicit — may not sum to the amount they describe. Whether the field is used at all is bank policy: SouthState doesn't populate it; HSBC uses ",[37,685,643],{}," when value, posting and reporting dates differ.",[54,688,690],{"id":689},"reading-one-end-to-end","Reading one end to end",[13,692,693,694,698],{},"The reading algorithm that falls out of all this: split on record codes; splice 88s onto parents; walk 01 → 02 → 03 → 16s → 49, maintaining the envelope stack; apply implied decimals from the currency in scope; take direction from the type-code range, never from a sign; expand funds-type fields by their own code; verify all three trailer totals. When an ",[21,695,697],{"href":696},"\u002Fblog\u002Felectronic-bank-statement-processing-in-sap","electronic bank statement run in SAP"," imports a BAI2 file, the type code is the external transaction code its posting rules key on — the same job MT940's :61: transaction type and camt.053's Bank Transaction Code do — so the per-bank code list isn't trivia, it's the input to your posting-rule design.",[54,700,702],{"id":701},"what-usually-goes-wrong","What usually goes wrong",[76,704,705,711,717,723,738,744,750],{},[79,706,707,710],{},[16,708,709],{},"Parsing amounts as signed decimals."," No decimal points (implied by currency), no signs on detail amounts. Direction is the type-code range: 100–399 credit, 400–699 debit.",[79,712,713,716],{},[16,714,715],{},"Treating 88 as a record type."," It's a continuation. Splice first, parse second — and expect text to split mid-word.",[79,718,719,722],{},[16,720,721],{},"Hard-coding the text terminator."," The spec ends text at the next record boundary; HSBC omits the trailing slash, SouthState prints one. Per-bank tolerance, not one rule.",[79,724,725,728,729,731,732,734,735,737],{},[16,726,727],{},"Fixed field positions through funds type."," ",[37,730,654],{},", ",[37,733,665],{}," and ",[37,736,643],{}," change the field count. The composite must drive the cursor.",[79,739,740,743],{},[16,741,742],{},"Skipping the trailer arithmetic."," Three levels of control totals are sitting there; recompute them or ship truncated files into your cash position.",[79,745,746,749],{},[16,747,748],{},"Stripping leading zeros from type codes."," 010 is a code, 10 is not. Same for account numbers — leading zeros are significant.",[79,751,752,755],{},[16,753,754],{},"Assuming one bank's code list."," The 900 range is bank-defined by design, and even uniform codes get bank-specific names and per-country meanings. One code map per bank, from that bank's guide.",[13,757,758,759,762],{},"The format is older than almost everything that parses it, and its US home means most treasuries meet it only on the American accounts in an otherwise MT940\u002Fcamt landscape — the ",[21,760,761],{"href":23},"comparison post"," covers when you'd choose it. But the engineering habit is the same one the whole statement trio teaches: the standard gives you the skeleton and the integrity checks for free, and every hard part — code lists, text conventions, which optional fields arrive — is written down in a per-bank guide that you should read before the first production file, not after.",[764,765],"hr",{},[13,767,768],{},[45,769,770,771,731,774,731,777,780,781,118],{},"See also ",[21,772,773],{"href":23},"bank statement formats: MT940 vs camt.053 vs BAI2",[21,775,776],{"href":28},"the MT940 tag walkthrough",[21,778,779],{"href":33},"the camt.053 field walkthrough",", and ",[21,782,783],{"href":696},"electronic bank statement processing in SAP",{"title":131,"searchDepth":785,"depth":785,"links":786},2,[787,788,789,790,791,792,793,794,795,796],{"id":56,"depth":785,"text":57},{"id":137,"depth":785,"text":138},{"id":203,"depth":785,"text":204},{"id":264,"depth":785,"text":265},{"id":479,"depth":785,"text":480},{"id":531,"depth":785,"text":532},{"id":556,"depth":785,"text":557},{"id":594,"depth":785,"text":595},{"id":689,"depth":785,"text":690},{"id":701,"depth":785,"text":702},"connectivity",null,false,"2026-08-03","Every BAI2 record explained: the 01–99 hierarchy, balance codes 010\u002F015\u002F040\u002F045, credit vs debit type-code ranges, the funds-type field and control totals.","md",[804,807,810,813],{"question":805,"answer":806},"What are the record types in a BAI2 file?","Eight, arranged as nested envelopes. An 01 file header opens the file and a 99 file trailer closes it with a control total. Inside, one or more groups each open with an 02 group header (one originator, one as-of-date) and close with a 98 group trailer. Inside a group, each account opens with an 03 account identifier record carrying the balance and summary data, is followed by zero or more 16 transaction detail records, and closes with a 49 account trailer. An 88 continuation record can follow any record type — including another 88 — and carries the overflow in the same format. Every trailer's control total and record count is checkable arithmetic, which is the format's built-in integrity test.",{"question":808,"answer":809},"What do BAI2 type codes 010, 015, 040 and 045 mean?","They are account status codes from BAI's uniform type-code list, reported on the 03 record (or its 88 continuations): 010 is the opening ledger balance, 015 the closing ledger, 040 the opening available and 045 the closing available. Ledger is what the books say; available is what the funds-availability rules let you use. Intraday files use different codes for the same idea — 030 current ledger and 060 current available; in HSBC's implementation, for example, an end-of-day file carries 010\u002F015\u002F040\u002F045 while an intraday file carries 010\u002F030\u002F040\u002F060 and omits the closing balances, because the day isn't closed yet. Status amounts may be signed negative, and each status code may appear only once per account per as-of-date.",{"question":811,"answer":812},"How does a BAI2 file distinguish debits from credits?","By the type code on each record, not by a sign — detail and summary amounts are always positive or unsigned. Codes 100–399 are the credit family (100 itself is the Total Credits summary) and 400–699 are the debit family (400 is Total Debits), with 700–799 reserved for loan reporting and 900–999 for codes each bank defines itself. So a 16 record with code 475 (Check Paid) is a debit and one with 142 (ACH Credit Received) is a credit, and the amount field looks identical on both. A parser that expects signed amounts, or that ignores the code and guesses direction some other way, will book half the statement backwards.",{"question":814,"answer":815},"What is the difference between BAI and BAI2?","Versions of the same specification. The Bank Administration Institute's Cash Management Balance Reporting Specifications went through a Version 1 (retroactively 'BAI1') and a Version 2 — and BAI2 is simply that second version, the one the industry standardized on; the version-number field every file header carries is 2. In 2008 BAI transferred the copyright to Accredited Standards Committee X9, and in 2012 ANSI approved the Balance and Transaction Reporting Standard (BTRS) as its successor — versioned straight to BTR3 in 2016 so the numbering would continue from BAI2. BTRS was built so a BAI2 file could be read by a BTRS reader (with exceptions for deleted or repurposed codes), but not the reverse, and in practice banks' guides still say BAI2.",{},14,true,3.4,"\u002Fblog\u002Fbai2-file-format-explained","treasury-systems-architecture","bai2 file format",195,"Record layouts, field rules, type-code ranges and the printed codes verified against BAI's Cash Management Balance Reporting Specifications v2 (2005 Technical Reference Manual) and the published BAI2 implementation guides of HSBC and SouthState Bank; the BAI1\u002FBAI2\u002FBTRS history against ASC X9's BTR3 format guide. Bank code lists diverge — your bank's guide is the contract.","on ISO 20022 \u002F bank format changes","editorial-and-factual","reviewed","Tan Gravam","informational",{"title":5,"description":801},[832,835,838,841],{"title":833,"url":834,"accessed":800},"BAI — Cash Management Balance Reporting Specifications, Version 2 (Technical Reference Manual, 10\u002F2005)","https:\u002F\u002Fwww.bai.org\u002Fdocs\u002Fdefault-source\u002Flibraries\u002Fsite-general-downloads\u002Fcash_management_2005.pdf",{"title":836,"url":837,"accessed":800},"HSBC — BAI2 Statement Message Implementation Guide, Version 1.5","https:\u002F\u002Fwww.hsbcnet.com\u002F-\u002Fmedia\u002Fhsbcnet\u002Fclient-transition\u002Fbai2-ir-specs.pdf",{"title":839,"url":840,"accessed":800},"SouthState Bank — BAI-2 Format: Cash Management Balance Reporting Specifications User Guide (January 2025)","https:\u002F\u002Fprd.ssbcdn.com\u002Fssbweb\u002Fmedia\u002Fpdf\u002Fssb-bai2-format-v3-jan-2025-rev.pdf",{"title":842,"url":843,"accessed":800},"ASC X9 — ANSI X9.121-201 (BTR3) Balance and Transaction Reporting Standard, Format Guide Version 3 (2016)","https:\u002F\u002Fx9.org\u002Fwp-content\u002Fuploads\u002F2013\u002F10\u002FANSI-X9-121201-BTRS-Format-Guide-Version-3.pdf","blog\u002Fbai2-file-format-explained",[846,847,848],"treasury","bank-connectivity","integration","9_dSQP3iU47FD_DLbclyn1kltCcYecuqXi8yy1isA-0",{"related":851,"prev":864,"next":866,"hasOrder":818,"place":869},[852,856,860],{"path":853,"title":854,"description":855},"\u002Fblog\u002Fiso-20022-payments-pain-001-pain-002","ISO 20022 Payments Explained: pain.001 and pain.002","ISO 20022 is the global XML standard for financial messaging. For payments, pain.001 is the instruction you send and pain.002 the status back. What they are.",{"path":857,"title":858,"description":859},"\u002Fblog\u002Fpain-001-structure-and-fields","pain.001 Structure: The Fields That Actually Matter","Inside the pain.001 file: GroupHeader, PaymentInformation and the transaction level — which fields treasury maps, and where bank implementations differ.",{"path":861,"title":862,"description":863},"\u002Fblog\u002Fpain-002-status-and-reject-codes","pain.002 Status and Reject Codes: Reading the Bank's Reply","How to read a pain.002 status report: group, payment and transaction level, the ACTC\u002FACCP\u002FACSC status codes, and reject reasons like AC01, AC04 and AM04.",{"path":28,"title":865,"type":128,"language":798},"MT940 Format: The Tags, Line by Line",{"path":867,"title":868,"type":128,"language":798},"\u002Fblog\u002Fmt101-vs-mt103-vs-mt202","MT101 vs MT103 vs MT202: Which SWIFT Message Does What",{"label":870,"position":871,"total":872,"hub":873},"Connectivity",7,15,"\u002Ftopics\u002Ftreasury-systems-architecture",[],1785752409698]