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.

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:
Open Connectivity Settings
In TallyPrime, press F1 (Help) → Select Settings → Select Connectivity.
Configure Server Port
Under Client/Server configuration, set TallyPrime acts as to Both or Server, Enable ODBC to Yes, and Port to 9000.
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.
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:
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.
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.
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/:
<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.
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.
Python 3 & C# .NET 8 TallyPrime HTTP Client Implementation
Production-grade scripts with connection health check, error XML parsing, and automated voucher creation:
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)}"
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?
Can I connect an RFID scanner to Tally Prime without purchasing expensive third-party TDL plugins?
What is the difference between Physical Stock Voucher and Stock Journal in RFID audits?
Which handheld RFID readers work best with Tally Prime in India?
Which Tally versions support RFID API integration?
Why does Tally return HTTP 200 even when a voucher fails to save?
How do you prevent Tally from crashing when reading 500+ tags per second?
What happens if warehouse Wi-Fi drops while scanning inventory?
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.