VouchRow

Guide

The OFX format, explained for accountants

Updated 11 min read

You do not need to write OFX, but being able to open one and see what it says turns a failed import from a mystery into a two-minute check.

What OFX is for

Open Financial Exchange is a specification for exchanging financial data between institutions and software. CheckFree, Intuit and Microsoft published the first version in 1997, and the specification is now looked after by the Financial Data Exchange consortium, whose current banking specification is version 2.3 from 2020. In practice, though, most statement files in circulation are still written in the 1.0.2 dialect from the late nineties, because that is what desktop accounting software expects.

Its advantage over CSV is that it is self-describing. A CSV date is ambiguous and its amount column may or may not be signed; an OFX date is always written year first and its amounts are signed by definition. There is no mapping step because there is nothing to map. Xero, Sage, MYOB, Wave, Zoho Books and QuickBooks Online all read it, and QBO and QFX are OFX with one Intuit tag added.

Where a CSV import has fought you twice over column mapping, an OFX file with unambiguous dates and signed amounts removes the mapping step entirely because the format describes itself.

The two versions, and how to tell them apart

Version 1.x is SGML: a header block of colon-separated lines, then tags, where elements that hold a value are usually not closed. Version 2.x is XML: it begins with an XML declaration and an OFX processing instruction, and every tag is closed. Both are legitimate OFX, and a program that reads one may reject the other. QuickBooks Desktop in particular expects 1.0.2.

OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE

<TRNAMT>-45.20          no closing tag needed
Version 1.0.2 (SGML) header and a value tag
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?OFX OFXHEADER="200" VERSION="220" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>

<TRNAMT>-45.20</TRNAMT>  closing tag required
Version 2.x (XML) header and the same tag

A quick tell

If a file opens in a browser as a tidy expandable tree, it is OFX 2.x. That is a warning sign rather than a good one where the target software expects the older form.

Reading one

After the header, a statement file has three layers: a sign-on response saying who produced it, a statement response for one account, and inside that the transaction list and balances. Bank accounts use BANKMSGSRSV1 and STMTRS; credit cards use CREDITCARDMSGSRSV1 and CCSTMTRS, with a CCACCTFROM block that has an account number but no routing number. The parts worth knowing are few:

TagHoldsNotes
<CURDEF>Default currencyISO code such as USD, GBP, AUD
<BANKID>Routing number or sort codeBank accounts only
<ACCTID>Account numberHow the importer recognises the account next time
<ACCTTYPE>CHECKING, SAVINGS, MONEYMRKT, CREDITLINE, CDCard statements use CCACCTFROM instead
<DTSTART> / <DTEND>Statement periodSome importers reject an end date in the future
<LEDGERBAL>Closing balance and its dateThe figure the transactions should reach
<AVAILBAL>Available balanceNot the same figure; ignore it for checking
Statement-level fields
TagHoldsNotes
<TRNTYPE>Transaction typeDEBIT, CREDIT, CHECK, FEE, INT and others
<DTPOSTED>Date postedYYYYMMDD, optionally with time and zone
<DTUSER>Date initiatedOptional, e.g. the card swipe date
<TRNAMT>AmountSigned: negative is money out
<FITID>Transaction IDUnique within the account; the duplicate key
<CHECKNUM>Cheque numberOnly for cheques
<REFNUM>Reference numberOptional
<NAME>Payee or descriptionShort: 32 characters in the specification
<MEMO>Longer descriptionUp to 255 characters; where full text survives
Transaction fields inside each <STMTTRN>

Most import failures are visible here. A missing ACCTID, a period in the future, an ACCTTYPE that disagrees with the account you are importing into, a card statement written as a checking account: all findable in under a minute with a text editor.

Dates and amounts, precisely

OFX dates are written year, month, day, optionally followed by hours, minutes, seconds, milliseconds and a time zone in square brackets. All of these are valid and mean the same day:

20260315
20260315120000
20260315120000.000[-5:EST]

The time zone is the one place dates can still go wrong. A transaction stamped at midnight UTC can appear a day earlier in software that converts it to a US time zone, so careful writers either omit the time or set it to midday. Amounts use a full stop as the decimal separator and no thousands separator, whatever the country, and the sign carries the direction.

Why it needs no bank ID

OFX carries a BANKID, a routing or sort code, which identifies the bank in the ordinary sense, and an FI block naming the institution. What it does not carry is Intuit’s INTU.BID, which exists to confirm the institution participates in Web Connect. That tag is a commercial check, not a technical one, which is why plain OFX imports into non-Intuit software without one.

In practice this makes OFX the best default for anything that is not QuickBooks or Quicken: same data, no number to hunt for. QuickBooks Online also accepts plain OFX through Upload from file, which is useful when your bank has no Intuit ID.

The transaction types, and what they change

TRNTYPE classifies each transaction, and importers use it to suggest a posting or to filter. The specification lists about seventeen values; the ones you will actually meet are few.

  • DEBIT and CREDIT: the generic pair, and what most converters write when the statement does not say more.
  • CHECK: a cheque, usually with a CHECKNUM alongside it.
  • FEE, SRVCHG and INT: bank charges and interest, which some importers route to their own accounts automatically.
  • DEP, DIRECTDEP and DIRECTDEBIT: deposits and direct debits.
  • XFER: a transfer between accounts, worth distinguishing because posting one as income overstates revenue.
  • ATM, POS, PAYMENT, CASH and OTHER: useful for filtering rather than for posting.

The sign in TRNAMT is authoritative regardless. A DEBIT with a positive amount is a contradiction some software resolves one way and some the other, so the type should never be relied on to carry direction.

The status block, and what a rejection looks like

Near the top of every file sits a sign-on response with a status code inside it. Zero means success. Anything else is the bank or the file telling you why it will not proceed, and it is worth reading before assuming the transactions are the problem.

<STATUS>
  <CODE>0
  <SEVERITY>INFO
</STATUS>

Statement files produced by converters generally set this to zero as a formality. Files downloaded from a bank sometimes carry a real error here, which is the actual cause of an import that appeared to fail for no reason.

Balances, and why they matter for checking

A statement block carries LEDGERBAL, the closing balance, and often AVAILBAL, the available balance. These are the closest thing OFX has to a self-check: opening balance plus the sum of the transactions should reach the ledger balance. OFX has no opening balance field, so the opening figure comes from your books or the statement.

Available balance is not the same figure and should never be used for that arithmetic. It reflects pending items and any overdraft facility, so it will not agree and is not supposed to.

Common mistakes in hand-built OFX

  • Unescaped characters. An ampersand in a payee name, as in M&S, has to be written &amp;, and a raw one breaks the parse, often with an error that points nowhere useful.
  • The wrong character set. A 1.0.2 file declaring CHARSET:1252 but saved as UTF-8 turns accented names into stray symbols.
  • Mixing dialects: closing tags in a file whose header says SGML, or an XML header in front of SGML-style tags. Some readers tolerate it; QuickBooks often does not.
  • Writing a credit card as a bank account. Card statements belong in CCSTMTRS, or the importer offers the wrong accounts.
  • Opening an OFX in Excel to check it. Excel can read the XML version as a table, but the SGML version arrives as a single column of tags. Use a text editor.

FAQ

Related questions

What is an OFX file?

An Open Financial Exchange file: a text file containing a bank or card account, a statement period, transactions with dates, signed amounts and unique IDs, and the closing balance. Most accounting software outside Intuit imports it, and QBO and QFX are variants of it.

How do I open an OFX file?

Any plain text editor will show its contents, since it is text. To use the data, import it into accounting or personal finance software. Excel can open the XML version as a table but not the older SGML version cleanly.

Is OFX the same as XML?

Only version 2.x. OFX 1.x is SGML, with a colon-separated header and value tags that are not closed. Version 2.x is well-formed XML. Many desktop programs, QuickBooks Desktop included, expect 1.0.2.

What is the difference between OFX and QFX?

QFX is OFX with Intuit’s INTU.BID tag added, which Quicken checks against its list of participating banks. The transaction data is the same; plain OFX needs no bank ID and is what Xero, Sage, MYOB and similar packages read.

Which accounting software accepts OFX?

Xero (its recommended format), MYOB, Sage Accounting and Sage 50, Wave, Zoho Books, and QuickBooks Online through Upload from file. QuickBooks Desktop and Quicken want the Intuit variants, QBO and QFX.

What is the latest version of OFX?

The banking specification is at version 2.3, published in 2020 and maintained by the Financial Data Exchange consortium. Statement downloads, though, are still very often written as OFX 1.0.2 for compatibility.

Skip the import errors next time

Convert statements into files your software accepts, with every row checked against the running balance.