Developer documentation
TDS Compliance API
REST API for TDS calculation, reasoning storage, and audit trail management. Built for Income Tax Act 2025, effective 1 April 2026.
Overview
The RegInfra API is organized around REST. It accepts JSON request bodies, returns JSON responses, and uses standard HTTP status codes. The API processes one vendor payment per request and returns a complete TDS decision with the full reasoning chain attached.
Every response includes the applicable section, rate, deduction amount, threshold state at payment time, and a plain-English justification suitable for statutory audit documentation. Decisions are stored permanently and queryable at any time.
Test vs live mode
The API key you use determines the mode. Test mode keys have the prefix tds_test_ and do not create compliance records or affect your live vendor data. Live keys have the prefix tds_live_.
Authentication
All requests must include your API key in the x-api-key header. Requests without a valid key return 401 authentication_error.
x-api-key: tds_live_your_key_here
Content-Type: application/json
Requesting access
During beta, API keys are provisioned manually. Request a free trial at reginfra.com/#trial or email contact@reginfra.com. You will receive a test key within 24 hours on business days.
Base URL & versioning
The current API version is v1. The version is specified in the URL path.
Breaking changes are never made to an existing version. When CBDT issues a circular — rates and thresholds update automatically on the effective date. Your integration keeps working without any changes.
Deprecation notices are issued a minimum of 6 months in advance.
Idempotency
The API supports idempotency for safely retrying requests without processing the same vendor payment twice. Include a unique Idempotency-Key header with every request.
Idempotency-Key: INV-2026-001-v1
Key format
Use your invoice number, transaction reference, or a UUID. Keys must be under 255 characters and are retained for 24 hours.
// Good — use meaningful identifiers
Idempotency-Key: INV-2026-001
Idempotency-Key: TXN-Q1-2026-042
Idempotency-Key: VENDOR_001_2026-04-18_50000
// Bad — too generic, risk of collision
Idempotency-Key: 12345
409 idempotency_conflict error. Always use a new key for a new unique transaction.
Core endpoint — compute TDS
This is the primary endpoint. Call it at the moment of vendor payment. It returns the correct TDS decision with the complete reasoning chain and stores the decision permanently.
Replace {section} with the section identifier — e.g. 194C, 194J, 194A.
Sample request — 194J professional services
POST https://api.reginfra.com/v1/tds/194J/compute
Content-Type: application/json
x-api-key: tds_live_your_key_here
Idempotency-Key: INV-2026-001
{
"transaction_id": "INV-2026-001",
"pan": "ABCDE1234F",
"vendor_name": "ABC Consulting Pvt Ltd",
"deductee_type": "Company",
"residential_status": "Resident",
"pan_status": "Available",
"is_206ab_applicable": false,
"is_pan_operative": true,
"nature_of_payment": "professional_fees",
"service_type": "Professional_Services",
"credit_amount": 75000,
"aggregate_amount_ytd": null,
"credit_datetime": "2026-04-18T10:00:00"
}
{
"section": "194J",
"tds_rate": "0.10",
"tds_amount": "7500.00",
"currency": "INR",
"computed_at": "2026-04-18T10:32:39+00:00",
"legal_reference": {
"act": "Income-tax Act, 2025",
"section": "393 Table 1 S.No.(6)(iii)",
"section_title": "Fees for professional or technical services",
"effective_from": "2026-04-01"
},
"calculation_reasoning": {
"threshold_check": "₹75,000 exceeds threshold ₹50,000 — TDS applicable",
"rate_selection": "10% — PAN available, Professional_Services",
"aggregate_impact": "YTD after this payment: ₹75,000"
},
"meta": {
"rule_id": "r_ac29066e",
"rule_version": "1.0.0"
},
"warnings": []
}
Request fields
Required fields
| Field | Type | Description |
|---|---|---|
| transaction_id | string | Your unique transaction reference. Used for idempotency and audit queries. |
| pan | string | 10-character PAN of the vendor/deductee. |
| deductee_type | string | Entity classification. See accepted values. |
| residential_status | string | Resident or Non-Resident. Non-resident blocks with Section 195 guidance. |
| pan_status | string | Available or Not_Available. Determines higher deduction rate. |
| is_pan_operative | boolean | Whether PAN is operative on payment date. Inoperative PAN triggers higher rate. |
| nature_of_payment | string | Payment classification. Must match the section called. See accepted values. |
| credit_amount | number | Payment amount in INR. Used for threshold checking and TDS calculation. |
| credit_datetime | string | ISO 8601 datetime of the payment. Used to determine FY and threshold position. |
Optional fields
| Field | Type | Description |
|---|---|---|
| vendor_name | string | Stored in the audit record for human-readable querying. |
| aggregate_amount_ytd | number / null | Caller-supplied YTD. If null, RegInfra computes from stored records. If supplied and differs from computed, DB value wins and a warning is returned. |
| is_206ab_applicable | boolean | Override for 206AB applicability. Defaults to false. |
| service_type | string | Required for 194J to distinguish professional vs technical fees rate. |
Response fields
| Field | Description |
|---|---|
| section | TDS section applied (e.g. 194J). |
| tds_rate | Rate as decimal (e.g. 0.10 for 10%). |
| tds_amount | TDS amount in INR to 2 decimal places. |
| legal_reference.act | Full name of the applicable Act. |
| legal_reference.section | Exact 393-series section reference from ITA 2025. |
| calculation_reasoning | Plain-English explanation of every decision made. Threshold check, rate selection, PAN status. Suitable for audit documentation. |
| meta.rule_id | Unique identifier of the rule set used. Stored with the transaction. |
| meta.rule_version | Semantic version of the rule file. Cryptographic fingerprint of which Finance Act rates were active. |
| warnings | Array of non-blocking advisory messages. E.g. YTD mismatch between caller-supplied and computed values. |
GET /transactions
Query stored TDS decisions. Returns all decisions matching the filter criteria. Query stored decisions for any vendor, date range, or section. Use for audit documentation, reconciliation, or historical reporting.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| vendor_pan | string | Filter by vendor PAN. Returns all decisions for this vendor. |
| section | string | Filter by TDS section (e.g. 194C). |
| from_date | string | ISO date. Start of date range. |
| to_date | string | ISO date. End of date range. |
| transaction_id | string | Retrieve a single specific decision. |
GET /v1/tds/transactions?vendor_pan=ABCDE1234F&from_date=2026-04-01&to_date=2026-06-30
GET /health
Returns API status. Use for monitoring and uptime checks.
{ "status": "ok", "version": "1.0.0" }
TDS sections covered
| Section | Description | Threshold |
|---|---|---|
| 194A | Interest other than on securities | ₹40,000 / ₹50,000 (banks) |
| 194B | Winnings from lottery / crossword puzzle | ₹10,000 |
| 194BA | Winnings from online gaming | Net winnings per FY |
| 194BB | Winnings from horse race | ₹10,000 |
| 194C | Payments to contractors | ₹30,000 single / ₹1,00,000 aggregate |
| 194D | Insurance commission | ₹15,000 |
| 194DA | Payment on life insurance policy | ₹1,00,000 |
| 194G | Commission on lottery tickets | ₹15,000 |
| 194H | Commission or brokerage | ₹15,000 |
| 194I | Rent — land/building/furniture | ₹2,40,000 |
| 194J | Professional / technical fees | ₹50,000 |
| 194M | Payment by individual/HUF for contract/professional | ₹50,00,000 |
| 194N | Cash withdrawal | ₹1,00,00,000 |
| 194O | E-commerce operator payments | ₹5,00,000 |
| 194Q | Purchase of goods | ₹50,00,000 |
| 194R | Benefit or perquisite to business/profession | ₹20,000 |
| 194S | Transfer of virtual digital assets | ₹50,000 / ₹10,000 |
| 194T | Payment to partners | ₹20,000 |
Section mismatch detection
If you call POST /v1/tds/194C/compute but the nature_of_payment field indicates professional fees, RegInfra returns a 400 section_mismatch error before any deduction is calculated. The error includes the correct section to use.
{
"error": "section_mismatch",
"message": "nature_of_payment 'professional_fees' is not valid under 194C",
"correct_section": "194J",
"correct_endpoint": "/v1/tds/194J/compute"
}
Error codes
| HTTP | Error code | Meaning |
|---|---|---|
| 400 | section_mismatch | Payment type does not match the section called. Response includes correct section. |
| 400 | invalid_pan | PAN format invalid or failed validation. |
| 400 | missing_field | A required field is absent from the request. |
| 400 | non_resident_blocked | Non-resident vendor — use Section 195 with Form 15CA/15CB. RegInfra does not process non-resident payments. |
| 401 | authentication_error | API key missing, invalid, or revoked. |
| 409 | idempotency_conflict | Same Idempotency-Key used with different request payload. |
| 422 | validation_error | Field values are present but fail validation rules. |
| 429 | rate_limit_exceeded | Too many requests. See rate limits. |
| 500 | internal_error | Server error. Payment is never blocked — fallback mode returns a safe response. |
Rate limits
| Plan | Monthly calls | Rate limit |
|---|---|---|
| Free trial | 500 | 100 req/min |
| Starter | 5,000 | 100 req/min |
| Growth | 25,000 | 100 req/min |
| Scale | 1,00,000 | 100 req/min |
| Enterprise | Custom | Custom |
Rate limit headers are returned with every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Upcoming endpoints
- POST /v1/tds/validate — Pre-payment validation without storing a decision. Check section and rate before committing.
- GET /v1/tds/ytd/{pan} — Current YTD aggregate for a vendor PAN across all sections.
- GET /v1/tds/export/26Q — Export quarterly 26Q filing data in NSDL format.