Handling TDS
TDS — Tax Deducted at Source — is the tax you withhold from a supplier's payment and deposit with the government on their behalf. Three sections apply in our business today:
- 194C — contractor / works contract payments (most of our supplier bills — hotel services, transport, ground services).
- 194J — professional / technical fees (consultants, legal, accountants).
- 194Q — purchase of goods (only if FY aggregate with that supplier exceeds ₹50 lakh).
Payroll TDS (sections 192 / 24Q) is out of scope for the finance module — that belongs to payroll and uses slab-based calculations.
When TDS applies
Section 194C — contractor / works
| Deductee | Rate | Single-payment threshold | FY aggregate threshold |
|---|---|---|---|
| Individual / HUF | 1.0% | ₹30,000 | ₹1,00,000 |
| Company / firm | 2.0% | ₹30,000 | ₹1,00,000 |
Deduct when either the single payment is ≥ ₹30,000 or the FY aggregate with that supplier is ≥ ₹1,00,000. Below both: no deduction.
Section 194J — professional / technical
| Deductee | Rate | Single-payment threshold |
|---|---|---|
| Any | 10.0% | ₹30,000 |
Deduct when the single payment is ≥ ₹30,000. No aggregate threshold.
Section 194Q — purchase of goods
| Deductee | Rate | FY aggregate threshold |
|---|---|---|
| Any | 0.1% | ₹50,00,000 |
Deduct only on the portion above ₹50 lakh once FY aggregate with the supplier crosses that cap. Below: no deduction.
All thresholds and rates are exactly mirrored from the seed migration
supabase/migrations/20260418150000_tds_scaffolding.sql and the pure
calculator at src/lib/tds.ts — keep them in sync if anything changes.
The math (how the app decides)
The calculator at src/lib/tds.ts returns:
tdsAmount— what to withhold (rounded to paise).rateApplied— the rate used (0 when exempt).netAmount— what to actually pay the supplier (gross − TDS).grossAmount— the invoice amount you entered.belowThreshold—truewhen no deduction was required.reason— human-readable explanation if exempt.
Test your numbers
The test file at src/lib/tds.test.ts covers every threshold
edge case. If you're ever unsure about a scenario, find the
matching test case — it will tell you the expected answer.
Worked example — 194C, individual, ₹35,000
- Single payment ₹35,000 is above the ₹30,000 threshold → deduction triggered.
- Rate 1.0% → TDS = ₹350.
- Net payable to supplier = ₹34,650.
- You'd also need to deposit the ₹350 to the government within 7 days (or by the 7th of next month, whichever is sooner).
Worked example — 194Q, company, ₹10,00,000 with ₹49,00,000 YTD
- FY aggregate after this payment = ₹59,00,000, over the ₹50 lakh cap.
- Taxable portion = ₹59L − ₹50L = ₹9,00,000 (not the whole ₹10L — the first ₹50L is exempt in the FY).
- But of the current ₹10,00,000 payment, the taxable portion is
min(current, excess) = min(10_00_000, 9_00_000) = ₹9,00,000. - Rate 0.1% → TDS = ₹900.
- Net payable = ₹9,99,100.
How to apply TDS on a supplier payment
- Finance → Vouchers → Payment. Pick the supplier — section and
deductee type pre-populate from the supplier record
(
Supplier.tdsSection/deducteeType/panNumber). - Enter the gross invoice amount in Amount.
- Tick the Deduct TDS switch. You need the
finance.tds.deductpermission (CASHIER and above). - The form shows the live preview:
Gross ₹4,50,000 − TDS @ 1.0% (₹4,500) = Net payable ₹4,45,500. If the number is below threshold, the preview says so and the voucher falls back to the plain 2-line posting on submit. - Confirm and post.
- The app posts a 3-line journal
(DR Supplier / CR Bank net / CR 2401 TDS Payable) and writes the
matching
TDSDeductionrow — that row is what the quarterly 26Q CSV reads.
Missing PAN?
If the supplier record is missing a PAN, the voucher form will still let you post — but the 26Q return will fail RPU validation. Fix the PAN on the supplier master before posting.
Auto-computed year-to-date aggregate
The voucher sums the supplier's prior credit transactions in the
current session and threads that into calculateTds as the YTD
aggregate, so sections with aggregate thresholds (194C single-or-
aggregate, 194Q excess-over-₹50L) resolve correctly.
Challan management — depositing TDS to government
Every month (by the 7th of the following month), you deposit the TDS you withheld to the government via a challan (Form 281).
Procedure
- Log into the TRACES portal (https://www.tdscpc.gov.in/) or the income-tax e-filing portal.
- Generate Challan 281 for the total TDS payable — broken down by section (194C / 194J / 194Q).
- Pay via net banking.
- Note the CIN (Challan Identification Number) and deposit date.
Update our records
For each deduction the challan covers, issue
PATCH /finance/tds/deductions/:id with
{ challanNo, challanDate, status: 'deposited' }. The endpoint is
gated on finance.tds.deduct and is idempotent — replaying the same
patch returns the row unchanged and does not emit a second update.
curl -X PATCH /api/finance/tds/deductions/<id> \
-H 'content-type: application/json' \
-d '{"challanNo":"CIN-26040-0001","challanDate":"2026-05-07","status":"deposited"}'
A dedicated admin screen under Finance → Reports is listed as a follow-up in tds.md §7; until it ships, operators call the endpoint directly (or an IT-scripted bulk update covers the month's batch).
Record the challan payment in our books
- Finance → Vouchers → Payment (or Journal for flexibility).
- Debit
2401 TDS Payablefor the total challan amount — clears the liability. - Credit the bank account for the same amount.
- Memo:
TDS challan 281, April 2026, CIN <cin>, ₹X — sections 194C ₹a / 194J ₹b / 194Q ₹c. - Post and have approved.
Quarterly 26Q filing
Every quarter (by July 31 / Oct 31 / Jan 31 / May 31), you file Form 26Q with the government listing every deduction you made and which challan you paid it under.
Generate the 26Q CSV from our app
- Finance → Reports tab → TDS. (Permission:
finance.tds.export.) - Pick the quarter start and end dates.
- Click Export 26Q CSV.
- The app calls
GET /finance/tds/26q?fromDate=...&toDate=...and returns a CSV with 14 columns (see tds.md §4). - Save the file as
26Q-FY26-Q1-Apr-Jun.csv.
CSV columns
Serial No, Deductee PAN, Deductee Name, Section, Deductee Type,
Payment Date, Gross Amount, Rate (%), TDS Amount, Net Paid,
Challan No, Challan Date, Certificate No, Status
This is a review spreadsheet, not the final return
The 14 columns are the fields auditors typically check. The full 26Q return has more fields (BSR code, deposit sequence number, etc.) that you key into the TDS Return Preparation Utility (RPU) — a free desktop tool from the Protean (NSDL) site.
Prepare the RPU file
- Download the RPU from https://www.protean-tinpan.com/services/etds-etcs/etds-rpu.html.
- Open the RPU. Start a new 26Q return. Enter employer details.
- For each deduction in your CSV, key the line into the RPU's Annexure I deduction detail screen.
- For each challan paid this quarter, key into the RPU's Challan Details screen.
- Link each deduction to the right challan (the RPU has a matcher).
- Validate the return — the RPU runs shape checks and flags missing PANs / wrong rates / unmatched challans.
- Generate the
.fvufile.
Upload to TRACES
- Log into TRACES with your TAN credentials.
- Upload TDS Return → select Form 26Q → Quarter → Year.
- Upload the
.fvufile generated from RPU. - Sign with DSC and submit.
- Save the acknowledgement (a 15-digit RRR number).
Post-filing — certificates
Once the return is accepted and the deductees show up on TRACES:
- Download Form 16A certificates for each deductee (one PDF per deductee per quarter).
- Upload the PDF to our records. For each deduction, POST a
multipart form to
/finance/tds/deductions/:id/certificatewith the PDF (or scanned image — PNG/JPG/WEBP/GIF) as thefilefield, and optionally the TRACEScertificateNoin the same call. The endpoint stores the file in the Supabaselead-attachmentsbucket attds-certificates/<deductionId>/…, writes the URL back to the row, and flips status tocertificate_issued. Requiresfinance.tds.deduct.
curl -X POST /api/finance/tds/deductions/<id>/certificate \
-F 'file=@form16a-Q1-2026.pdf' \
-F 'certificateNo=CERT-Q1-001'
- Email the certificate link to each deductee / supplier. They need
it to claim the TDS credit on their own return.
Download is available via
GET /finance/tds/deductions/:id/certificate— returns{ certificateUrl, certificateNo, certificateUploadedAt, status }. The GET requiresfinance.tds.view, so suppliers with portal access (or any user on the finance side) can fetch it.
Your quarterly TDS checklist
- [ ] Every supplier payment this quarter that crossed threshold has
a matching
TDSDeductionrow. - [ ] Every TDSDeduction has a valid PAN (deductee PAN on the supplier record).
- [ ] Every deduction has a
challanNo+challanDate— none leftpending. - [ ]
2401 TDS Payableledger balance is zero after all challans recorded. - [ ] 26Q CSV exported from our app and reviewed.
- [ ] 26Q return filed via RPU → TRACES, RRR number saved.
- [ ] Form 16A certificates downloaded for every deductee.
- [ ] Certificates emailed to suppliers.
Permissions
| Permission | Who holds it | What it lets you do |
|---|---|---|
finance.tds.view |
CASHIER and above, AUDITOR | Read rate master + deduction ledger. |
finance.tds.deduct |
CASHIER and above | Apply TDS on a supplier payment. |
finance.tds.export |
ACCOUNTANT and above, AUDITOR | Export the quarterly 26Q CSV. |
Details: tds.md §6.
Common mistakes
- Missing PAN. The supplier's PAN must be on the
Supplierrecord before the deduction is posted. Without PAN, the return will fail at RPU validation and you'll scramble to collect PANs mid-filing. - Deducting TDS on GST. TDS is on the taxable value, not on the taxable + GST. A ₹1,00,000 invoice with 18% GST = ₹1,18,000 gross. TDS is on ₹1,00,000 not ₹1,18,000. The voucher form takes whichever number you enter as the gross — enter the pre-GST taxable amount when TDS applies.
- Section confusion. Travel DMCs → 194C (works contract). Consultants and lawyers → 194J. Procurement of goods → 194Q. If in doubt, check the supplier's SAC/HSN code against the section.
- Missing challan date/number. Means the deduction sits in
status
pendingforever. RPU validation will fail. - Claiming TDS credit in the wrong quarter. A deduction dated April goes in Q1 (Apr-Jun) 26Q, not Q4 of the previous year. Filter by payment date, not entry date.
See also
- tds.md — reference page: schema, endpoints, calculator internals.
- recording-transactions.md §1 — posting the underlying supplier invoice.
- month-end-close.md §Tax — where the TDS check fits into the close checklist.