TallyPrime & Tally.ERP 9 Native Connector

Real-Time RFID Tally Integration for Automated Inventory

Connect fixed RFID reader portals and rugged Android handhelds directly to TallyPrime via TCP Port 9000. Instantly generate Stock Journal vouchers, automate purchase receives, and verify physical warehouse godowns with 0% manual keystrokes.

Port 9000
Native HTTP Interface
<200ms
Voucher Creation
100%
Offline Queue WAL
0 Plugins
Core TDL Compatible
Tally RFID integration system for efficient tracking
Prerequisites & Configuration

How to Enable TallyPrime HTTP Server on Port 9000

Before physical RFID readers or edge gateways can post inventory vouchers, TallyPrime must be configured to accept incoming HTTP requests on port 9000:

1

Open Connectivity Settings

In TallyPrime, press F1 (Help) → Select Settings → Select Connectivity.

2

Configure Server Port

Under Client/Server configuration, set TallyPrime acts as to Both or Server, Enable ODBC to Yes, and Port to 9000.

3

Windows Firewall Rule

Open Windows Defender Firewall → Inbound Rules → New Rule → Port → TCP 9000 → Allow connection. This permits warehouse handhelds on Wi-Fi to reach the Tally server.

Voucher Architecture

Physical Stock vs. Stock Journal: Choosing the Right Voucher Type

Depending on your inventory workflow, OpenRFID compiles scanned EPC batches into either Physical Stock vouchers or Stock Journal envelopes:

Audit & Cycle Counting VCHTYPE="Physical Stock"

Physical Stock Voucher

Used when warehouse operators walk aisles with handheld scanners (Chainway C72 or Zebra MC3300R). It records the actual physical count found in each Godown and automatically reconciles book balance without affecting financial P&L accounts.

  • Replaces manual counting on clipboards with 700+ tags/sec sweeps.
  • Only specifies audited Godown, SKU name, Batch, and Actual Physical Qty.
  • Generates instant variance reports in Tally: Display → Statements of Inventory → Stock Summary.
Transfers & Production VCHTYPE="Stock Journal"

Stock Journal Voucher

Used for inter-godown transfers (e.g. moving goods from Central Warehouse to Retail Showroom) or consumption in manufacturing (Raw Materials issued to Work in Progress).

  • Supports dual line entries: Source (Consumption) and Destination (Production/Arrival).
  • Automates dock portal transit transfers when forklifts pass between warehouse bays.
  • Maintains FIFO cost attribution and GST state-to-state inventory trail.
Native TDL XML Payload

Automated Stock Journal Voucher XML Payload

This standard TDL XML payload is dynamically compiled by our RFID gateway and posted via HTTP to http://localhost:9000/:

POST http://localhost:9000/ text/xml;charset=utf-8
<ENVELOPE>
  <HEADER>
    <VERSION>1</VERSION>
    <TALLYREQUEST>Import</TALLYREQUEST>
    <TYPE>Data</TYPE>
    <ID>Vouchers</ID>
  </HEADER>
  <BODY>
    <DESC>
      <STATICVARIABLES>
        <SVVCHIMPORTFORMAT>XML</SVVCHIMPORTFORMAT>
        <SVCURRENTCOMPANY>Enterprise Garments Ltd</SVCURRENTCOMPANY>
      </STATICVARIABLES>
      <TALLYMESSAGE xmlns:UDF="TallyUDF">
        <VOUCHER VCHTYPE="Stock Journal" ACTION="Create" OBJVIEW="Inventory Voucher View">
          <DATE>20260912</DATE>
          <VOUCHERTYPENAME>Stock Journal</VOUCHERTYPENAME>
          <VOUCHERNUMBER>RFID-AUDIT-901</VOUCHERNUMBER>
          <NARRATION>Automated RFID audit sweep via Chainway C72</NARRATION>
          
          <!-- Source (Consumption) Godown -->
          <INVENTORYENTRIESIN.LIST>
            <STOCKITEMNAME>Cotton Denim Jeans 32</STOCKITEMNAME>
            <ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
            <RATE>1200.00</RATE>
            <AMOUNT>-12000.00</AMOUNT>
            <ACTUALQTY>-10 Pcs</ACTUALQTY>
            <BILLEDQTY>-10 Pcs</BILLEDQTY>
            <BATCHALLOCATIONS.LIST>
              <GODOWNNAME>Central Warehouse</GODOWNNAME>
              <BATCHNAME>LOT-2026-B</BATCHNAME>
              <AMOUNT>-12000.00</AMOUNT>
              <ACTUALQTY>-10 Pcs</ACTUALQTY>
              <BILLEDQTY>-10 Pcs</BILLEDQTY>
            </BATCHALLOCATIONS.LIST>
          </INVENTORYENTRIESIN.LIST>

          <!-- Destination (Audited) Godown -->
          <INVENTORYENTRIESOUT.LIST>
            <STOCKITEMNAME>Cotton Denim Jeans 32</STOCKITEMNAME>
            <ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>
            <RATE>1200.00</RATE>
            <AMOUNT>12000.00</AMOUNT>
            <ACTUALQTY>10 Pcs</ACTUALQTY>
            <BILLEDQTY>10 Pcs</BILLEDQTY>
            <BATCHALLOCATIONS.LIST>
              <GODOWNNAME>Audited Retail Floor</GODOWNNAME>
              <BATCHNAME>LOT-2026-B</BATCHNAME>
              <AMOUNT>12000.00</AMOUNT>
              <ACTUALQTY>10 Pcs</ACTUALQTY>
              <BILLEDQTY>10 Pcs</BILLEDQTY>
            </BATCHALLOCATIONS.LIST>
          </INVENTORYENTRIESOUT.LIST>
        </VOUCHER>
      </TALLYMESSAGE>
    </DESC>
  </BODY>
</ENVELOPE>
              

Why Use Native XML Over ODBC?

While Tally provides read-only ODBC access, ODBC cannot write multi-line inventory transactions with batch and godown allocations. The native XML HTTP server on Port 9000 is the official, high-integrity write protocol for TallyPrime.

Edge Debouncing & Deduplication

When a worker walks past a pallet, RFID tags respond hundreds of times per second. Our edge gateway buffers scans in a 3-second sliding window, deduplicates by EPC, resolves the SKU in local cache, and sends only aggregated line totals to TallyPrime.

Response Verification & Error Trap

Upon receiving the payload, Tally returns HTTP 200 with <CREATED>1</CREATED>. If an item does not exist or a date is locked, Tally returns <ERRORS>1</ERRORS> with <LINEERROR>, which our gateway automatically logs to prevent inventory mismatches.

Production Connector Code

Python 3 & C# .NET 8 TallyPrime HTTP Client Implementation

Production-grade scripts with connection health check, error XML parsing, and automated voucher creation:

tally_rfid_gateway.py
Python 3.10+ (Requests + ElementTree)
import requests
import xml.etree.ElementTree as ET
from typing import List, Dict, Tuple

class TallyRfidGateway:
    def __init__(self, host: str = "http://localhost", port: int = 9000, timeout: int = 10):
        self.endpoint = f"{host}:{port}/"
        self.timeout = timeout
        self.headers = {'Content-Type': 'text/xml; charset=utf-8'}

    def verify_connection(self) -> bool:
        """Ping TallyPrime HTTP Port 9000."""
        try:
            r = requests.get(self.endpoint, timeout=3)
            return r.status_code == 200
        except requests.exceptions.RequestException:
            return False

    def post_stock_journal(self, date_str: str, vch_no: str, item_name: str, 
                           src_godown: str, dest_godown: str, qty: int, rate: float = 0.0) -> Tuple[bool, str]:
        """
        Posts automated Stock Journal moving items from source godown to audited destination godown.
        Returns: (success: bool, response_message: str)
        """
        payload = f"""<ENVELOPE>
  <HEADER><VERSION>1</VERSION><TALLYREQUEST>Import</TALLYREQUEST><TYPE>Data</TYPE><ID>Vouchers</ID></HEADER>
  <BODY>
    <DESC><STATICVARIABLES><SVVCHIMPORTFORMAT>XML</SVVCHIMPORTFORMAT></STATICVARIABLES>
      <TALLYMESSAGE xmlns:UDF="TallyUDF">
        <VOUCHER VCHTYPE="Stock Journal" ACTION="Create">
          <DATE>{date_str}</DATE>
          <VOUCHERTYPENAME>Stock Journal</VOUCHERTYPENAME>
          <VOUCHERNUMBER>{vch_no}</VOUCHERNUMBER>
          <INVENTORYENTRIESIN.LIST>
            <STOCKITEMNAME>{item_name}</STOCKITEMNAME><ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
            <RATE>{rate}</RATE><AMOUNT>-{qty * rate}</AMOUNT><ACTUALQTY>-{qty} Pcs</ACTUALQTY><BILLEDQTY>-{qty} Pcs</BILLEDQTY>
            <BATCHALLOCATIONS.LIST><GODOWNNAME>{src_godown}</GODOWNNAME><ACTUALQTY>-{qty} Pcs</ACTUALQTY></BATCHALLOCATIONS.LIST>
          </INVENTORYENTRIESIN.LIST>
          <INVENTORYENTRIESOUT.LIST>
            <STOCKITEMNAME>{item_name}</STOCKITEMNAME><ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>
            <RATE>{rate}</RATE><AMOUNT>{qty * rate}</AMOUNT><ACTUALQTY>{qty} Pcs</ACTUALQTY><BILLEDQTY>{qty} Pcs</BILLEDQTY>
            <BATCHALLOCATIONS.LIST><GODOWNNAME>{dest_godown}</GODOWNNAME><ACTUALQTY>{qty} Pcs</ACTUALQTY></BATCHALLOCATIONS.LIST>
          </INVENTORYENTRIESOUT.LIST>
        </VOUCHER>
      </TALLYMESSAGE>
    </DESC>
  </BODY>
</ENVELOPE>"""
        try:
            resp = requests.post(self.endpoint, data=payload.encode('utf-8'), headers=self.headers, timeout=self.timeout)
            root = ET.fromstring(resp.content)
            created = int(root.findtext('.//CREATED') or 0)
            errors = int(root.findtext('.//ERRORS') or 0)
            if created > 0 and errors == 0:
                return True, f"Voucher {vch_no} created successfully."
            error_text = root.findtext('.//LINEERROR') or "Unknown TDL Error"
            return False, f"Tally Error: {error_text}"
        except Exception as ex:
            return False, f"Connection Failed: {str(ex)}"

            
TallyRfidService.cs
.NET 8 (HttpClient + System.Xml.Linq)
using System.Text;
using System.Xml.Linq;

namespace OpenRFID.TallyConnector;

public class TallyRfidService
{
    private readonly HttpClient _httpClient;
    private const string TallyUrl = "http://localhost:9000/";

    public TallyRfidService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<(bool Success, string Message)> CommitPhysicalStockAsync(string sku, string godown, int count)
    {
        var dateNow = DateTime.Now.ToString("yyyyMMdd");
        var xmlPayload = $@"<ENVELOPE>
  <HEADER><VERSION>1</VERSION><TALLYREQUEST>Import</TALLYREQUEST><TYPE>Data</TYPE><ID>Vouchers</ID></HEADER>
  <BODY><DESC><STATICVARIABLES><SVVCHIMPORTFORMAT>XML</SVVCHIMPORTFORMAT></STATICVARIABLES>
    <TALLYMESSAGE xmlns:UDF=""TallyUDF"">
      <VOUCHER VCHTYPE=""Physical Stock"" ACTION=""Create"">
        <DATE>{dateNow}</DATE>
        <VOUCHERTYPENAME>Physical Stock</VOUCHERTYPENAME>
        <ALLINVENTORYENTRIES.LIST>
          <STOCKITEMNAME>{sku}</STOCKITEMNAME>
          <ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
          <ACTUALQTY>{count} Pcs</ACTUALQTY>
          <BILLEDQTY>{count} Pcs</BILLEDQTY>
          <BATCHALLOCATIONS.LIST><GODOWNNAME>{godown}</GODOWNNAME><ACTUALQTY>{count} Pcs</ACTUALQTY></BATCHALLOCATIONS.LIST>
        </ALLINVENTORYENTRIES.LIST>
      </VOUCHER>
    </TALLYMESSAGE>
  </DESC></BODY></ENVELOPE>";

        using var content = new StringContent(xmlPayload, Encoding.UTF8, "text/xml");
        var response = await _httpClient.PostAsync(TallyUrl, content);
        var xmlResp = await response.Content.ReadAsStringAsync();

        var doc = XDocument.Parse(xmlResp);
        var created = (int?)doc.Descendants("CREATED").FirstOrDefault() ?? 0;
        var errors = (int?)doc.Descendants("ERRORS").FirstOrDefault() ?? 0;

        if (created > 0 && errors == 0) return (true, "Voucher created successfully in TallyPrime");
        
        var errorMsg = doc.Descendants("LINEERROR").FirstOrDefault()?.Value ?? "Unknown Tally XML Error";
        return (false, errorMsg);
    }
}
            

Frequently Asked Questions: TallyPrime RFID Integration

Technical answers for IT managers, warehouse architects, and Tally administrators.

How does an RFID scanner communicate with TallyPrime?
TallyPrime includes an internal HTTP XML server running on TCP Port 9000. When RFID handhelds (e.g. Chainway C72) or fixed dock readers scan tags, our OpenRFID middleware aggregates the tags and posts a standard TDL <ENVELOPE> XML payload directly to http://<tally-ip>:9000/ with zero manual keystrokes.
Can I connect an RFID scanner to Tally Prime without purchasing expensive third-party TDL plugins?
Yes. Tally Prime includes an integrated HTTP server running on TCP Port 9000 that natively processes standard XML envelopes. OpenRFID formats scanned EPC tags directly into standard Tally <ENVELOPE> payloads for Stock Journals and Physical Stock vouchers without requiring proprietary paid TDL plugins. For custom User Defined Fields (UDFs) like RFID Tag EPC or Antenna ID, we provide pre-compiled TDL definitions.
What is the difference between Physical Stock Voucher and Stock Journal in RFID audits?
A Physical Stock voucher (VCHTYPE="Physical Stock") is used for periodic stock counts and audits. It overrides the recorded godown balance with the exact physical count without generating financial debits or credits. A Stock Journal (VCHTYPE="Stock Journal") is used for inter-godown transfers (e.g., Raw Material to Production Floor) or recording manufacturing assembly/disassembly.
Which handheld RFID readers work best with Tally Prime in India?
Rugged Android terminals such as Chainway C72, Zebra MC3300R/RFD40, Seuic AutoID, and ATID AT911N running the OpenRFID mobile client connect directly over warehouse Wi-Fi to your on-premise or cloud Tally Server, allowing instantaneous physical stock audits.
Which Tally versions support RFID API integration?
All major versions including TallyPrime 1.0, 2.0, 3.0, 4.0, 5.0+ and Tally.ERP 9 (Release 6.x and higher). Both single-user (Silver) and multi-user (Gold/Server) editions support the HTTP XML interface.
Why does Tally return HTTP 200 even when a voucher fails to save?
Tally’s HTTP daemon returns HTTP 200 OK as long as the XML payload is syntactically well-formed, regardless of whether the voucher passed accounting validation. The integration gateway must parse the XML body for <ERRORS>1</ERRORS> and extract error messages from <LINEERROR> to detect master mismatches, closed voucher dates, or negative stock blocks.
How do you prevent Tally from crashing when reading 500+ tags per second?
Tally’s single-threaded XML engine cannot handle raw high-velocity socket bursts. Our middleware incorporates an in-memory ring-buffer with a 3-second debounce filter and micro-batches tags into idempotent, throttled voucher transactions.
What happens if warehouse Wi-Fi drops while scanning inventory?
The middleware includes an offline-first encrypted SQLite database (WAL mode). Vouchers are queued locally on the handheld or warehouse edge PC and automatically synced with TallyPrime once the network reconnects.

Need Turnkey RFID Deployment for TallyPrime?

From hardware mounting (Chainway, Zebra, Impinj) to custom godown mapping and staff handheld training, we deliver turnkey RFID solutions across India in 2–3 weeks with dedicated SLA support.