India API
Free, open source APIs for Indian data. Pincodes, IFSC and bank branches, GSTIN and PAN checks, bank and market holidays, RTO codes, company logos, UPI QR codes, numbers in lakh and crore, GST invoices as PDF, OCR in Indian languages, PDF and image tools, translation, speech to text and text to speech, and more: 44 APIs behind one consistent JSON shape. No API key, no sign-up, open CORS, and an MCP server so AI assistants can use it too.
Documentation: api.dharun.dev · API reference · Guides · Use with AI · OpenAPI · llms.txt
curl https://api.dharun.dev/v1/pincode/637001
{
"data": { "pincode": "637001", "district": "Namakkal", "stateCode": "TN", "state": "Tamil Nadu", "offices": [ ... ] },
"meta": { "source": { "name": "...", "licence": "...", "attribution": "..." } }
}
APIs
Each name links to its page, with every parameter, a real response and code in curl, JavaScript and Python.
One shape everywhere
- Every JSON response is
{ "data": ..., "meta": { ... } }.datais an object, or an array for list endpoints, which addmeta.total,meta.limitandmeta.offset. meta.sourcenames the dataset, its version, its licence and the credit it asks for.- Errors are
{ "error": { "code", "message" } }with a matching HTTP status. - Each client has an allowance of 600 requests a minute. A lookup costs 1; a request that takes real CPU work (image rendering, astronomy, live DNS) costs 10, a file upload 15, and a neural network job (speech, speech to text, translation, background removal, denoise) 30. Embeddings, reranking and moderation count as CPU work.
- Text endpoints take
?text=, or a POST body astext/plainor JSON{"text": "..."}. - Image endpoints return the image itself, ready for an
<img>tag; PDF and audio endpoints return the file. - File endpoints take a POST of the file as the body, or as
multipart/form-data, up to 10 MB. Files are deleted when the answer is sent; nothing is kept.
Use it from AI assistants
One MCP server, one Agent Skill and one Claude Code plugin cover every API.
# Claude Code: the MCP server
claude mcp add --transport http india-api https://api.dharun.dev/mcp
# Claude Code: the plugin (skill and MCP server together)
/plugin marketplace add dharunashokkumar/api.dharun.dev
/plugin install india-api@dharun-dev
# Any agent that reads Agent Skills (Claude Code, Codex, Copilot, Cursor, Gemini CLI)
npx skills add dharunashokkumar/api.dharun.dev
- MCP server:
https://api.dharun.dev/mcp, Streamable HTTP, stateless, no authentication. Each tool returns exactly what the matching REST endpoint returns. Setup for Claude, ChatGPT, VS Code, Cursor, Windsurf, Gemini CLI and Codex: api.dharun.dev/ai. In the MCP Registry asio.github.dharunashokkumar/india-api. - Agent Skill:
skills/india-api. - Claude Code plugin:
plugins/india-api, with the marketplace in.claude-plugin/marketplace.json. - For crawlers and agents:
/llms.txt,/llms-full.txt, every page as Markdown (add.mdor sendAccept: text/markdown),/openapi.json, an MCP server card, an AI catalog and an API catalog under/.well-known/.
The skill, the plugin and server.json are generated from the catalog in
internal/api/catalog.go; a test fails when the committed copies are out of date.
Licence
- Calling the API puts no licence on your app.
- The code is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only). If you run a modified copy as a service for others, you must offer them your changes.
- Code examples, the guides' code, the Agent Skill and the Claude Code plugin are MIT-0: use them anywhere, no credit needed.
- Data keeps the licence of its source (below); every response repeats the credit.
- Third-party code and fonts compiled into the server keep their licences, such as the
SGP4 code in
internal/orbit(BSD-2-Clause) and the Noto fonts (OFL-1.1). The release bundle'sNOTICESlists every one. - Company logos are trademarks of their owners.
Security and privacy
Report vulnerabilities privately: see SECURITY.md. Client IP addresses are never logged, and endpoints that take personal values never log their input; the full list is at api.dharun.dev/privacy. Each release carries a build provenance attestation:
gh attestation verify dharun-api-linux-amd64.tar.gz --repo dharunashokkumar/api.dharun.dev
Contributing
Bug reports, corrections to data and requests for new APIs are welcome as issues. Pull requests are not accepted; see CONTRIBUTING.md.
Data sources
Exact versions, retrieval dates and checksums are in data/sources.json
(the models: pinned by revision and checksum in internal/dataset/aimodels.go), and every
response repeats the credit in meta.source. Models published only as PyTorch weights or in
full precision were converted to ONNX and int8 by tools/models/convert.py
and attached to the models-2026-10 release.
Known gaps:
- State government holidays are not included. Bank holidays are per state, and they come from each state's own notification.
- Andaman and Nicobar RTO codes are missing: the source article has no section for them.
- The pincode file was fetched through a mirror because the government portal refuses scripted downloads. Its size matches the file the portal lists.
- Railway stations come from a community list: some stations are missing and a few codes are out of date.
- Assembly constituency boundaries pre-date the latest redrawing in six states; the response says so where it applies.
- Phone operator and circle are the original allocation of a number series. A ported number keeps its series, so the current operator can differ.
- Panchang timings are computed from Sun and Moon positions and can differ from a printed almanac by a minute or so.
- Tamil legacy encodings: TSCII only so far; TAB, TAM and Bamini are planned.
- Hindi and Tamil number words follow standard written forms, with Tamil compound numbers written as separate words. Corrections are welcome.
Run it locally
Requires Go 1.26 or newer.
go run ./cmd/apidata build -resvg none # build every dataset from data/ into seed/
go run ./cmd/api # http://127.0.0.1:8080/
go test ./...
PNG output (logos and generated images) is rendered by
resvg; bash tools/fetch-resvg.sh <dir> downloads
the pinned Linux build. Without it everything else works and PNG requests answer 501.
Configuration is by environment variable; see
deploy/dharun-api.env.example.
ROADMAP.md tracks what is built, what is planned and what was turned down.
Repository layout
cmd/api the server
cmd/apidata data tool: build, import, refresh, status
internal/api routing, endpoints, the website, MCP, metrics
internal/api/guides the guides, in Markdown
internal/api/templates the Markdown forms of the pages and the skill
internal/dataset one file per dataset: how it is built, fetched and checked
internal/typeset text shaping and the fonts for generated images
internal/panchang almanac calculations
internal/translit transliteration between scripts
internal/tamilfont Tamil 8-bit encodings
internal/textkit chunking, redaction, token counts, language detection
internal/fake test data
internal/words number to words
internal/validate GSTIN, PAN, IFSC and checksum rules
internal/india states and their codes
data/ one folder per dataset (logos included), and sources.json
skills/ the Agent Skill (generated from the catalog)
plugins/ the Claude Code plugin (generated); marketplace in .claude-plugin/
server.json the MCP Registry entry (generated)
deploy/ systemd units, installer, self-updater, monitoring
tools/ release build, smoke test, install test, resvg download, logo scraper
How data stays fresh
Each dataset is its own read-only SQLite file. A release carries a seed copy of every
dataset, built from data/. On a server, apidata refresh runs hourly as a separate
short-lived job: each dataset that a program can fetch (IFSC, RTO codes, bank and market
holidays, HSN, mutual fund NAV, airports, stations, IP addresses, disposable domains) is
downloaded when it is due, checked, and built into a new file in the server's own data
directory. The API serves whichever copy is newer and picks up a new file without a
restart. A deploy replaces the seeds and never touches the server's own copies.
Datasets that cannot be fetched by a program are updated by hand and ship with a push:
go run ./cmd/apidata import pincode -file pincode.csv # CSV saved from data.gov.in
python tools/scrape_logos.py --dry-run # logos: see new, renamed and delisted companies
python tools/scrape_logos.py # then download and write them
go run ./cmd/apidata status # which copy of each dataset is in use
Central government holidays are typed into data/holidays/central/<year>.json from the
yearly memorandum, usually published in July for the following year.
Release and deploy
Deployment is pull-based: the server fetches releases, nothing connects in to it.
- Every push to
mainruns CI: tests, shell lint, a full release build, a smoke test of the bundle against the full datasets, and an install of it on a fresh Debian 13. - When it passes, the bundle is published as release
v1.1.<run number>. - On the server,
dharun-api-update.timerchecks every 2 minutes. It downloads the new release, verifies the checksum, switches to it, and checks/healthz. If the new version does not come up, it switches back and marks that release as failed. - When CI has finished, the
Productionworkflow waits (up to 20 minutes) for the public/healthzto report the new version, then runs the smoke test's route checks against the live site. A release that was never installed, or was rolled back, fails the run. The run shows on GitHub as a deployment toproduction.
First-time setup on a Debian 12 or 13 machine or container, as root:
tar -C deploy -cz . | ssh <host> 'mkdir -p /root/api-deploy && tar -xz -C /root/api-deploy && sh /root/api-deploy/install.sh'
The server is one static binary plus a database file per dataset. It runs as the
unprivileged user dharun-api with a read-only filesystem, and uses about 35 MB of
memory idle and about 150 MB under a burst. The updater
runs as root and is only replaced by re-running install.sh. Restrict port 8080 to your
proxy and port 9464 to Prometheus with a firewall.
Monitoring
:9464/metricsserves Prometheus metrics: requests by API and status, response times, logo lookups, memory,api_lifetime_requests_total, and for each dataset which copy is in use, how old it is and whether its last refresh worked.:9464/statsserves the all-time totals as JSON. They are saved to disk and survive restarts.deploy/monitoring/has the Prometheus scrape job, alert rules (API down, a refresh that keeps failing, stale data) and a Grafana dashboard.- Every request is one JSON line on stdout: route, status, duration, what was looked up, country and user agent. Client IP addresses are not logged, and format checks log nothing about the value checked.
Trademark notice
Company logos and trademarks belong to their respective owners. This project is an index for discovery and convenience; review each company's brand rules before production use. To request removal of a logo, open an issue.