API v1 stable

Public, read-only JSON API for India's open geo layers. No auth, no API key. All endpoints return JSON with CORS enabled.

Base URL: https://bharatlas.com/api/v1

Layers

GET /api/v1/layers

List all curated layers with pagination and filters.

ParamTypeDescription
categorystringFilter by category (e.g. boundaries, city-wards, environment)
levelstringFilter by admin level (e.g. state, district)
sourcestringFilter by data source (e.g. LGD, OpenCity)
qstringText search across id, source, notes
limitintResults per page (default 100, max 500)
offsetintSkip N results (default 0)
curl https://bharatlas.com/api/v1/layers?category=city-wards&limit=5

GET /api/v1/layers/:id

Single layer detail with download URLs, attribution, and column schema.

curl https://bharatlas.com/api/v1/layers/lgd_states

GET /api/v1/layers/:id/schema

Column names, types, and sample values. Reads parquet metadata from R2 at runtime. Use this to discover what columns a layer has before querying.

curl https://bharatlas.com/api/v1/layers/airports/schema

GET /api/v1/layers/:id/query

Query layer data with filters and grouping. Reads the parquet from R2 at runtime, no pre-computation needed. Works for curated and community layers.

ParamTypeDescription
selectstringComma-separated column names to return
wherestringFilters: col1=val1,col2=val2. Or pass columns directly as params: ?state=KA&type=INTERNATIONAL
group_bystringGroup by column, returns value counts
limitintMax rows (default 100, max 1000)
# How many airports in Bengaluru district?
curl "https://bharatlas.com/api/v1/layers/airports/query?where=district=Bengaluru Urban&select=name,type"

# How many reserve forests in Karnataka?
curl "https://bharatlas.com/api/v1/layers/soi_forests/query?where=State_LGD=29&group_by=type"

# National parks vs wildlife sanctuaries
curl "https://bharatlas.com/api/v1/layers/gs_wildlife/query?group_by=type"

# Which blocks are in district 571?
curl "https://bharatlas.com/api/v1/layers/lgd_blocks/query?where=Dist_LGD=571&select=BNAME,Block_LGD"

Columns with geometry data (geom, wkb_geometry) are excluded from results. For large layers, queries may take 1-5 seconds on first call (cached afterward).

Spatial

GET /api/v1/locate

Given a lat/lng, returns all polygon layers that contain that point: state, district, ward, pincode, forest, eco-zone, seismic zone, and more. The "where am I?" endpoint.

ParamTypeDescription
latfloat *Latitude (6 to 38, India bounding box)
lngfloat *Longitude (68 to 98, India bounding box)
layersstringComma-separated layer IDs (default: 12 essential layers)
zoomintTile resolution 4-16 (default 14, auto-capped to layer max zoom)
curl "https://bharatlas.com/api/v1/locate?lat=12.97&lng=77.59"

Response groups results by category:

{
  "point": { "lat": 12.97, "lng": 77.59 },
  "results": {
    "boundaries": [{
      "layer_id": "lgd_states",
      "level": "state",
      "feature": {
        "properties": { "STNAME": "KARNATAKA", "State_LGD": 29 }
      }
    }]
  },
  "queried_layers": ["lgd_states", "lgd_districts", ...],
  "timing_ms": 450
}

GET /api/v1/nearby

Find features from any layer near a point. Reads PMTiles tiles in a radius, extracts features with computed centroids, filters by Haversine distance. Works for points, polygons, and lines.

ParamTypeDescription
latfloat *Center latitude (6-38)
lngfloat *Center longitude (68-98)
layerstring *Layer ID to search
radius_kmfloatSearch radius in km (default 25, max 200)
limitintMax results (default 20, max 100)
# Reservoirs within 50km of Bengaluru
curl "https://bharatlas.com/api/v1/nearby?lat=12.97&lng=77.59&layer=wris_reservoirs&radius_km=50"

# Wildlife sanctuaries within 100km of Mysuru
curl "https://bharatlas.com/api/v1/nearby?lat=12.30&lng=76.65&layer=gs_wildlife&radius_km=100"

Categories and Levels

GET /api/v1/categories

List all categories with layer counts.

curl https://bharatlas.com/api/v1/categories

GET /api/v1/levels

List admin hierarchy levels in order (country, state, district, subdistrict, block, village, ...).

curl https://bharatlas.com/api/v1/levels

Counts and Stats

GET /api/v1/layers/:id/counts

Feature counts with optional column grouping. Without group_by, returns the total and lists all groupable columns. With group_by, returns value-level counts for that column.

ParamTypeDescription
group_bystringColumn name to group by (e.g. statename, wardname, zone)
# List groupable columns
curl https://bharatlas.com/api/v1/layers/soi_forests/counts

# Count forests per state
curl https://bharatlas.com/api/v1/layers/soi_forests/counts?group_by=statename

# Count wards per zone in PCMC
curl https://bharatlas.com/api/v1/layers/wards_pcmc/counts?group_by=zone

Columns with fewer than 200 distinct values are pre-computed and available for grouping. The column list is auto-detected from the parquet schema, no hardcoding.

Downloads

GET /api/v1/downloads/counts

Download counts per layer and format, plus a grand total.

curl https://bharatlas.com/api/v1/downloads/counts

Community Submissions

GET /api/v1/submissions

List accepted community submissions.

ParamTypeDescription
sortstringrecent (default) or useful
categorystringFilter by category
qstringSearch name and description
limitintResults per page (default 20, max 100)
offsetintSkip N results

GET /api/v1/submissions/:id

Single submission detail.

Response Format

All endpoints return JSON. List endpoints wrap results in:

{ "data": [...], "total": N, "limit": 100, "offset": 0 }

Detail endpoints wrap in:

{ "data": { ... } }

Errors return:

{ "error": "Not found", "status": 404 }

Rate Limits

EndpointLimit
All read endpoints120 requests/minute per IP
/locate, /nearby60 requests/minute per IP
Submissions (write)5/hour, 20/day per IP

Exceeded limits return 429 with a retry-after header. Cloudflare DDoS protection applies to all endpoints.

Versioning

All v1 endpoints follow additive-only evolution: new fields may appear, but existing fields will not be renamed or removed. If a breaking change is needed, it ships as v2. All responses include an x-api-version: v1 header.

Download Formats

Each layer may offer up to 5 formats. Use the downloads object from /api/v1/layers/:id to get direct URLs:

FormatBest for
parquetDuckDB, Pandas, R, Spark
pmtilesMapLibre, Leaflet, web maps
geojsonQGIS, D3, Mapbox, general GIS
kmlGoogle Earth
shapefileArcGIS, legacy GIS tools

Common questions

Do I need an API key to use the bharatlas API?

No. The API is public, read-only and CORS-enabled. No auth, no signup, no API key. Rate limit is 120 requests per minute per IP for most endpoints, 60/min for /locate and /nearby.

How do I list all geo layers via the API?

GET https://bharatlas.com/api/v1/layers returns every curated layer with pagination. Optional filters: ?category=, ?level=, ?source=, ?q= for full-text search.

How do I find what state or district a coordinate is in?

GET https://bharatlas.com/api/v1/locate?lat=12.97&lng=77.59 runs point-in-polygon across 12 admin and zone layers in a single call. Returns state, district, ward, pincode, seismic zone, eco-zone and more.

How do I find features near a point?

GET https://bharatlas.com/api/v1/nearby?lat=12.97&lng=77.59&layer=wris_reservoirs&radius_km=50 finds features from any layer within a radius. Works for points, polygons and lines via Haversine distance to computed centroids.

How do I query a layer with column filters?

GET https://bharatlas.com/api/v1/layers/:id/query?where=col=val&select=col1,col2&group_by=col. Reads parquet directly from R2 at runtime. Call /schema first to discover column names.

What download formats does bharatlas support?

Up to 5 formats per layer: parquet (DuckDB, Pandas, R, Spark), pmtiles (web maps), geojson (QGIS, D3), kml (Google Earth) and shapefile (ArcGIS). Use /api/v1/layers/:id to get direct download URLs.

How do I connect an LLM to the bharatlas API?

Use the bharatlas MCP server: add bharatlas-mcp to your MCP client config and run npx -y bharatlas-mcp. Connects Claude, GPT, Gemini or any MCP-compatible LLM with 8 tools and built-in instructions for spatial joins and schema-first querying.

For LLMs

Use the bharatlas MCP server (npx bharatlas-mcp) to connect Claude, GPT, Gemini, or any MCP-compatible LLM directly to this API. 8 tools with built-in instructions for schema-first querying, spatial joins, and multi-source awareness.