Skip to content

Repository files navigation

hsn-code-package

Zero-dependency HSN/SAC code lookup and GST toolkit for India — search 12,000+ codes, look up GST rates, validate GSTIN/PAN, compute CGST/SGST/IGST, and export invoice data.

npm version node

🚀 Live Demo — See every feature in action, no setup needed.

What is this?

Try it live at hsn-gst-demo.karthi-21.com before installing.

hsn-code-package bundles the full CBIC/WCO Harmonized System Nomenclature (HSN) code list along with Service Accounting Codes (SAC) and a set of pure utility functions for GST work in India. It has no runtime dependencies — the data ships as JSON inside the package and everything runs on the Node.js standard library.

It provides:

  • HSN code lookup — search, validate, and browse 12,604 HSN codes by code or description.
  • GST rate data — chapter-level CGST/SGST/IGST rates derived from CBIC Notification 09/2025-CT(Rate).
  • GST calculation — rate-agnostic helpers for tax, reverse tax, invoice totals, and round-off.
  • GSTIN & PAN validation — format checks plus MOD-36 checksum verification and state decoding.
  • SAC codes — 496 service accounting codes with search.
  • Export utilities — CSV/JSON export and a GSTR-1 rate-wise summary.
  • CLIhsn command for lookups, validation, and export from the terminal.
  • TypeScript — complete type definitions bundled (no @types needed).

Installation

npm install hsn-code-package

Requires Node.js >= 14.

Quick start

const hsn = require('hsn-code-package');

// 1. Look up an HSN code
hsn.getHsnByExactCode('52010011');
// → { code: '52010011', description: 'COTTON, NOT CARDED OR COMBED ... BENGAL DESHI' }

// 2. Find its GST rate
hsn.getGstRateByCode('52010011');
// → { code: '52010011', igstRate: 5, cgstRate: 2.5, sgstRate: 2.5, cessRate: 0, ... }

// 3. Calculate GST on an amount
hsn.calculateGSTBreakdown(10000, 5, { isInterState: false });
// → { taxableAmount: 10000, cgst: 250, sgst: 250, igst: 0, cess: 0, totalTax: 500, grandTotal: 10500 }

// 4. Validate a GSTIN
hsn.validateGSTIN('27AAPFU0939F1ZV');
// → { isValid: true, stateCode: '27', stateName: 'Maharashtra', panNumber: 'AAPFU0939F', ... }

Table of contents


HSN code lookup

getAllHsn()

Returns every HSN code in the dataset.

hsn.getAllHsn();
// → [ { code: '1011010', description: '...' }, ... ]  (12,604 entries)

Bundled HSN, SAC, GST-rate, and metadata records are immutable. The canonical arrays returned by getAllHsn() and getAllSac() are also immutable and keep the same reference; clone an array or record before modifying it. Search result arrays may be reordered, but their records remain immutable.

getCodeByTxt(txt)

Case-insensitive partial search on the description.

hsn.getCodeByTxt('cotton');
// → [ { code: '12072010', description: '...COTTON SEEDS : OF SEED QUALITY' }, ... ]

getDesByCode(code)

Returns all entries whose code string contains the given value (partial match). Use getHsnByExactCode for a strict lookup.

hsn.getDesByCode('5201');
// → [ { code: '52010011', description: '...' }, { code: '52010012', ... }, ... ]

getHsnByExactCode(code)

Returns the single entry for an exact code, or undefined.

hsn.getHsnByExactCode('52010011');
// → { code: '52010011', description: 'COTTON, NOT CARDED OR COMBED ...' }

isValidHsnCode(code)

Returns true if the exact code exists.

hsn.isValidHsnCode('52010011'); // → true
hsn.isValidHsnCode('00000000'); // → false

getHsnChapter(chapter)

Returns all codes under a chapter (first two digits). Accepts '52', '5', or 52.

hsn.getHsnChapter('52'); // → all chapter-52 (cotton) codes

searchHsn(query, options)

Advanced description search with match type and pagination.

hsn.searchHsn('silk', { matchType: 'contains', limit: 10, offset: 0 });
Option Type Default Description
matchType 'contains' | 'startsWith' | 'exact' 'contains' How the description is matched.
limit number 0 Max results (0 = unlimited).
offset number 0 Results to skip (for pagination).

getStats()

Returns metadata about the bundled dataset.

hsn.getStats();
// → { version: '2.3.0', lastUpdated: '2026-06-02',
//     gstRatesLastUpdated: '2026-06-02', gstRateSource: 'chapter-level',
//     gstNotificationRef: 'Notification No. 09/2025-CT(Rate) dated 17 Sep 2025',
//     totalCodes: 12604, chapterCount: 86,
//     source: 'CBIC / WCO Harmonized System Nomenclature' }

getChapterSummary(chapter)

Returns a summary of a chapter, or null if none exist.

hsn.getChapterSummary('52');
// → { chapter: '52', totalCodes: 123, codeRange: { from: '...', to: '...' }, codes: [...] }

findCodesByDescription(keywords)

Returns codes whose description contains all of the given keywords (AND match).

hsn.findCodesByDescription(['cotton', 'carded']);
// → entries matching both terms

bulkValidateHsnCodes(codes)

Validates many codes at once.

hsn.bulkValidateHsnCodes(['52010011', '00000000']);
// → { valid: ['52010011'], invalid: ['00000000'],
//     summary: { total: 2, validCount: 1, invalidCount: 1 } }

GST rate data

Note: GST rates are chapter-level mappings derived from CBIC Notification No. 09/2025-CT(Rate) dated 17 Sep 2025, effective 2025-09-22. They are a best-effort classification at the chapter level — always confirm against the official notification for legal/billing use.

The bundled fallback was generated on 2026-06-02 and is labeled chapter-level. gstRatesLastUpdated records the date the bundled rate content materially changed; it is not a record of background source checks.

getGstRateByCode(code)

Returns GST rate details for an exact code, or null.

hsn.getGstRateByCode('52010011');
// → { code: '52010011', igstRate: 5, cgstRate: 2.5, sgstRate: 2.5, cessRate: 0,
//     rateSource: 'chapter-level', effectiveFrom: '2025-09-22',
//     notificationRef: 'Notification No. 09/2025-CT(Rate)' }

getHsnByExactCodeWithRate(code)

Returns the HSN entry merged with its GST rate, or undefined if the code does not exist.

hsn.getHsnByExactCodeWithRate('52010011');
// → { code: '52010011', description: '...', igstRate: 5, cgstRate: 2.5, ... }

getHsnByRateSlabs(igstRate)

Returns all HSN codes under a given IGST rate slab.

hsn.getHsnByRateSlabs(5); // → all codes taxed at 5% IGST

GST calculation utilities

These are pure, rate-agnostic helpers — you pass the rate in; they do not look it up. All monetary results are rounded to 2 decimals (half-up).

calculateTax(taxableAmount, rate)

hsn.calculateTax(10000, 18);
// → { taxableAmount: 10000, rate: 18, taxAmount: 1800, total: 11800 }

calculateGSTBreakdown(taxableAmount, gstRate, options)

Splits GST into CGST/SGST (intra-state) or IGST (inter-state), plus optional cess.

hsn.calculateGSTBreakdown(10000, 18, { isInterState: false });
// → { taxableAmount: 10000, cgst: 900, sgst: 900, igst: 0, cess: 0,
//     totalTax: 1800, grandTotal: 11800 }
Option Type Default Description
isInterState boolean false true → IGST, false → CGST+SGST.
cessRate number 0 Additional cess percentage.

reverseCalculateTax(grandTotal, rate)

Extracts the base amount and tax from a tax-inclusive total.

hsn.reverseCalculateTax(11800, 18);
// → { grandTotal: 11800, rate: 18, taxableAmount: 10000, taxAmount: 1800 }

getApplicableTaxType(supplierStateCode, placeOfSupplyStateCode)

Returns 'CGST_SGST' when the two state codes match, otherwise 'IGST'.

hsn.getApplicableTaxType('27', '27'); // → 'CGST_SGST'
hsn.getApplicableTaxType('27', '33'); // → 'IGST'

calculateInvoiceTotals(items, isInterState)

Aggregates a list of line items into invoice totals with round-off.

hsn.calculateInvoiceTotals(
  [{ taxableValue: 10000, gstRate: 18 }, { taxableValue: 5000, gstRate: 5 }],
  false
);
// → { totalTaxableValue, totalCGST, totalSGST, totalIGST, totalCess,
//     totalTax, grandTotal, roundOff }

Each item: { taxableValue: number, gstRate: number, cessRate?: number }.

groupItemsByTaxRate(items)

Groups line items by their GST rate (useful for GSTR-1 summaries).

hsn.groupItemsByTaxRate([{ taxableValue: 1000, gstRate: 18 }, { taxableValue: 500, gstRate: 5 }]);
// → { '18': [ {...} ], '5': [ {...} ] }

applyRoundOffRules(amount)

Rounds a monetary amount to 2 decimals using half-up rounding.

hsn.applyRoundOffRules(10.005); // → 10.01

GSTIN & PAN validation

validateGSTIN(gstin)

Validates format, state code, and MOD-36 checksum. Returns a result object.

hsn.validateGSTIN('27AAPFU0939F1ZV');
// → { isValid: true, stateCode: '27', stateName: 'Maharashtra',
//     panNumber: 'AAPFU0939F', entityNumber: '1', checkDigit: 'V' }

hsn.validateGSTIN('27AAPFU0939F1ZX');
// → { isValid: false, error: 'Invalid checksum: expected V, got X' }

formatGSTIN(gstin)

Trims and uppercases a GSTIN string.

hsn.formatGSTIN('27aapfu0939f1zv '); // → '27AAPFU0939F1ZV'

getStateFromGSTIN(gstin)

Returns the state name for a GSTIN's first two digits. Throws on unknown codes.

hsn.getStateFromGSTIN('27AAPFU0939F1ZV'); // → 'Maharashtra'

isValidPAN(pan)

Checks PAN format (AAAAA9999A).

hsn.isValidPAN('AAPFU0939F'); // → true

getGSTINComponents(gstin)

Decomposes a GSTIN into its parts (does not run the checksum).

hsn.getGSTINComponents('27AAPFU0939F1ZV');
// → { stateCode: '27', stateName: 'Maharashtra', pan: 'AAPFU0939F',
//     entityNumber: '1', checkDigit: 'V' }

SAC codes (services)

getAllSac()

Returns all 496 SAC entries.

hsn.getAllSac(); // → [ { code: '9954', description: 'Construction services' }, ... ]

getSacByCode(code)

Returns the single SAC entry for an exact code, or undefined.

hsn.getSacByCode('9954'); // → { code: '9954', description: 'Construction services' }

searchSac(query, options)

Description search with the same SearchOptions as searchHsn.

hsn.searchSac('construction', { matchType: 'contains', limit: 5 });

getCodeDetails(code)

Looks a code up in both HSN and SAC datasets and tags the result.

hsn.getCodeDetails('9954'); // → { code: '9954', description: '...', type: 'SAC' }
hsn.getCodeDetails('52010011'); // → { code: '52010011', description: '...', type: 'HSN' }

Export utilities

exportToCSV(data, options)

Converts an array of objects to CSV (with quoting/escaping).

hsn.exportToCSV(hsn.getCodeByTxt('cotton'));
// → "code,description\n12072010,..."
Option Type Default Description
delimiter string ',' Field delimiter.
headers string[] keys of the first row Explicit column order/selection.
preventFormulaInjection boolean true Prefix spreadsheet-like string cells with '.

Formula protection applies to string values and headers beginning with = or @, non-numeric strings beginning with + or - after optional whitespace, and strings beginning with a tab or carriage return. Signed decimal and scientific-notation strings such as -1234.50 and +1e3 remain unchanged. Disable protection only when legacy formula handling is required and the output will not be opened by spreadsheet software.

exportToJSON(data, options)

Serialises to JSON (pretty by default).

hsn.exportToJSON(hsn.getCodeByTxt('cotton'), { pretty: false });

generateGSTR1Summary(items)

Produces a rate-wise summary suitable for GSTR-1 reporting.

hsn.generateGSTR1Summary([{ taxableValue: 10000, gstRate: 18, isInterState: false }]);
// → [ { taxRate: 18, taxableValue: 10000, igst: 0, cgst: 900, sgst: 900,
//       cess: 0, totalTax: 1800, count: 1 } ]

Each item requires a non-negative finite taxableValue and either gstRate or the compatible igstRate field. cessRate defaults to 0, and isInterState defaults to false. When both rate fields are supplied, gstRate takes precedence. Malformed items, non-finite numbers, negative values, and a non-boolean isInterState throw an indexed field error instead of being included in the summary.


CLI

Installed as the hsn binary (use npx hsn if installed locally).

hsn search <query> [--limit N] [--type contains|startsWith|exact]
hsn validate <code>
hsn chapter <chapter>
hsn stats
hsn gstin <gstin>
hsn sac <query> [--limit N]
hsn export <query> [--format csv|json]
hsn help

Examples:

hsn search cotton --limit 3
hsn validate 52010011
hsn gstin 27AAPFU0939F1ZV
hsn export silk --format json

The validate and gstin commands exit with status 0 for a valid identifier and status 1 for an invalid identifier or usage error.


TypeScript

Type definitions are bundled — there is no separate @types package.

import { getHsnByExactCode, calculateGSTBreakdown, HsnCode, GSTBreakdown } from 'hsn-code-package';

const entry: HsnCode | undefined = getHsnByExactCode('52010011');
const tax: GSTBreakdown = calculateGSTBreakdown(10000, 18, { isInterState: false });

Exported interfaces include HsnCode, SearchOptions, HsnStats, GstRate, HsnCodeWithRate, GSTINValidationResult, GSTINComponents, SacCode, CodeDetails, TaxResult, GSTBreakdown, ReverseTaxResult, InvoiceLineItem, InvoiceTotals, GSTBreakdownOptions, ChapterSummary, and BulkValidationResult.


Data sources & update schedule

  • HSN/SAC codes: CBIC / WCO Harmonized System Nomenclature.
  • GST rates: CBIC Notification No. 09/2025-CT(Rate) dated 17 Sep 2025 (effective 2025-09-22), mapped at the chapter level.
  • The read-only update workflow checks weekly only when GST_RATE_SOURCE_URL is configured with an authoritative machine-readable workbook. Failed, unchanged, and changed checks do not modify repository data. After reviewing a reported difference, a maintainer can run node scripts/update-gst-rates.js --write locally and review the resulting diff before committing it. gstRatesLastUpdated advances only for that validated material update. A workbook must match at least 80% of its rows to bundled HSN codes. Metadata reports authoritative-excel only when every generated rate came from the workbook, and mixed when chapter-level fallbacks remain.
  • Workbook parsing is intentionally fail-closed. Every populated worksheet row must contain a recognized HSN-code field and GST-rate field; footer, note, or commentary rows abort the refresh and must be removed from the reviewed input before using --write.

Rates are provided as a developer convenience and classified at chapter granularity. For legal, billing, or filing purposes, verify against the official CBIC notification.

Migrating from v1 / v2.x

Migrating from v2.x to v3.0

Version 3.0 makes previously permissive behavior explicit and safe:

  • getAllHsn() and getAllSac() return stable, frozen arrays containing frozen records. Clone before modification: const editable = hsn.getAllHsn().map(row => ({ ...row })).
  • generateGSTR1Summary() now requires finite, non-negative numeric values and throws indexed errors for malformed entries. Normalize imported strings and supply taxableValue plus gstRate or igstRate before calling it.
  • exportToCSV() protects spreadsheet-formula strings by default. Legitimate signed numeric strings remain unchanged. Pass { preventFormulaInjection: false } only when preserving potentially executable spreadsheet input is intentional.
  • Invalid hsn validate and hsn gstin commands now exit with status 1.
  • TypeScript models canonical HSN/SAC/rate records and arrays as readonly. HsnStats now includes required GST-rate provenance fields.

See CHANGELOG.md for the complete release summary.

From Change
v1.x Package now exports a named-function API (e.g. getHsnByExactCode) instead of a default lookup object. HSN entries use { code, description }.
v2.0–v2.1 Added GST calculation utilities (calculateTax, calculateGSTBreakdown, …). No breaking changes to HSN lookup functions.
v2.2 Added GSTIN/PAN validation, SAC codes, export utilities, and the hsn CLI. No breaking changes.
v2.3 Added GST rate data (getGstRateByCode, getHsnByExactCodeWithRate, getHsnByRateSlabs) and advanced HSN lookups. No breaking changes.
v3.0 Hardened validation, exports, CLI statuses, immutable data, rate ingestion, and TypeScript contracts. See the migration notes above.

No function signatures or return shapes changed within the published 2.x line; the safety changes described above begin in 3.0.

Live demo

https://hsn-gst-demo.karthi-21.com/

An interactive showcase built on top of this package — try HSN lookups, GSTIN validation, GST calculations, SAC search, invoice generation, and CSV export right in the browser. No installation required.

Author

Built and maintained by Karthikeyan.

Contributing

Issues and pull requests are welcome at the GitHub repository.

npm install       # install dev dependencies
npm test          # run the test suite with coverage
npm run typecheck # type-check the bundled .d.ts against the smoke test

Please keep the package free of runtime dependencies and ensure npm test and npm run typecheck pass before opening a PR.

License

ISC

About

Zero-dependency HSN/SAC code lookup and GST toolkit for India — search 12,000+ codes, look up GST rates, validate GSTIN/PAN, compute CGST/SGST/IGST, and export invoice data.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages