VouchRow

Guide

The Tally XML voucher format, explained

Updated 10 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. Once you can read the envelope, almost every rejected import explains itself.

Two ways into Tally, and which one XML uses

TallyPrime has two separate routes for bank data, and most confusion comes from mixing them up. The Bank Statement import, reached from Alt+O or from Bank Reconciliation, takes the CSV, Excel or MT940 file your bank lets you download, for banks on Tally’s supported list, and Tally’s help says it refuses PDFs and files converted from PDFs. The Transactions import, Alt+O → Transactions, takes vouchers written as XML from any source.

This post is about the second. In Tally.ERP 9 the same import sits under Gateway of Tally → Import of Data → Vouchers, and the XML is the same.

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.

The envelope

Every Tally import is wrapped in the same structure, whatever it contains. The outer layers say what kind of request this is and, optionally, which company it is for; the vouchers sit inside, one per TALLYMESSAGE.

<ENVELOPE>
  <HEADER><TALLYREQUEST>Import Data</TALLYREQUEST></HEADER>
  <BODY><IMPORTDATA>
    <REQUESTDESC>
      <REPORTNAME>Vouchers</REPORTNAME>
      <STATICVARIABLES><SVCURRENTCOMPANY>Acme Traders</SVCURRENTCOMPANY></STATICVARIABLES>
    </REQUESTDESC>
    <REQUESTDATA>
      <TALLYMESSAGE xmlns:UDF="TallyUDF">
        <VOUCHER VCHTYPE="Payment" ACTION="Create">
          <DATE>20260315</DATE>
          <VOUCHERTYPENAME>Payment</VOUCHERTYPENAME>
          <NARRATION>SHELL OIL CARD 1234</NARRATION>
          <ALLLEDGERENTRIES.LIST>
            <LEDGERNAME>Suspense A/c</LEDGERNAME>
            <ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>   debit side
            <AMOUNT>-4520.00</AMOUNT>                  debit is negative
          </ALLLEDGERENTRIES.LIST>
          <ALLLEDGERENTRIES.LIST>
            <LEDGERNAME>HDFC Bank A/c</LEDGERNAME>
            <ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>    credit side
            <AMOUNT>4520.00</AMOUNT>                   credit is positive
          </ALLLEDGERENTRIES.LIST>
        </VOUCHER>
      </TALLYMESSAGE>
    </REQUESTDATA>
  </IMPORTDATA></BODY>
</ENVELOPE>
The import envelope, with one Payment voucher

Tally’s developer documentation also shows a newer header form, with TALLYREQUEST set to Import, TYPE to Data and ID to Vouchers. Both carry the same vouchers. SVCURRENTCOMPANY is optional; leave it out and the vouchers go into whichever company is open, which is usually what you want and occasionally exactly what you did not.

The tags that matter

TagWhat it holdsNotes
VOUCHER VCHTYPEVoucher typeReceipt for money in, Payment for money out; Contra for transfers between bank and cash
ACTIONCreate, Alter or CancelImported statements are always Create
DATEVoucher dateYYYYMMDD, no separators
VOUCHERTYPENAMEVoucher type nameMust match an existing voucher type
NARRATIONFree descriptionWhere the statement description belongs
ALLLEDGERENTRIES.LISTOne ledger entryAt least two per voucher
LEDGERNAMELedger to post toMust exist in the company, spelled exactly
ISDEEMEDPOSITIVEYes for the debit side, No for the credit sideMust agree with the sign of AMOUNT
AMOUNTSigned amountDebit negative, credit positive; entries sum to zero
Voucher-level and entry-level tags for a bank voucher

A voucher, and the inverted sign

Each transaction becomes a voucher, Receipt for money in and Payment for money out, carrying two ledger entries that must sum to zero. For a payment, the expense or party ledger is debited and the bank ledger credited; for a receipt it is the other way round.

Here is the part that catches everyone: Tally writes a debit as a negative amount and a credit as a positive one. Tally’s own sample XML shows exactly this, with the debited ledger at minus the amount and ISDEEMEDPOSITIVE set to Yes. 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 entries are the wrong way round, and every one is rejected or posted backwards.

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, and must already exist

Tally resolves LEDGERNAME against the ledgers in the company exactly as written, including spaces, punctuation and suffixes such as A/c. Tally’s documentation asks for every master a voucher depends on, ledgers included, to exist before the vouchers are imported. A voucher naming a ledger Tally cannot find is counted as an error and not imported.

The near-miss name

“HDFC Current” against “HDFC Current A/c” is enough to fail every voucher in a file. Copy the bank ledger’s name from Chart of Accounts rather than typing it, and make sure any holding ledger the file uses, such as Suspense A/c, exists under the right group before importing.

The other side of each voucher is the harder decision. A converter cannot know your expense heads, and guessing one per transaction would post rows silently to plausible wrong ledgers. Posting everything to Suspense A/c leaves one visible balance to clear by altering each voucher to its proper ledger.

The details that reject a file

SymptomUsual cause
Whole file fails with a generic errorUnescaped & or < in a narration, or invalid XML
Vouchers counted as errorsLedger name not found exactly as written
Voucher totals do not matchEntries do not sum to zero, or rounding left a paisa over
Vouchers rejected for their dateDate outside the company’s books, or not in YYYYMMDD
Import stops at the first problemError handling not set in Alt+O → Configuration
Common import failures
  • Dates are eight digits, YYYYMMDD, with no separators. Rigid, but unambiguous: there is nothing here to misread.
  • A voucher dated before the company’s books begin is rejected, so check the Books beginning from date when importing old statements.
  • Ampersands are common in payee names. They must be written &amp; in XML, and one raw ampersand makes the whole document unparseable.
  • TallyPrime can write a detailed import log, Tally.imp, which names each failed voucher and why. Turn it on under Alt+O → Configuration before a large import.

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, identified by an identifier Tally holds for it, such as its GUID. 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. Tally only replaces an incoming voucher when it carries the GUID of an existing one and the “Overwrite voucher when a voucher with same GUID exists” option is on; a voucher built from a statement has no such GUID, so importing the same file twice produces two complete sets of vouchers, silently.

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 Day Book or the bank ledger for the period.

Narration and reference are not the same field

NARRATION is the free description shown against the voucher, and the natural home for the statement’s transaction description. Reference-type fields are short identifiers, typically a cheque or instrument number, meant for searching and for matching during bank reconciliation.

Putting the whole description into a reference field, which converters do when they treat the two as interchangeable, fills the reconciliation screens with eighty-character strings where short references were expected. Keep the description in NARRATION and put a reference in only when the statement actually printed one.

FAQ

Related questions

What is the Tally XML voucher format?

An XML file in Tally’s ENVELOPE structure: a header saying it is an import, then one TALLYMESSAGE per voucher, each with a VOUCHER element holding the date, voucher type, narration and two or more ledger entries that sum to zero.

How do I import an XML file into TallyPrime?

Open the company, press Alt+O, choose Transactions, give the path to the XML file and confirm. In Tally.ERP 9 use Gateway of Tally → Import of Data → Vouchers.

Why is the debit amount negative in Tally XML?

That is Tally’s convention: a debit entry has ISDEEMEDPOSITIVE set to Yes and a negative AMOUNT, a credit has No and a positive AMOUNT. It is the reverse of bank statements, so signs copied straight from a statement are wrong.

Do ledgers have to exist before importing vouchers into Tally?

Yes. Tally’s help asks for every ledger a voucher names to exist first, spelled exactly as in the XML. Create the bank ledger and any holding ledger, such as Suspense A/c, before importing.

Can Tally import a PDF bank statement?

Not directly. The Bank Statement import takes CSV, Excel or MT940 downloaded from supported banks, and refuses PDFs and files converted from them. A PDF statement goes in as XML vouchers through Alt+O → Transactions.

Does Tally stop duplicate vouchers when I import the same XML twice?

No. Vouchers created from a statement have no identifier Tally can match, so a second import creates a second set. Check the bank ledger for the period before importing.

Skip the import errors next time

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