← All articles

The Tally XML voucher format, explained

6 min read

Tally does not import a statement. It imports vouchers, in an envelope of its own design, with a sign convention that is the opposite of every other format here.

The envelope

Every Tally import is wrapped in the same structure, whatever it contains. The outer layers say what kind of request this is; the vouchers sit inside.

<ENVELOPE>
  <HEADER><TALLYREQUEST>Import Data</TALLYREQUEST></HEADER>
  <BODY><IMPORTDATA>
    <REQUESTDESC><REPORTNAME>Vouchers</REPORTNAME></REQUESTDESC>
    <REQUESTDATA>
      <TALLYMESSAGE>  ... one voucher ...  </TALLYMESSAGE>
    </REQUESTDATA>
  </IMPORTDATA></BODY>
</ENVELOPE>

Since Tally rejects any voucher whose entries do not sum to zero, a converter producing both ledger entries written and balanced is the difference between an import and an import log full of rejections.

A voucher, and the inverted sign

Each transaction becomes a voucher — Receipt for money in, Payment for money out — carrying two ledger entries that must sum to zero.

Here is the part that catches everyone: Tally writes a debit as a negative amount and a credit as a positive one. That is the opposite of how a bank statement, and almost every other format, represents the same movement. A converter passing its own signs straight through produces vouchers whose two entries share a sign, and every one is rejected.

The ISDEEMEDPOSITIVE flag on each entry marks the debit side and has to agree with the sign of its amount. Disagreement is rejected just as readily as an imbalance.

Ledgers are matched by name

Tally resolves LEDGERNAME against the ledgers in the open company. Depending on the import settings, a name it does not recognise is either rejected or created.

The silent failure

Where Tally is set to create missing ledgers, a bank ledger spelled even slightly differently from yours — "HDFC Current" against "HDFC Current A/c" — produces a brand new ledger and posts everything to it. Nothing fails, nothing is rejected, and the balance you expected to change does not. Copy the name from Gateway of Tally → Chart of Accounts exactly.

The details that reject a file

  • Dates are eight digits, YYYYMMDD, with no separators. Rigid, but unambiguous — there is nothing here to misread.
  • A voucher dated outside the company’s open financial year is rejected.
  • Unescaped ampersands or angle brackets from a description make the whole document unparseable, and Tally reports it as a generic failure rather than pointing at the character.
  • ACTION="Create" does not deduplicate. There is no equivalent of a FITID, so importing the same file twice produces two complete sets with no warning.

Opening the file in a browser is the fastest structural check available: valid XML renders as a tree, and invalid XML gives you a parse error with a line number.

Create, Alter and Cancel

The ACTION attribute on a voucher says what to do with it. Create makes a new one. Alter modifies an existing voucher, matched by a master identifier that Tally assigned when it was created. Cancel voids one while leaving it in the numbering, which matters to an audit trail.

Alter is only usable if you kept the identifiers from a previous import, which a converter has no way to know. So imported statements are always Create — and Create does not deduplicate. Importing the same file twice produces two complete sets of vouchers, silently, because there is no equivalent of a FITID to match on.

Check the register, not the log

The import log reports what was created, not whether it duplicated something already there. Before re-importing anything, look at the voucher register for the period.

Narration and reference are not the same field

NARRATION is the free description shown against the voucher — the natural home for the statement’s transaction description. REFERENCE is a short identifier, typically an instrument or cheque number, and it is what Tally matches on in bank reconciliation.

Putting the whole description into REFERENCE, which converters do when they treat the two as interchangeable, makes the reconciliation screen unusable — a column of eighty-character strings where short references were expected. Keep the description in NARRATION and put a reference in REFERENCE only when the statement actually printed one.

Related