For years, connecting Tally to anything was painful: no REST API, no cloud endpoint, just a local port on an office desktop. This guide explains exactly how Tally's XML-over-HTTP gateway works, how to bridge it to the internet safely, and how to send payment reminders and import orders between TallyPrime and WhatsApp.
Tally has no REST API and no hosted cloud endpoint. It exposes an XML-over-HTTP gateway on a local port (default 9000). That gateway is genuinely powerful: you can read every report and write vouchers and masters. The only real difficulty is that the gateway lives on a local machine, so a cloud platform like WA.Expert needs a bridge to reach it. This guide covers the gateway, the bridge, and the exact XML for both directions.
Unlike a modern SaaS tool with a JSON REST API, TallyPrime communicates using XML over HTTP. When you enable the gateway, Tally itself becomes a small HTTP server. You POST an XML request describing what you want, and Tally responds with XML.
There are three request types, set in the
<TALLYREQUEST> tag:
| Request type | What it does | Example use |
|---|---|---|
| EXPORT | Read data and reports out of Tally | Get outstanding receivables, ledger balances, the Day Book, Trial Balance. |
| IMPORT | Write masters and transactions into Tally | Create a customer ledger, post a sales voucher from a WhatsApp order. |
| EXECUTE | Run a Tally function | Less common; used for specific TDL functions. |
Every request shares the same envelope shape: a
<HEADER> that says what you want, and a <BODY>
that carries the detail.
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>EXPORT</TALLYREQUEST> <!-- EXPORT / IMPORT / EXECUTE -->
<TYPE>COLLECTION</TYPE> <!-- OBJECT / COLLECTION / DATA -->
<ID>List of Ledgers</ID> <!-- report or collection name -->
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
<SVCURRENTCOMPANY>ABC Traders</SVCURRENTCOMPANY>
</STATICVARIABLES>
</DESC>
</BODY>
</ENVELOPE>Tally's own developer documentation states that Tally can communicate with any environment capable of sending and receiving XML over HTTP, including web scripting languages and applications. This is not a hack: it is the official, documented integration mechanism. Reference: Tally developer reference.
Here is the catch that has frustrated businesses for years. The Tally
gateway listens on localhost:9000. Localhost means "this machine only", so a
cloud platform on the internet cannot reach it. WA.Expert's HTTP step runs in the cloud,
not on your office PC, so it cannot call localhost:9000 directly.
There are three proven ways to bridge that gap. Choose based on your security needs and whether your Tally is on a desktop or already on a cloud server.
| Bridge option | How it works | Best for |
|---|---|---|
| Secure tunnel (Cloudflare Tunnel / ngrok) | A small agent on the Tally PC creates an outbound HTTPS tunnel, giving Tally a public https URL without opening firewall ports. | Quick setup, single office PC running Tally. |
| TallyPrime on Cloud (OCI / AWS) | Tally runs on a cloud-hosted virtual machine that already has a reachable address. The gateway is exposed within the secured cloud network. | Businesses already moving Tally to the cloud for remote access. |
| Outbound local connector | A small program on the Tally PC polls Tally with XML EXPORT, then calls WA.Expert outbound. Tally is never exposed to the internet at all. | Regulated businesses; the most secure option. |
For finance data, the outbound connector pattern is the safest: Tally stays completely private and only makes outbound calls.
The Tally gateway has no built-in authentication. Anyone who can reach the port can read and write your books. Always put it behind a secure tunnel with access controls, keep it inside a private cloud network, or use the outbound connector pattern so the port is never publicly reachable.
9000 (or any free port).http://localhost:9000.# A simple POST that asks Tally for its list of ledgers.
# If Tally responds with XML, the gateway is working.
curl --location 'http://localhost:9000' \
--header 'Content-Type: text/xml' \
--data '<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>EXPORT</TALLYREQUEST>
<TYPE>COLLECTION</TYPE>
<ID>List of Ledgers</ID>
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
</STATICVARIABLES>
</DESC>
</BODY>
</ENVELOPE>'Tally accepts text/xml (UTF-8 by default), UTF-16 (needed for the Rupee symbol and other special characters), and ASCII. Use UTF-16 if amounts or names contain currency symbols. The HTTP method is always POST.
The fastest bridge for a single office PC is Cloudflare Tunnel. It runs a small agent on the Tally machine and gives Tally a public HTTPS URL without opening any firewall ports.
# 1. Install cloudflared on the Tally PC (one-time).
# 2. Authenticate and create a named tunnel:
cloudflared tunnel login
cloudflared tunnel create tally-gateway
# 3. Route a hostname to the local Tally port:
cloudflared tunnel route dns tally-gateway tally.yourdomain.com
# 4. Run the tunnel pointing at Tally:
cloudflared tunnel --hostname tally.yourdomain.com \
--url http://localhost:9000 run tally-gateway
# Tally is now reachable at:
# https://tally.yourdomain.com
# Add Cloudflare Access in front of it to require authentication.For a quick test, ngrok http 9000 gives you a temporary public HTTPS URL in seconds. For production, Cloudflare Tunnel or a cloud-hosted Tally with access controls is more dependable. Whichever you choose, always require authentication in front of the tunnel.
This is the highest-value direction for most businesses: read data out of Tally, then send it to customers or the owner on WhatsApp. The flagship use case is automated payment reminders from outstanding receivables.
Send an EXPORT request for the Bills Receivable report. Tally returns every outstanding bill with the party name and amount.
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>EXPORT</TALLYREQUEST>
<TYPE>DATA</TYPE>
<ID>Bills Receivable</ID>
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
<SVCURRENTCOMPANY>ABC Traders</SVCURRENTCOMPANY>
<SVFROMDATE TYPE="Date">20260401</SVFROMDATE>
<SVTODATE TYPE="Date">20260623</SVTODATE>
</STATICVARIABLES>
</DESC>
</BODY>
</ENVELOPE>
Tally responds with XML listing each outstanding bill:
party name, bill reference, due date, and pending amount.When a customer messages "what is my balance?" on WhatsApp, fetch their exact outstanding from Tally with a Ledger export.
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>EXPORT</TALLYREQUEST>
<TYPE>OBJECT</TYPE>
<SUBTYPE>Ledger</SUBTYPE>
<ID TYPE="Name">Rajesh Enterprises</ID>
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVEXPORTFORMAT>$$SysName:XML</SVEXPORTFORMAT>
</STATICVARIABLES>
<FETCHLIST>
<FETCH>Name</FETCH>
<FETCH>ClosingBalance</FETCH>
<FETCH>LedgerMobile</FETCH>
</FETCHLIST>
</DESC>
</BODY>
</ENVELOPE>
Returns Name, ClosingBalance, and the stored mobile number,
which you prepend +91 to before sending the WhatsApp.Connector or scheduled automation, once per day:
1. POST EXPORT 'Bills Receivable' to the Tally bridge URL.
-> Tally returns all outstanding bills as XML.
2. Parse the XML. For each overdue party:
party_name = 'Rajesh Enterprises'
pending_amount = 48500.00
due_date = '2026-06-10'
mobile = '9820012345' (from the ledger master)
3. wa_phone = '+91' + mobile = '+919820012345' <- PREPEND +91
4. Call WA.Expert send-message API for each party:
'Dear Rajesh Enterprises, our records show an outstanding
balance of Rs. 48,500 due since 10 June 2026.
Kindly arrange payment. Reply here for any query.'
Result: dozens of polite, accurate reminders sent automatically
every morning, straight from your Tally books.Tally stores LedgerMobile as whatever was typed, usually a bare 10-digit Indian number. WA.Expert needs +919820012345. Prepend +91 in your connector or automation before sending, and strip any spaces or leading zeros.
The reverse direction writes into Tally. When a customer confirms an order on WhatsApp, create the sales voucher in Tally automatically so the books stay current without manual entry.
Tally rejects a voucher if the ledgers it references do not exist. Before posting a sales voucher for a new customer, create the party ledger (under Sundry Debtors) and ensure the Sales ledger exists (under Sales Accounts). Send the ledger IMPORT first, then the voucher IMPORT.
<ENVELOPE>
<HEADER>
<TALLYREQUEST>Import Data</TALLYREQUEST>
</HEADER>
<BODY>
<IMPORTDATA>
<REQUESTDESC>
<REPORTNAME>All Masters</REPORTNAME>
</REQUESTDESC>
<REQUESTDATA>
<TALLYMESSAGE xmlns:UDF="TallyUDF">
<LEDGER Action="Create">
<NAME>Priya Textiles</NAME>
<PARENT>Sundry Debtors</PARENT>
<LEDGERMOBILE>9820012345</LEDGERMOBILE>
<LEDSTATENAME>Maharashtra</LEDSTATENAME>
<COUNTRYNAME>India</COUNTRYNAME>
</LEDGER>
</TALLYMESSAGE>
</REQUESTDATA>
</IMPORTDATA>
</BODY>
</ENVELOPE>The party ledger is debited (positive) and the sales ledger is credited (negative). The two must sum to zero or Tally rejects the voucher.
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>Import</TALLYREQUEST>
<TYPE>Data</TYPE>
<ID>Vouchers</ID>
</HEADER>
<BODY>
<DESC></DESC>
<DATA>
<TALLYMESSAGE>
<VOUCHER VCHTYPE="Sales" ACTION="Create">
<DATE>20260623</DATE>
<VOUCHERTYPENAME>Sales</VOUCHERTYPENAME>
<VOUCHERNUMBER>1</VOUCHERNUMBER>
<PERSISTEDVIEW>Accounting Voucher View</PERSISTEDVIEW>
<ISINVOICE>No</ISINVOICE>
<LEDGERENTRIES.LIST>
<LEDGERNAME>Priya Textiles</LEDGERNAME>
<ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>
<ISPARTYLEDGER>Yes</ISPARTYLEDGER>
<AMOUNT>-11800.00</AMOUNT>
</LEDGERENTRIES.LIST>
<LEDGERENTRIES.LIST>
<LEDGERNAME>Sales</LEDGERNAME>
<ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
<AMOUNT>11800.00</AMOUNT>
</LEDGERENTRIES.LIST>
</VOUCHER>
</TALLYMESSAGE>
</DATA>
</BODY>
</ENVELOPE>
Response includes <CREATED>1</CREATED> on success,
or <LINEERROR> describing why it failed.Debit total must equal credit total, to the paisa. The party ledger amount is negative and the sales ledger amount is positive (or vice versa for a receipt). If they do not net to zero, Tally returns Voucher totals do not match! and creates nothing. Dates must be in YYYYMMDD format.
| Tally response | What it means | Fix |
|---|---|---|
| DESC not found | A referenced master (ledger, stock item) does not exist in Tally. | Create the dependent ledgers and stock items first with an IMPORT, then retry the voucher. |
| Voucher totals do not match! | Debit and credit amounts do not net to zero. | Check the signs: party ledger negative, sales ledger positive. They must sum to exactly zero. |
| No response / connection refused | Gateway not running or not reachable. | Confirm Tally is open with the company loaded, the port is set in Data Synchronization, and the tunnel or connector is running. |
| Empty or partial data on EXPORT | Company not loaded, or wrong SVCURRENTCOMPANY. | Load the correct company in Tally and set SVCURRENTCOMPANY to the exact company name. |
| LINEERROR about ledger nature | Ledger created under the wrong group. | Sales ledger must be under Sales Accounts, party ledger under Sundry Debtors. Create masters under the correct group. |
| Garbled currency symbols | Encoding mismatch on amounts with the Rupee symbol. | Send the request as UTF-16 (Content-Type: UTF-16) so special characters render correctly. |
Tally also logs every import to a Tally.imp file in the TallyPrime installation folder, which is useful for debugging failed vouchers.
The most reliable way to learn the exact XML for any voucher or master is to create one manually in Tally, then export it as XML (Tally → export the master/voucher). Tally shows you the precise tag structure it expects. Copy those tags into your IMPORT request. This removes all guesswork about optional fields.
Tally integration has more moving parts than a normal cloud API: the gateway, the bridge, and the XML mapping. If you would like a hand setting up the connector or the payment-reminder flow for your business, book a call and the WA.Expert team will walk you through it.
ERPNext: a modern open-source ERP with a proper REST API and webhooks.
Read guide →Zoho Books: cloud accounting with OAuth and webhooks for invoices.
Read guide →Free trial, no credit card. Tally setups are our specialty, we answer live on WhatsApp.