Reading Tally data for FBR: the traps that don’t throw errors
A practical guide for whoever builds the connection between Tally and FBR digital invoicing. Almost every failure here shows up as a plausible-looking invoice or a quiet day with no invoices. Very few of them raise an error.
Answer first. Tally doesn’t fail loudly. Ask its gateway for the wrong company and it answers with an empty list and HTTP 200. Read a voucher’s lines the obvious way and every single-line invoice disappears. Take amounts at face value and every sale comes out negative. None of these raise an error, so the first sign is usually a day with no invoices, or an FBR submission that doesn’t match Tally’s own sales register. What fixes them is knowing the list below, then checking each item against a week of real vouchers before anything is filed with FBR.
How Tally hands over data
TallyPrime and Tally.ERP 9 are desktop programs with no way to push a change to another system. What they offer instead is a gateway: switch on Tally’s setting to act as a server (where it sits in the menus differs between releases) and, commonly on port 9000, it will answer XML requests posted to it over your local network, provided Tally is running with the company loaded. There is no REST interface and no published schema; you send an envelope describing what you want, and Tally sends back XML.
The most stable way to ask is an inline collection, where the request names exactly the fields it wants rather than relying on a built-in report whose layout varies between installations. An illustrative request for a month of vouchers looks like this — check every field name against your own Tally before relying on it:
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>Export</TALLYREQUEST>
<TYPE>Collection</TYPE>
<ID>FbrSalesVouchers</ID>
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
<SVCURRENTCOMPANY>EXACT COMPANY NAME</SVCURRENTCOMPANY>
<SVFROMDATE>20260901</SVFROMDATE>
<SVTODATE>20260930</SVTODATE>
</STATICVARIABLES>
<TDL><TDLMESSAGE>
<COLLECTION NAME="FbrSalesVouchers">
<TYPE>Voucher</TYPE>
<FETCH>Date, VoucherNumber, VoucherTypeName, PartyLedgerName,
Reference, IsCancelled, IsOptional, AllInventoryEntries</FETCH>
</COLLECTION>
</TDLMESSAGE></TDL>
</DESC>
</BODY>
</ENVELOPE>
Three properties of this arrangement shape everything else. Tally only serves companies that are currently open in it. It handles one request at a time. And the gateway has no authentication at all — anything that can reach the port can read the whole company file, which is why it belongs on the local network and nowhere else.
Traps in the response itself
- A wrong company name returns nothing, successfully. Tally matches the company name literally. A near miss (a missing full stop, “Pvt” for “(Private)”) comes back as an empty collection with HTTP 200, which is indistinguishable from a day with no sales. Other failures, such as a company that isn’t loaded, arrive as a
LINEERRORelement inside a 200 response. Never treat the status code as success; check that the company you asked for is the company that answered, and alert on a day with zero vouchers. - Single-line invoices can vanish. XML has no way to say “a list of one”. An invoice with one stock line arrives with one inventory element where a three-line invoice has three, and a parser that turns repeated elements into arrays but leaves single ones as objects will skip every one-line invoice. Force every list element to an array, always. The bug is easy to miss, because test invoices usually have several lines.
- Fields you ask for can silently not arrive. Misspell a name in the fetch list and Tally leaves the field out rather than complaining. A mandatory field that is simply absent is the signal; test for presence, not just value.
- The encoding is not what it says. Responses typically come without a declared character set and contain Windows-1252 characters such as curly quotes, so decoding them as UTF-8 garbles every non-ASCII name. Control characters, including raw
0x04bytes andreferences, turn up in narrations and addresses and will stop a strict XML parser dead. Strip them before parsing, and before escaping ampersands, or you will corrupt the data you meant to clean. - Tally can simply stop answering. An open dialog on the Tally PC can stall the gateway, a very wide date range can time out, and two requests at once can come back empty. Ask for small windows, one request at a time, with a timeout and a retry.
Traps in the numbers
- Sales are negative. Tally follows double-entry signs: a sale credits sales and tax, so amounts on inventory and tax entries arrive negative. Flip the sign deliberately, in one place, and test with a credit note so you know the flip is right in both directions.
- Quantities carry their unit. A quantity arrives as text such as
100 Kgs. Parsing it as a number either fails or silently drops the unit, and the unit is exactly what you need to translate into FBR’s wording. - Billed and actual quantity differ. Tally records both. When a delivery differs from what was billed, the invoice is the billed quantity — take the other and the value and tax no longer agree.
- Discount is already applied. Tally’s discount is a percentage, and the line amount is already net of it. Subtracting it again undercharges tax on every discounted line.
- Tax is posted once, but FBR wants it per line. Tally books sales tax as a single entry on the voucher against a ledger under Duties & Taxes. FBR needs the tax on each line. Apportion it using whole paisa and give the rounding difference to one line, so the lines add up exactly to the voucher total. Floating-point arithmetic will get this wrong often enough to fail a reconciliation.
What counts as an invoice
- Voucher types are user-defined. “Sales” is only Tally’s default. Companies create “Sales – Lahore”, “Export Sales”, “Cash Sales”. Filtering on the name “Sales” misses them all. Keep an explicit list of which voucher types are FBR sales invoices and which are notes.
- Cancelled and optional vouchers look like invoices. Both carry a flag,
ISCANCELLEDandISOPTIONAL, and both must be excluded, or you file invoices that were never issued. Filing them is not a harmless mistake: FBR’s API has no cancel method, so undoing it means the portal, within 72 hours. - Voucher numbers are unique per type, not per company. “1001” can exist as a cash sale and as a credit sale. Your invoice number for FBR needs to include something that makes it unique, and it can only contain letters, digits and hyphens.
- The reference field means different things. On a sales voucher it usually holds the customer’s purchase order; on a note it may hold the original invoice. Don’t map it blindly into FBR’s reference field.
- Some vouchers must never reach FBR. Stock journals, branch transfers and own-consumption postings are not supplies to a buyer, and FBR refuses an invoice where the buyer is the seller. Filter them out before they reach the queue.
Identity fields that lie
Tally’s company and party ledgers have income-tax and sales-tax number fields, and by convention many Pakistani businesses type the NTN into the first and the STRN into the second. Both are free text with no validation, so treat them as a starting point, not a source of truth.
- Leading zeros disappear the moment an identifier is treated as a number. Keep every ID as text end to end.
- Punctuation hides a trap. Strip the dashes from an STRN and you can end up with exactly thirteen digits — the length of a CNIC. It will pass a length check and file against the wrong identity. Validate by field, not by length.
- Province is free text, and there is no city field. The ledger’s state field is often blank, and addresses are unlabelled lines. FBR wants one of its provinces (a city name such as “Karachi” is rejected), so set the province once per customer in your mapping.
- Registration type doesn’t exist in Tally. Whether a buyer is registered or unregistered changes what FBR expects on the invoice, and Tally has nowhere to hold it. Look it up from FBR against the buyer’s number and store it in the mapping.
Noticing new invoices
Because Tally can’t announce a new voucher, something has to keep asking. The simplest approach polls a short date window every few minutes and remembers which vouchers it has already handled. It works, but it re-reads the same vouchers repeatedly and can miss a voucher that is back-dated into a window it has already passed. A sturdier approach tracks Tally’s alteration identifiers and asks only for what has changed since the last high-water mark.
Whichever you choose, keep the polling interval short. FBR expects each invoice to be transmitted as it is generated, so a nightly run leaves you out of line with the rule every single day.
Proving it before go-live
Everything above can be tested before a single invoice is filed. FBR offers a dry run: a validation call that judges an invoice by the same rules as a real filing but leaves nothing behind — no record, no number. Run a full week of real Tally vouchers through it, then compare the total value and tax against Tally’s own sales register for the same week. If the two don’t match to the rupee, one of the traps on this page is the reason, and it is far cheaper to find it now than after filing.
After that comes FBR’s sandbox, where each business is assigned its own set of test scenarios, never all 28, and must pass them before production access is issued. Our sandbox to go-live guide covers that stage.
FAQs
Can Tally send invoices to FBR by itself? No. Tally has no FBR connection and cannot push data to another system. Invoices have to be read from Tally’s gateway, given the fields FBR requires that Tally doesn’t hold, and submitted individually through a filing layer.
Should we use ODBC instead of the XML gateway? Generally not for this. Tally’s ODBC interface is 32-bit, single-threaded and flattens the nested inventory lines an invoice depends on. It is fine for reports in Excel; for invoice-level extraction the XML gateway is the more reliable route.
Is it safe to open Tally’s port so a cloud service can reach it? No. The gateway has no password, so anyone who can reach it can read the entire company file. Run the reader on the same local network as Tally and have it make only outgoing connections.
Why does our reader return no invoices on some days? Check the company name first — Tally matches it literally and answers a near miss with an empty result rather than an error. Then check that the company is open in Tally and that no dialog box is waiting on the Tally PC.
Where should the HS code and sale type come from if Tally doesn’t hold them? From a mapping kept alongside Tally, set once per stock item or stock group and checked against FBR’s own lists. Our guide to mapping tax codes to FBR sale types walks through it.
Related reading: connecting Tally to FBR, mapping tax codes to FBR sale types and FBR invoice error codes.
Ready to simplify your FBR digital invoicing?
Join 2000+ businesses that use eInvoicePro to make invoices and send them to FBR.