Tally is the default accounting system of small and mid-sized Indian business. TallyPrime (and its predecessor Tally.ERP 9) is desktop software installed on a shop or office machine, holding company data in a local .tsf file rather than in a cloud database. There is no hosted REST API and no developer console. What there is instead, and what every Indian integration vendor builds on, is a small HTTP server that Tally itself runs on port 9000, speaking a Tally-specific XML dialect. You POST an XML envelope to it, and you either get data back (an Export request) or you push vouchers and masters in (an Import request). If you want a seller's invoices, stock and ledgers out of Tally, or want to write sales invoices back in, this is the only programmatic route, and it requires an agent process on the same network as the Tally machine.
At a glance
What it is
Tally Solutions is a Bengaluru company whose accounting product has been the small-business standard in India since the 1990s, and is also used across the GCC, Kenya, Bangladesh and Nepal. The current release line is TallyPrime (7.x as of September 2026); the previous line, Tally.ERP 9, is still very widely installed and speaks the same XML. Tally Solutions has publicly claimed a user base in the millions of licences, and in practice any Indian D2C brand of meaningful size keeps its books, GST returns and often its inventory in Tally even when it sells on Shopify and five marketplaces.
For a commerce database this makes Tally the accounting side of the picture rather than the sales side. It holds the invoice of record, the GST treatment, the customer ledger balance, and frequently the authoritative stock figure per godown (Tally's word for warehouse or location). It does not hold marketplace order identifiers, courier tracking or settlement reports unless somebody has pushed them in.
The crucial architectural fact: Tally is not multi-tenant and is not on the internet. Each installation is one machine, with one or more companies loaded, and the XML server binds to that machine. Aggregators (EasyEcom, Unicommerce, Vinculum, Browntape, Zoho's Tally connector and dozens of smaller Tally partners) all solve this the same way, with a small Windows agent installed alongside Tally that polls it locally over 127.0.0.1:9000 and relays to a cloud endpoint. Tally also ships TallyPrime Server, a licensed edition for multi-user data access, and Tally.NET / Tally Cloud offerings for remote access, but those change where the machine lives rather than the protocol you speak to it.
API access
There is nothing to apply for. The requirements are operational:
- A running TallyPrime or Tally.ERP 9 process. The XML server lives inside the application. If Tally is closed, the port is closed.
- At least one company loaded. The help page for prerequisites states it plainly: at least one company must be loaded in Tally, selected from Company then Select. A request naming a company that is not loaded will fail.
- The HTTP listener enabled and a port chosen. In TallyPrime the setting is under F1 (Help) then Settings then Connectivity / Advanced Configuration, where you set the TallyPrime role (Both, Server, Client or None), enable ODBC if you want it, and set the port. 9000 is the documented default and is what every client library assumes.
- Network reach. For anything other than a same-machine agent you need a route to that host and port, which normally means a VPN, a tunnel, or the vendor agent pattern described above.
Versioning is a property of the installed release, not of the request. <VERSION>1</VERSION> in the header has been 1 across Tally.ERP 9 and TallyPrime alike; the thing that actually changes between releases is which TDL methods and which internal report names exist. Tally publishes a help page titled "What are the changes in XML tags" for release-to-release differences, which is the page to check when a working request starts returning empty data after a customer upgrades.
Official SDKs: none. Tally's own developer tooling is TDL (Tally Definition Language), a declarative language compiled into a .tcp file and loaded into Tally, plus TallyPrime Developer as the IDE. TDL is the route when you want to change Tally's behaviour or expose a custom collection; it is not needed to read or write standard objects. TallyPrime also ships a Tally Connector screen under Tools, which is a request tester: you give it a URL such as http://localhost:9000, headers, and an XML or JSON body, and it shows the response. That is the fastest way to validate a request during development.
Well-maintained third-party clients worth reading rather than reinventing:
dhananjay1405/tally-database-loader(Node.js, MIT) pulls masters and vouchers into SQL Server, MySQL, PostgreSQL or BigQuery. Itstally-export-config.yamlis effectively a published field map from Tally collections to relational columns.Accounting-Companion/TallyConnector(C#) is a typed model layer over the same XML, and its model classes name the exact import tags.
The XML server has no authentication, no TLS and no authorisation model. Anything that can reach port 9000 can read the company's entire ledger and write vouchers into it. Never expose it to a public interface. Bind the agent to loopback and tunnel out, and treat the port as equivalent to filesystem access to the books.
Authentication
There is none, and that is the honest answer for both TallyPrime and Tally.ERP 9. There is no token, no API key, no OAuth, no basic auth on the XML server.
What replaces identity is the pair of things a request has to state for itself:
- Which host and port.
http://<tally-host>:9000. The request path is empty; clients POST to the root. - Which company.
<SVCURRENTCOMPANY>inside<STATICVARIABLES>selects the loaded company for that request. Omit it and Tally uses whatever company is currently active in the UI, which is a common source of data landing in the wrong books. - Which period.
<SVFROMDATE>and<SVTODATE>, inYYYYMMDDform, scope voucher reads. Without them you get the current period as set in the application.
Character encoding matters more than usual. TallyPrime accepts UTF-8, UTF-16 and ASCII. Both reference clients send and read UTF-16LE with Content-Type: text/xml;charset=utf-16, and Content-Length computed over the UTF-16 byte length, because responses containing Indian-language master names come back garbled otherwise.
A minimal authenticated call does not exist, so here is the equivalent: a probe that asks Tally for the active company and its two alteration counters. If this returns a row, your transport is working.
Probe the local Tally XML server. No credentials exist to send. curl -s -X POST http://localhost:9000 \ -H 'Content-Type: text/xml;charset=utf-16' \ --data-binary @company-probe.xml
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>Export</TALLYREQUEST>
<TYPE>Collection</TYPE>
<ID>TallyDatabaseLoaderColl</ID>
</HEADER>
<BODY>
<DESC>
<TDL>
<TDLMESSAGE>
<COLLECTION NAME="TallyDatabaseLoaderColl">
<TYPE>company</TYPE>
<COMPUTE>IsActiveCompany : $$IsEqual:$Name:##SVCurrentCompany</COMPUTE>
<FETCH>BooksFrom,AltMstId,AltVchId</FETCH>
</COLLECTION>
</TDLMESSAGE>
</TDL>
</DESC>
</BODY>
</ENVELOPE>
Multi-account, meaning several sellers, is not a property of the protocol. Each seller is a separate Tally installation, so a connector stores a host, port and company name per seller and reaches each through its own agent or tunnel. Within one installation, several companies can be loaded at once and are separated by <SVCURRENTCOMPANY>.
Objects we can read
Every read is a TALLYREQUEST of Export. Three shapes are in use:
<TYPE>Collection</TYPE>with a TDLCOLLECTIONdefined inline in the request. This is the workhorse: you name a Tally collection (Ledger,StockItem,Voucher,Godown), list the methods toFETCH, optionally add aFILTER, and Tally returns XML objects. Nothing has to be installed in Tally first.<TYPE>Data</TYPE>with<ID>naming a report, either a built-in one (All Masters,Day Book,Trial Balance,Stock Summary) or a report you define inline in the same request through<TDL><TDLMESSAGE>. Defining the report inline and setting<SVEXPORTFORMAT>ASCII (Comma Delimited)</SVEXPORTFORMAT>gives you CSV rather than XML, which is what the database loader does for volume.<TYPE>Function</TYPE>with<ID>naming a TDL function, for example$$SystemPeriodFrom, to read a single scalar.
There is no pagination. Tally returns the whole collection or report in one response body. The scoping levers are the date window (SVFROMDATE and SVTODATE) and TDL FILTER expressions. For a large company the practical technique is to page by date: walk months, or walk days during backfill.
Orders
Sales orders and purchase orders are vouchers with VOUCHERTYPENAME of Sales Order and Purchase Order. They are read from the Voucher collection like any other voucher, distinguished by voucher type, and Tally exposes $$IsOrderVch:$VoucherTypeName as a test. Order lines carry ORDERNO and ORDERDUEDATE on the inventory entry, which is how a later delivery note or invoice is tied back to the order.
Request for vouchers in a period:
<ENVELOPE>
<HEADER>
<VERSION>1</VERSION>
<TALLYREQUEST>Export</TALLYREQUEST>
<TYPE>Collection</TYPE>
<ID>VchColl</ID>
</HEADER>
<BODY>
<DESC>
<STATICVARIABLES>
<SVCURRENTCOMPANY>Acme Traders</SVCURRENTCOMPANY>
<SVFROMDATE>20260401</SVFROMDATE>
<SVTODATE>20260930</SVTODATE>
</STATICVARIABLES>
<TDL>
<TDLMESSAGE>
<COLLECTION NAME="VchColl">
<TYPE>Voucher</TYPE>
<FETCH>Date,VoucherTypeName,VoucherNumber,Reference,ReferenceDate,PartyLedgerName,PlaceOfSupply,Narration,IsInvoice,IsCancelled,Guid</FETCH>
<FILTER>FltNotCancelled</FILTER>
</COLLECTION>
<SYSTEM TYPE="Formulae" NAME="FltNotCancelled">NOT $IsCancelled AND NOT $IsOptional</SYSTEM>
</TDLMESSAGE>
</TDL>
</DESC>
</BODY>
</ENVELOPE>
The fields above are the ones the database loader fetches for its trn_voucher table, so they are known to exist on current releases. Response objects are <VOUCHER> elements carrying those methods as child tags plus the nested entry lists described next.
Order items
Order and invoice lines live inside the voucher as ALLINVENTORYENTRIES.LIST (for invoice-mode vouchers) or INVENTORYENTRIES.LIST (for voucher-mode ones). Read them as a derived collection Voucher.AllInventoryEntries. The methods that matter:
Ledger postings for the same voucher are ALLLEDGERENTRIES.LIST, with LEDGERNAME, AMOUNT, ISDEEMEDPOSITIVE (Tally's sign convention: this flag, not the number, tells you debit versus credit), ISPARTYLEDGER, and nested BILLALLOCATIONS.LIST for bill-by-bill references.
A trimmed response, with the shape both reference clients parse:
<VOUCHER VCHTYPE="Sales" ACTION="Create">
<DATE>20260912</DATE>
<VOUCHERTYPENAME>Sales</VOUCHERTYPENAME>
<VOUCHERNUMBER>INV-2026-0417</VOUCHERNUMBER>
<REFERENCE>SO-8891</REFERENCE>
<PARTYLEDGERNAME>Kumar Retail</PARTYLEDGERNAME>
<PLACEOFSUPPLY>Karnataka</PLACEOFSUPPLY>
<PARTYGSTIN>29AABCU9603R1ZM</PARTYGSTIN>
<ISINVOICE>Yes</ISINVOICE>
<GUID>4f1d2a3b-0000-0000-0001-000000000417</GUID>
<ALLINVENTORYENTRIES.LIST>
<STOCKITEMNAME>Cold Pressed Oil 500ml</STOCKITEMNAME>
<RATE>450.00/Nos</RATE>
<ACTUALQTY>5 Nos</ACTUALQTY>
<BILLEDQTY>5 Nos</BILLEDQTY>
<AMOUNT>2250.00</AMOUNT>
<GODOWNNAME>Main Warehouse</GODOWNNAME>
<ACCOUNTINGALLOCATIONS.LIST>
<LEDGERNAME>Sales GST 18%</LEDGERNAME>
<ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
<AMOUNT>2250.00</AMOUNT>
</ACCOUNTINGALLOCATIONS.LIST>
</ALLINVENTORYENTRIES.LIST>
<ALLLEDGERENTRIES.LIST>
<LEDGERNAME>Kumar Retail</LEDGERNAME>
<ISPARTYLEDGER>Yes</ISPARTYLEDGER>
<ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>
<AMOUNT>-2655.00</AMOUNT>
</ALLLEDGERENTRIES.LIST>
</VOUCHER>
Money is unsigned text with a sign carried separately; parse AMOUNT together with ISDEEMEDPOSITIVE rather than trusting the minus. Quantities and rates arrive as strings with the unit appended and have to be split.
Products and listings
Tally's product object is the stock item, collection StockItem. It is a catalogue entry with costing, not a channel listing: there is no URL, no channel item id, no listing status. Verified fields, taken from the database loader's mst_stock_item map:
GstDetails and PartNo need an explicit <FETCH> because they are not returned by default. Selling price lives in a separate derived collection, StockItem.StandardPriceList (and StockItem.StandardCostList for cost), each entry carrying a date and a rate, so a price history rather than a single current price. Price levels, Tally's customer-tier pricing, are a further structure and are not exposed by either reference client.
Inventory
Two readings, and they answer different questions.
Closing balance per item, from ClosingBalance on the StockItem collection above, scoped by SVTODATE. This is the whole-company figure.
Balance per location and batch, from the derived collection StockItem.BatchAllocations, which in master context gives the opening position per godown and batch, and from Voucher.AllInventoryEntries.BatchAllocations for movements. Batch allocation entries carry GODOWNNAME, BATCHNAME, AMOUNT, ACTUALQTY, BILLEDQTY, and, for tracked goods, EXPIRYPERIOD and MFDON.
There is no reserved or inbound quantity concept in Tally. Pending sales orders can be derived by reading unfulfilled Sales Order vouchers, which is what Tally's own Order Summary reports do, but no field hands you quantity_reserved.
<COLLECTION NAME="StkColl"> <TYPE>StockItem</TYPE> <FETCH>Name,Parent,BaseUnits,ClosingBalance,ClosingRate,ClosingValue,InfGSTHSNCode,PartNo</FETCH> </COLLECTION>
Shipments and tracking
Not present as an object. Tally records a Delivery Note voucher (VOUCHERTYPENAME of Delivery Note) with the despatch fields on the voucher itself: BASICSHIPDOCUMENTNO, BASICSHIPPEDBY, BASICFINALDESTINATION, BILLOFLADINGNO, BILLOFLADINGDATE, DISPATCHFROMNAME and the related despatch-from address tags, plus EWAYBILLDETAILS.LIST for the GST e-way bill. Those are shipping paperwork, not carrier tracking: there is no AWB status, no scan events, no delivered timestamp. Carrier state has to come from the courier connector and be joined on the invoice number.
Returns and cancellations
Returns are vouchers, not a separate object. A sales return is a Credit Note; a purchase return is a Debit Note. Both carry the same inventory and ledger entry lists as an invoice and normally reference the original through REFERENCE or through a bill allocation of type Agst Ref. Cancelled vouchers are not deleted: they remain with ISCANCELLED set to Yes, which is why both reference clients filter NOT $IsCancelled AND NOT $IsOptional on every read. Optional vouchers (ISOPTIONAL) are Tally's draft state and should be excluded from any financial aggregate.
Payments and settlements
Receipts and payments are vouchers of type Receipt and Payment. Their ALLLEDGERENTRIES.LIST carries BANKALLOCATIONS.LIST with instrument details, and BILLALLOCATIONS.LIST with the bill-by-bill application: NAME (the bill reference), BILLTYPE (New Ref, Agst Ref, Advance, On Account) and AMOUNT. That structure is how you compute what is actually paid against an invoice rather than merely what the customer's balance is.
There is no settlement object in the marketplace sense. Marketplace payouts only exist in Tally if somebody has imported them as receipts or journals.
Customers
Customers and suppliers are both ledgers under the appropriate group, collection Ledger. The database loader's mst_ledger map names the fields, and they include full PII: Name, Parent (the group, which is how you tell Sundry Debtors from Sundry Creditors), Alias, MailingName, Address list, LedStateName, CountryName, PinCode, Email, LedgerMobile, IncomeTaxNumber (PAN), PartyGSTIN, GSTRegistrationType, OpeningBalance, ClosingBalance, BillCreditPeriod, and bank fields BankAccountHolderName, BankAccountNumber, IFSCode, SwiftCode, BankName, BankBranchName.
A Tally ledger read returns a company's entire customer list with postal addresses, phone numbers, PAN, GSTIN and bank account numbers, with no masking and no scope to narrow it. Treat the whole Ledger collection as PII, and fetch only the methods you need rather than using <FETCH>*</FETCH>.
Outstanding invoices per customer come from Ledger.BillAllocations in master context, giving opening bill-wise balances with NAME, BILLDATE and AMOUNT.
Locations
Godowns, collection Godown, with Guid, Name, Parent and Address. A godown may be a warehouse, a shop or a notional location such as "Goods in Transit". There is no type field to tell them apart, so classification has to come from naming convention.
Writing back: sales orders, invoices and stock adjustments
All three are the same operation. Tally's import is voucher-shaped, and its verbs are attributes on the object, not HTTP methods.
The envelope is TALLYREQUEST of Import Data, with <REQUESTDESC><REPORTNAME>Vouchers</REPORTNAME></REQUESTDESC> for transactions or <REPORTNAME>All Masters</REPORTNAME> for masters, and one <TALLYMESSAGE> per object inside <REQUESTDATA>. The object carries ACTION="Create", "Alter", "Delete" or "Cancel", and for vouchers a VCHTYPE attribute naming the voucher type.
A sales invoice. Voucher type Sales, with ISINVOICE set to Yes, party ledger, inventory entries and their accounting allocations, and tax ledger entries. The minimal documented form from the Tally help page is:
<ENVELOPE>
<HEADER>
<TALLYREQUEST>Import Data</TALLYREQUEST>
</HEADER>
<BODY>
<IMPORTDATA>
<REQUESTDESC>
<REPORTNAME>Vouchers</REPORTNAME>
<STATICVARIABLES>
<SVCURRENTCOMPANY>Acme Traders</SVCURRENTCOMPANY>
</STATICVARIABLES>
</REQUESTDESC>
<REQUESTDATA>
<TALLYMESSAGE>
<VOUCHER VCHTYPE="Sales" ACTION="Create">
<DATE>20260912</DATE>
<VOUCHERTYPENAME>Sales</VOUCHERTYPENAME>
<VOUCHERNUMBER>INV-2026-0417</VOUCHERNUMBER>
<PARTYLEDGERNAME>Kumar Retail</PARTYLEDGERNAME>
<ISINVOICE>Yes</ISINVOICE>
<ALLINVENTORYENTRIES.LIST>
<STOCKITEMNAME>Cold Pressed Oil 500ml</STOCKITEMNAME>
<RATE>450.00/Nos</RATE>
<ACTUALQTY>5 Nos</ACTUALQTY>
<BILLEDQTY>5 Nos</BILLEDQTY>
<AMOUNT>2250.00</AMOUNT>
<ACCOUNTINGALLOCATIONS.LIST>
<LEDGERNAME>Sales GST 18%</LEDGERNAME>
<ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE>
<AMOUNT>2250.00</AMOUNT>
</ACCOUNTINGALLOCATIONS.LIST>
</ALLINVENTORYENTRIES.LIST>
<ALLLEDGERENTRIES.LIST>
<LEDGERNAME>Kumar Retail</LEDGERNAME>
<ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE>
<AMOUNT>-2655.00</AMOUNT>
</ALLLEDGERENTRIES.LIST>
</VOUCHER>
</TALLYMESSAGE>
</REQUESTDATA>
</IMPORTDATA>
</BODY>
</ENVELOPE>
A sales order. The same request with VCHTYPE="Sales Order" and <VOUCHERTYPENAME>Sales Order</VOUCHERTYPENAME>, and ORDERNO plus ORDERDUEDATE on each inventory entry.
A stock adjustment. Tally has no quantity-set endpoint. You post a movement. The voucher types are Stock Journal (transfer or adjustment between godowns, with SOURCEALLOCATIONS.LIST and DESTINATIONALLOCATIONS.LIST) and Physical Stock (a count that overrides the computed balance). Writing "stock is now 42" therefore means either posting a physical stock voucher for 42, or computing the difference and posting a stock journal for it. This is the single biggest impedance mismatch between Tally and a marketplace connector, which expects to PUT an absolute quantity.
Masters. Stock items, ledgers, godowns, units and voucher types are created and altered with <REPORTNAME>All Masters</REPORTNAME> and objects such as <STOCKITEM NAME="Cold Pressed Oil 500ml" ACTION="Create"> or <LEDGER NAME="Kumar Retail" ACTION="Create">. Names are the key: an ACTION="Alter" on a name that does not exist fails rather than creating, and renaming is done with a NAME attribute plus an <OLDNAME> child. Because Tally keys masters by name, a connector must maintain its own mapping from SKU to Tally stock item name and keep it stable, since a user renaming an item in the UI will break the link silently.
Confirmation. Import is synchronous. The response is a status block naming what happened:
<RESPONSE> <CREATED>1</CREATED> <ALTERED>0</ALTERED> <DELETED>0</DELETED> <LASTVCHID>4182</LASTVCHID> <LASTMID>0</LASTMID> <COMBINED>0</COMBINED> <IGNORED>0</IGNORED> <ERRORS>0</ERRORS> </RESPONSE>
Check ERRORS and IGNORED, not just the HTTP 200. A request that references a ledger or stock item that does not exist, or a voucher type that is not defined in that company, comes back with ERRORS greater than zero and nothing written. There is no partial-success guarantee documented per object within one request, so the safe pattern for bulk work is small batches with per-batch reconciliation rather than one very large request body.
Idempotency. There is none. Posting the same voucher twice creates two vouchers. Two practical guards: put your source system's order id in <REFERENCE> or <VOUCHERNUMBER> and read back before writing, or enable duplicate-voucher-number prevention in the voucher type's configuration inside Tally, which makes the second attempt fail rather than duplicate.
Batch sizes. Not published. Both reference clients chunk by date range rather than by object count. Treat several hundred vouchers per request as the upper working range and tune down: Tally processes the whole body on the single UI thread and a very large import will freeze the application for the operator sitting in front of it.
Webhooks and notifications
None. TallyPrime does not emit events and has no subscription mechanism. TDL can be written to make Tally call out to an HTTP endpoint (the Data Source: HTTP XML and HTTP JSONEx collection attributes, $$HTTPInfo, and the Remote URL / Remote Request attributes exist precisely for this), but that is a customisation you compile and install per site, not a platform feature, and the trigger has to be a user action or a scheduled TDL event rather than a data change hook.
The supported pattern is polling, and Tally gives you a cheap change detector so you do not have to re-read everything. Every company exposes two counters:
AltMstId, the last alteration id across mastersAltVchId, the last alteration id across vouchers
Read both with the company probe request shown under Authentication. If neither has moved since the last poll, nothing changed and you can stop. If AltVchId has moved, re-read the voucher window. The database loader uses exactly this to drive incremental sync.
Recommended cadence: every 2 to 5 minutes for the counters (the request is trivially cheap), and a full re-read of the current month on change. A nightly full re-read of the financial year to catch back-dated edits, which Tally permits freely and which will otherwise silently desynchronise your copy.
Rate limits and pagination
No published rate limit, no quota headers, no throttling response. The limit is the application: TallyPrime is single-threaded for data operations and serves the XML request on the same process that serves the human operator. Two consequences for a connector:
- Serialise requests per Tally instance. Concurrency does not help and will make the UI unresponsive, which is how integrations get uninstalled.
- Prefer CSV to XML for large reads. Setting
<SVEXPORTFORMAT>ASCII (Comma Delimited)</SVEXPORTFORMAT>with an inline report definition returns delimited text that is a fraction of the size of the equivalent XML and parses far faster. The database loader does this and adds a sentinel character as an end-of-line field so that embedded newlines in narration do not corrupt rows.
Pagination does not exist. Scope by date window and by TDL FILTER. For a backfill, walk the financial year month by month; for steady state, re-read a trailing window of 7 to 30 days on every change to pick up back-dated vouchers.
A practical sync cadence that works within these constraints: alteration-counter poll every 2 minutes, incremental voucher read of the trailing 30 days on change, full master read hourly, full financial-year read nightly during a quiet hour.
Mapping to the unified model
Gaps and open questions
- Exact built-in report identifiers.
All Mastersis documented in the official XML integration page and is safe. Other commonly cited identifiers such asDay Book,Voucher Register,Trial BalanceandStock Summaryare Tally report names visible in the UI and are widely used in<ID>by integrators, but the help pages read here do not enumerate them as a supported API surface, and they differ across releases. Defining a report inline in the request through<TDL><TDLMESSAGE>avoids the question entirely and is what both reference clients do. Treat any hard-coded built-in report id as a per-release risk. - The JSON transport. TallyPrime documents JSON integration (
Data Source: HTTP JSONandHTTP JSONEx,$$HTTPInfo,$$ImportInfo, and JSON export of reports) alongside XML, and the Tally Connector tester accepts a JSON body. The request and response schema for JSON import of vouchers is not laid out on the pages read, and no reference client uses it. XML is the safe choice today; confirm the JSON path with Tally before relying on it. - TallyPrime MCP. Tally now publishes a help topic on connecting Claude Desktop to TallyPrime through an MCP server, with its own release notes. Whether that MCP server is a supportable machine interface for a data pipeline, what it exposes, and whether it requires TallyPrime 7.x, could not be determined from the landing page, which did not render its sub-topics. Worth a second look before assuming XML is the only modern route.
- Sign conventions and unit parsing.
AMOUNTcarrying a sign that must be read together withISDEEMEDPOSITIVE, and quantities and rates arriving as strings with units appended, are the two things that break naive parsers. Both are visible in the reference clients but are not spelled out in the help pages. - TallyPrime Server and remote access. How the licensed TallyPrime Server edition and Tally's remote-access offerings change the transport (host, port, whether any credential appears) was not verified here. If a customer is on TallyPrime Server, confirm before assuming plain port 9000.
- Per-object error detail on import. The status block gives counts. Whether a failing object inside a multi-object request aborts the whole request or is skipped, and how to identify which one failed, is not documented on the pages read and should be established empirically before designing batch sizes.
- No authentication is not a gap, it is the design. Any deployment plan has to answer the network question first. There is no way to make the protocol itself safer.
Sources
- Integrate with TallyPrime, Tally Solutions help
- XML Integration, Tally Solutions help: envelope structure, Import versus Export, port 9000, sample request and response
- Integration Methods and Technologies, Tally Solutions help: TDL, XML, JSON, DLL and ODBC compared
- Prerequisites for Integrations, Tally Solutions help: running instance, company loaded, port and role settings, encodings
- Integration initiated from TPAs, Tally Solutions help: the Import Data voucher example and the response status block
- Understanding Tally XML Tags, Tally Solutions help: header and body tag reference
- Collection-level attributes for integration, Tally Solutions help: Data Source, Remote URL, Remote Request, Export Header
- ODBC integrations, Tally Solutions help: TallyODBC_9000, sample SQL, IsODBCTable
- Tally Connector request tester, Tally Solutions help
- Connect Claude Desktop with TallyPrime, Tally Solutions help
- Tally developer reference, Tally Solutions help: TDL and TallyPrime Developer
- dhananjay1405/tally-database-loader, source read:
src/tally.mtsfor the HTTP transport, UTF-16 encoding, company probe and period-setting requests;tally-export-config.yamlfor the verified collection and method names used above - Accounting-Companion/TallyConnector, source read:
src/TallyConnector.Models/Base/Voucher.csfor the voucher, inventory entry and ledger entry import tag names