Transactions
"Transaction" (Txn) is the common record for every business document. Its type is txnHeader.txnType:
Invoice, Estimate, SalesOrder, ProformaInvoice, Delivery, SalesReturn, CreditNote, Bills, PurchaseBills, PurchaseOrder, PurchaseReturn, DebitNote, Expense, StockIncrease, StockDecrease, StockAdjustment, ProductionOrder, OpeningBalance, OpeningStock, OpeningReceivable, OpeningPayables.
Availability of each type depends on your plan.
Create or update a transaction
POST /txndata/upsertTxn — Permission: Write on a transaction type — multipart/form-data
| Form field | Type | Notes |
|---|---|---|
txnDto | string (JSON) | Required. A Txn object serialised to a JSON string. |
file | file | Optional attachment. |
Response 200:
{ "message": "Txn saved successfully!" }
What you must calculate yourself
The server validates your totals; it does not calculate them. Compute every amount before sending, and the request is rejected with 400 if any of these checks fail:
txnHeader.subtotalAmtmust equal the sum ofamtBeforeTaxacross alllineItems.txnHeader.totalAmtmust equalsubtotalAmt − discount + tax + shippingAmt + shippingtaxAmt + otherChargesAmt + roundOffAmt, within 0.02.discountisdiscountAmt, orsubtotalAmt × discountPct ÷ 100whenisDiscountPctistrue.taxis the sum oftxnTaxes[].taxAmt, except whentaxTypeis"Inclusive"(tax is already inside the subtotal and is not added again).txnHeader.paymentAmtcannot exceedtotalAmt.- For
Expense:expenseAcctis required, and eitherpaymentAcctor (payViaAP: truewith acontactId). - With no line items,
Invoice,SalesReturn,PurchaseBillsandPurchaseReturnneedsubtotalAmt > 0. - Line items that reference an inactive (archived) item are rejected.
- Outward stock transactions are checked against available inventory.
- A transaction reconciled with a bank transaction cannot have its amount or date changed.
- A transaction cannot be cancelled while it has payments, and its total cannot be reduced below the payments already allocated to it.
Document numbers
Set txnHeader.txnNo to the document number you want (for example INV-0042). If another document of the same type already uses that number, the server advances to the next free number in your numbering sequence and saves under that instead — read the saved document back to see the final number.
Example: create an invoice
One line: 2 × Widget A at 500, taxed at 18% (exclusive). Subtotal 1000, tax 180, total 1180.
curl -X POST "$BASE_URL/txndata/upsertTxn" \
-H "x-api-key: YOUR_API_KEY" \
-F 'txnDto={
"txnHeader": {
"txnId": "5d0c9a7e-3b1f-4a52-8c64-0e9f2b7a1c88",
"txnType": "Invoice",
"txnNo": "INV-0042",
"txnDate": "2026-09-25",
"dueDate": "2026-10-25",
"contactId": "c3b1f0e2-6a52-4c1a-9d0e-2f6b9a7d1e10",
"contactName": "Acme Traders",
"txnStatus": "Saved",
"taxType": "Exclusive",
"subtotalAmt": 1000,
"txnTaxes": [ { "taxId": "TAX_ID_18", "taxPct": 18, "taxAmt": 180 } ],
"totalAmt": 1180,
"balanceDue": 1180,
"paymentAllocAmt": 0
},
"lineItems": [
{
"lineId": "1",
"itemId": "8f14e45f-ceea-467a-9575-7d1b6c1a2b33",
"itemName": "Widget A",
"itemRate": 500,
"itemQty": 2,
"itemAmt": 1000,
"amtBeforeTax": 1000,
"taxId": "TAX_ID_18",
"taxPct": 18,
"taxAmt": 180,
"taxIncl": false,
"inventoryFlag": true
}
]
}'
Look up real taxId, itemId and contactId values with getTaxes, getItems and getContacts.
List transactions by type
GET /txndata/getTxns/{txnType}/{gtimeStamp?} — Permission: Read on a transaction type
| Parameter | Where | Notes |
|---|---|---|
txnType | path | One of the transaction types above. An unknown value returns 400. |
dateFilter | query, JSON (required) | See dateFilter. |
txnStatus | query, JSON array (optional) | For example ["Saved","Paid"]. Valid statuses: Saved, Draft, Paid, Allocated, Cancelled, Void, PartiallyPaid, Overdue. |
Returns Txn[], or 204 when none match.
Search transactions
GET /txndata/getTxnsWithFilters — Permission: Read on a transaction type
| Query | Type | Notes |
|---|---|---|
txnType | string | A transaction type. |
fromDate, toDate | ISO 8601 | Default: all time. |
contactId | string | Comma-separated contact IDs. |
itemList | string | Comma-separated item IDs. |
txnStatus | string | Comma-separated statuses. |
tagsFilter | string | Comma-separated tags. |
branchId | string | Optional. |
Returns Txn[], or 204.
Other transaction endpoints
| Endpoint | Permission | Description |
|---|---|---|
GET /txndata/getTxn/{txnId} | Read on a transaction type | One Txn, or 404. |
PUT /txndata/cancelTxn/{txnId} | Write on a transaction type | Cancels the transaction. Fails while it has active payments. Returns { "message": "Cancel Success!" }. |
DELETE /txndata/deleteTxn/{txnId} | Full on a transaction type | Deletes the transaction. Returns { "message": "Delete Success!" }. |
DELETE /txndata/bulkDeleteTxn | Full on a transaction type | Body: { "txnIds": ["id1","id2"] }. Returns { "message": "...", "data": { "totalRequested", "successful", "failed", "results": [{ "id", "success", "error?" }] } }. Returns 404 if none could be deleted. |
GET /txndata/getEarliestModifiedDate?startDate=… | Read on a transaction type | Earliest modification date of any transaction since startDate (required). Returns { "earliestDate": "…" | null }. Useful for deciding how far back to re-sync. Optional branchId, filterBranch=true. |
GET /txndata/getTxnLogs/{objectId} | Read on a transaction type | Delivery log (email and WhatsApp) for a transaction or payment ID. |
POST /txndata/sendTxn | Write on a transaction type | Emails a transaction PDF to up to 3 recipients. Body: toEmails[], ccEmails[], note, txnId, txnType, docNo, and htmlContent — the rendered HTML of the document, which the server converts to PDF. Rate-limited, see above. |
POST /txndata/sendTxnWP | Write on a transaction type | Sends a transaction over WhatsApp to up to 3 numbers. Body: phoneNumber[], txnId, txnType, htmlContent (required), and optional customerName and amount/currency fields. Rate-limited. |
Data model
Only the commonly used properties are listed. Unless marked required, every property is optional. Properties that the server sets itself (bizId, createdBy, modifiedBy, app, and creation/modification timestamps) should be left out of requests. The OpenAPI document has the complete definitions.
Txn
{
"txnHeader": { },
"lineItems": [ ],
"contactInfo": { },
"branchId": "…"
}
| Property | Type | Notes |
|---|---|---|
txnHeader | object | Required. See below. |
lineItems | object[] | The document's lines. |
contactInfo | Contact | Optional snapshot of the contact. |
txnHeader
| Property | Type | Notes |
|---|---|---|
txnId | string | Required. Caller-generated unique ID. |
txnType | string | One of the transaction types listed at the top of this page. |
txnNo | string | Your document number. |
txnDate, dueDate | date | |
txnStatus | string | Saved, Draft, Paid, Allocated, Cancelled, Void, PartiallyPaid, Overdue. |
contactId, contactName | string | The customer or vendor. |
txnDescription, notes, terms, reference | string | |
poNum, poDate | string, date | Customer purchase-order reference. |
currencyId, fxRateAmt | string, number | Foreign-currency documents. |
taxType | string | Exclusive or Inclusive. |
subtotalAmt | number | Sum of lineItems[].amtBeforeTax. |
discountAmt, discountPct, isDiscountPct | number, number, boolean | Document-level discount. |
txnTaxes | object[] | [{ "taxId", "taxPct", "taxAmt" }] — one entry per tax applied. |
shippingAmt, shippingAcct, shippingtaxAmt, shippingtaxId | number, string | Shipping charge and its tax. |
otherChargesAmt, otherChargesAcct | number, string | |
withHoldingAmt, withHoldingTaxAcct | number, string | Withholding tax. |
roundOffAmt | number | Rounding adjustment. |
totalAmt | number | See What you must calculate yourself. |
paymentAmt | number | Amount paid at the time of creation. Cannot exceed totalAmt. |
balanceDue | number | Outstanding amount. |
paymentAllocAmt | number | Amount already allocated by payments. |
txnAcct | string | Override for the main ledger account. Normally omit and let default account mapping apply. |
billingAddress, shippingAddress | string | |
paymentTermsId, paymentTerms | string | |
placeOfSupply, inGSTTreatment, inGstNo, inSupplyType, inReverseCharge, inItc | mixed | India GST fields. |
salesPerson, salesPersonId | string | |
tags | string[] | |
customFields | object[] | User-defined fields. |
expenseAcct, paymentAcct, payViaAP, paymentMode | mixed | Expense documents only — see the validation rules above. |
convertedFromTxnId, convertedFromTxnType | string | Set when converting, for example an Estimate into an Invoice. |
projectId | string | Link to a project. |
attachmentId | string | Read-only. Set by the server when a file is uploaded. |
Recurring-invoice, export-shipping and e-invoice properties also exist on txnHeader; see the OpenAPI document.
lineItems[]
| Property | Type | Notes |
|---|---|---|
lineId | string | Identifier of the line within the document. |
itemId | string | The item sold or bought. |
itemName, itemTxt, itemCode | string | Name, description and code as shown on the document. |
itemRate | number | Unit price. |
itemQty | number | Quantity. |
itemAmt | number | itemRate × itemQty. |
discountAmt, discountPct, isDiscountPct | number, number, boolean | Line discount. |
amtBeforeTax | number | Line amount after line discount, before tax. These sum to subtotalAmt. |
taxId, taxName, taxPct, taxAmt, taxIncl | mixed | The line's tax. |
taxBreakup | object[] | Per-component tax detail: taxId, taxName, taxPct, taxAcct, taxAmt. |
uomId, uomNm | string | Unit of measure. |
acctId | string | Ledger account for the line. |
inventoryFlag | boolean | Whether the line affects stock. |
deleteFlag | boolean | true to remove the line when updating. |
tagId | string |