Tax Invoices & Sales Billing
Create, send, and manage GST 2.0-compliant tax invoices in Katixo. Learn how invoices automate customer receivables (AR), trigger stock deductions or inherit from Delivery Challans, post compound General Ledger journals, and record customer payments.
1. Module Overview: The Core Commercial Sales Document
Under Section 31 of the Central Goods and Services Tax (CGST) Act, 2017, a registered business supplying taxable goods or services must issue a legal Tax Invoice. In Katixo ERP, the invoice is the primary commercial engine connecting sales, inventory, and financial ledgers:
GST 2.0 Tax Splitting
Compares Supplier State vs Customer Place of Supply (POS) to automatically apply CGST+SGST or IGST.
Dual Dispatch Mechanics
Direct invoices deduct stock upon send; Delivery Challan-linked invoices reuse already-dispatched stock without duplication.
Live Accounts Receivable
Instantly updates customer ledger, credit limit utilization, and aging buckets (0-30, 31-60, 60+ days).
2. How to Create an Invoice (Step-by-Step UI Guide)
- 1Navigate to Sales > Invoices > Click "Create Invoice":Select the customer contact. Katixo auto-populates their GSTIN, billing address, shipping address, and Place of Supply (State Code).
- 2Set Dates & Payment Terms:Choose the Invoice Date and Due Date (defaults automatically to the customer's configured payment terms, e.g. Net 30).
- 3Add Item Lines:Search items by name or scan barcode. The system retrieves the statutory HSN code, unit price, and GST rate. Enter quantity and any line discount percentage.
- 4Save as Draft or Click "Send":Saving as
DRAFTallows packing and verification. Clicking "Send" officially posts the invoice to the customer ledger, generates the PDF, and delivers it via WhatsApp or Email.
3. Automated General Ledger & Stock Posting
When an invoice transitions from DRAFT to SENT, Katixo executes a balanced double-entry General Ledger journal:
• DEBIT: Accounts Receivable (1100) — [Gross Total with GST]
• CREDIT: Sales Revenue (4000) — [Taxable Subtotal]
• CREDIT: Output CGST / SGST (Intra-state) or Output IGST (Inter-state) — [GST Total]
• DEBIT: Cost of Goods Sold (5000) / CREDIT: Inventory Asset (1200) — [Blended FIFO Cost]
Developer & REST API Reference
Programmatically query, create, send, and record payments against tax invoices via REST endpoints.
/api/v1/invoices/api/v1/invoices/{id}/api/v1/invoices/api/v1/invoices/{id}/send/api/v1/invoices/{id}/cancel/api/v1/invoices/{id}/pdf/api/v1/invoices/{id}/payments/api/v1/invoices/{id}/payments/api/v1/invoices/{id}/payments/{paymentId}/api/v1/invoices/bulk-send/api/v1/invoices/bulk-cancelAuthorization header. All IDs are UUIDs.The InvoiceResponse object
{
"success": true,
"message": "Invoice retrieved successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"invoiceNumber": "KTX/2026-27/0042",
"contactId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"customerName": "Sharma Kirana Store",
"invoiceDate": "2026-06-11",
"dueDate": "2026-07-11",
"status": "SENT",
"subtotal": 1450.00,
"taxAmount": 72.50,
"totalAmount": 1522.50,
"amountPaid": 0.00,
"balanceDue": 1522.50,
"placeOfSupply": "27",
"notes": "Payment due within 30 days",
"lines": [
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"lineNumber": 1,
"description": "Toor Dal 1kg",
"hsnCode": "07139090",
"itemId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"quantity": 10,
"unitPrice": 145.00,
"discountPercent": 0,
"discountAmount": 0.00,
"taxableAmount": 1450.00,
"gstRate": 5.00,
"taxAmount": 72.50,
"lineTotal": 1522.50
}
],
"createdAt": "2026-06-11T05:00:00Z"
},
"errors": null
}Invoice statuses
| Status | Description |
|---|---|
DRAFT | Invoice created but not yet sent to the customer. |
SENT | Invoice has been sent to the customer and is awaiting payment. |
PAID | Full payment has been received. Balance due is zero. |
OVERDUE | Invoice is past its due date with balance still outstanding. |
CANCELLED | Invoice has been cancelled. Remains in system for audit purposes. |
List invoices
/api/v1/invoicesReturns a paginated list of invoices. The response is wrapped in ApiResponse<PagedResponse<InvoiceResponse>>.
Roles: OWNER, ADMIN, ACCOUNTANT, OPERATOR, VIEWER
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | String | Filter by status: DRAFT, SENT, PAID, CANCELLED, OVERDUE. |
contactId | UUID | Filter by contact (customer). |
dateFrom | LocalDate | Invoice date on or after this date (YYYY-MM-DD). |
dateTo | LocalDate | Invoice date on or before this date. |
search | String | Free-text search across invoice number and customer name. |
page | int | Page number (zero-based, default: 0). |
size | int | Results per page (default: 20). |
sort | String | Sort field and direction, e.g. invoiceDate,desc. |
curl https://api.katixo.com/api/v1/invoices?status=SENT&dateFrom=2026-04-01&page=0&size=10 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response
{
"success": true,
"message": "Invoices retrieved successfully",
"data": {
"content": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"invoiceNumber": "KTX/2026-27/0042",
"contactId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"customerName": "Sharma Kirana Store",
"invoiceDate": "2026-06-11",
"dueDate": "2026-07-11",
"status": "SENT",
"subtotal": 1450.00,
"taxAmount": 72.50,
"totalAmount": 1522.50,
"amountPaid": 0.00,
"balanceDue": 1522.50,
"placeOfSupply": "27",
"notes": null,
"lines": [...],
"createdAt": "2026-06-11T05:00:00Z"
}
],
"page": 0,
"size": 10,
"totalElements": 42,
"totalPages": 5,
"last": false
},
"errors": null
}Get an invoice
/api/v1/invoices/{id}Retrieves a single invoice by its UUID. Returns ApiResponse<InvoiceResponse>.
curl https://api.katixo.com/api/v1/invoices/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Create an invoice
/api/v1/invoicesCreates a new invoice in DRAFT status. Returns 201 Created on success.
Roles: OWNER, ADMIN, ACCOUNTANT, OPERATOR
CreateInvoiceRequest body
| Field | Type | Required | Description |
|---|---|---|---|
contactId | UUID | Yes | ID of the customer contact. |
invoiceDate | LocalDate | Yes | Date of the invoice (YYYY-MM-DD). |
dueDate | LocalDate | No | Payment due date. Defaults based on contact payment terms. |
placeOfSupply | String | No | State code (e.g. "27" for Maharashtra). Determines CGST+SGST vs IGST. |
notes | String | No | Free-text notes printed on the invoice. |
termsAndConditions | String | No | Terms and conditions text printed on the invoice. |
lines | InvoiceLineRequest[] | Yes | At least one line item is required. See line item fields below. |
InvoiceLineRequest fields
| Field | Type | Required | Description |
|---|---|---|---|
itemId | UUID | No | Reference to an item in the item master. Optional for ad-hoc line items. |
description | String | Yes | Description of the item or service. |
hsnCode | String | No | HSN/SAC code for GST classification. |
quantity | BigDecimal | Yes | Quantity of items. |
unitPrice | BigDecimal | Yes | Price per unit (before tax). |
discountPercent | BigDecimal | No | Discount percentage on this line (e.g. 5.00 for 5%). |
gstRate | BigDecimal | No | GST rate percentage (e.g. 5.00, 12.00, 18.00). Auto-resolved from item master if omitted. |
taxGroupId | UUID | No | Tax group to apply. Overrides gstRate if provided. |
Example: create an invoice for a kirana store
curl -X POST https://api.katixo.com/api/v1/invoices \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"contactId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"invoiceDate": "2026-06-11",
"dueDate": "2026-07-11",
"placeOfSupply": "27",
"notes": "Delivery to Sharma Kirana Store, Pune",
"termsAndConditions": "Payment due within 30 days. Late fee of 1.5% per month.",
"lines": [
{
"itemId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"description": "Toor Dal 1kg",
"hsnCode": "07139090",
"quantity": 10,
"unitPrice": 145.00,
"gstRate": 5.00
},
{
"itemId": "d4e5f6a7-b8c9-0123-def0-234567890123",
"description": "Basmati Rice 5kg",
"hsnCode": "10063010",
"quantity": 5,
"unitPrice": 420.00,
"discountPercent": 2.00,
"gstRate": 5.00
},
{
"description": "Ghee 1L (Amul)",
"hsnCode": "04059090",
"quantity": 3,
"unitPrice": 560.00,
"gstRate": 12.00
}
]
}'
# Response (201 Created)
{
"success": true,
"message": "Invoice created successfully",
"data": {
"id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"invoiceNumber": "KTX/2026-27/0043",
"contactId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"customerName": "Sharma Kirana Store",
"invoiceDate": "2026-06-11",
"dueDate": "2026-07-11",
"status": "DRAFT",
"subtotal": 4558.00,
"taxAmount": 375.70,
"totalAmount": 4933.70,
"amountPaid": 0.00,
"balanceDue": 4933.70,
"placeOfSupply": "27",
"notes": "Delivery to Sharma Kirana Store, Pune",
"lines": [
{
"id": "11111111-1111-1111-1111-111111111111",
"lineNumber": 1,
"description": "Toor Dal 1kg",
"hsnCode": "07139090",
"itemId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"quantity": 10,
"unitPrice": 145.00,
"discountPercent": 0,
"discountAmount": 0.00,
"taxableAmount": 1450.00,
"gstRate": 5.00,
"taxAmount": 72.50,
"lineTotal": 1522.50
},
{
"id": "22222222-2222-2222-2222-222222222222",
"lineNumber": 2,
"description": "Basmati Rice 5kg",
"hsnCode": "10063010",
"itemId": "d4e5f6a7-b8c9-0123-def0-234567890123",
"quantity": 5,
"unitPrice": 420.00,
"discountPercent": 2.00,
"discountAmount": 42.00,
"taxableAmount": 2058.00,
"gstRate": 5.00,
"taxAmount": 102.90,
"lineTotal": 2160.90
},
{
"id": "33333333-3333-3333-3333-333333333333",
"lineNumber": 3,
"description": "Ghee 1L (Amul)",
"hsnCode": "04059090",
"itemId": null,
"quantity": 3,
"unitPrice": 560.00,
"discountPercent": 0,
"discountAmount": 0.00,
"taxableAmount": 1680.00,
"gstRate": 12.00,
"taxAmount": 201.60,
"lineTotal": 1881.60
}
],
"createdAt": "2026-06-11T05:30:00Z"
},
"errors": null
}Send an invoice
/api/v1/invoices/{id}/sendTransitions the invoice from DRAFT to SENT and delivers it to the customer via the configured channel (email, WhatsApp, etc).
Roles: OWNER, ADMIN, ACCOUNTANT, OPERATOR
curl -X POST https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/send \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response
{
"success": true,
"message": "Invoice sent successfully",
"data": null,
"errors": null
}Cancel an invoice
/api/v1/invoices/{id}/cancelCancels an invoice. This reverses inventory deductions and outstanding receivable entries. Cancelled invoices remain in the system for audit purposes but are excluded from GST filing data. A cancelled invoice cannot be un-cancelled — create a new invoice instead.
Roles: OWNER, ADMIN, ACCOUNTANT
curl -X POST https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/cancel \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response
{
"success": true,
"message": "Invoice cancelled successfully",
"data": null,
"errors": null
}Download PDF
/api/v1/invoices/{id}/pdfReturns the invoice as a PDF file. The response has Content-Type: application/pdf and the body is the raw PDF bytes. The PDF uses your organization's configured invoice template, logo, and bank details.
curl https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/pdf \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-o invoice_KTX_2026-27_0043.pdfPayments
Record, list, and delete payments against an invoice. When the total payments equal the invoice total, the invoice status automatically transitions to PAID.
Record a payment
/api/v1/invoices/{id}/paymentsInvoicePaymentRequest body
| Field | Type | Required | Description |
|---|---|---|---|
amount | BigDecimal | Yes | Amount received. |
paymentDate | LocalDate | Yes | Date of payment (YYYY-MM-DD). |
paymentMode | String | Yes | Payment method (e.g. UPI, NEFT, CASH, CHEQUE, CARD). |
reference | String | No | Transaction reference (UPI ref, cheque number, NEFT UTR, etc). |
paidThroughAccountId | UUID | No | Bank/cash account the payment was deposited into. |
curl -X POST https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/payments \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"amount": 2000.00,
"paymentDate": "2026-06-15",
"paymentMode": "UPI",
"reference": "426198374512",
"paidThroughAccountId": "a0b1c2d3-e4f5-6789-0abc-def012345678"
}'
# Response
{
"success": true,
"message": "Payment recorded successfully",
"data": {
"id": "f6a7b8c9-d0e1-2345-f012-456789012345",
"invoiceId": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"amount": 2000.00,
"paymentDate": "2026-06-15",
"paymentMode": "UPI",
"reference": "426198374512"
},
"errors": null
}List payments
/api/v1/invoices/{id}/paymentsReturns all payments recorded against the specified invoice.
curl https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/payments \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response
{
"success": true,
"message": "Payments retrieved successfully",
"data": [
{
"id": "f6a7b8c9-d0e1-2345-f012-456789012345",
"invoiceId": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"amount": 2000.00,
"paymentDate": "2026-06-15",
"paymentMode": "UPI",
"reference": "426198374512"
}
],
"errors": null
}Delete a payment
/api/v1/invoices/{id}/payments/{paymentId}Removes a payment record from the invoice. The invoice balance due is updated accordingly, and the status may revert from PAID back to SENT if the balance becomes non-zero.
curl -X DELETE https://api.katixo.com/api/v1/invoices/e5f6a7b8-c9d0-1234-ef01-345678901234/payments/f6a7b8c9-d0e1-2345-f012-456789012345 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# Response
{
"success": true,
"message": "Payment deleted successfully",
"data": null,
"errors": null
}Bulk operations
Bulk send
/api/v1/invoices/bulk-sendSend multiple draft invoices at once. The request body is a JSON array of invoice UUIDs.
curl -X POST https://api.katixo.com/api/v1/invoices/bulk-send \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '[
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"e5f6a7b8-c9d0-1234-ef01-345678901234",
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
]'
# Response
{
"success": true,
"message": "3 invoices sent successfully",
"data": null,
"errors": null
}Bulk cancel
/api/v1/invoices/bulk-cancelCancel multiple invoices at once. The request body is a JSON array of invoice UUIDs.
Roles: OWNER, ADMIN, ACCOUNTANT
curl -X POST https://api.katixo.com/api/v1/invoices/bulk-cancel \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '[
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
]'
# Response
{
"success": true,
"message": "2 invoices cancelled successfully",
"data": null,
"errors": null
}LineResponse object
Each invoice contains an array of line items. The server computes discount amounts, taxable amounts, tax, and line totals automatically from the inputs you provide.
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier for this line item. |
lineNumber | int | Position of the line item (1-based). |
description | String | Description of the item or service. |
hsnCode | String | HSN/SAC code for GST classification. |
itemId | UUID | Reference to item master (null for ad-hoc items). |
quantity | BigDecimal | Quantity of items. |
unitPrice | BigDecimal | Price per unit. |
discountPercent | BigDecimal | Discount percentage applied. |
discountAmount | BigDecimal | Computed discount amount (quantity x unitPrice x discountPercent / 100). |
taxableAmount | BigDecimal | Amount after discount, before tax. |
gstRate | BigDecimal | GST rate applied (e.g. 5.00, 12.00, 18.00). |
taxAmount | BigDecimal | Computed tax amount (taxableAmount x gstRate / 100). |
lineTotal | BigDecimal | Total for this line (taxableAmount + taxAmount). |
Error handling
All error responses follow the standard ApiResponse wrapper with success: false and details in the errors array.
# 400 Bad Request — validation error
{
"success": false,
"message": "Validation failed",
"data": null,
"errors": [
"contactId: must not be null",
"lines: must not be empty"
]
}
# 404 Not Found
{
"success": false,
"message": "Invoice not found",
"data": null,
"errors": ["No invoice found with id: e5f6a7b8-c9d0-1234-ef01-345678901234"]
}
# 403 Forbidden — insufficient role
{
"success": false,
"message": "Access denied",
"data": null,
"errors": ["You do not have permission to cancel invoices"]
}