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

collect API (write) stable

collect is the write side: design a map form, collect points from contributors, and publish approved points into this catalog. It runs as a separate service with its own origin and auth, so it has its own section here rather than sitting under /api/v1 above.

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

Auth is a bearer token in the URL fragment of each share link (kept out of server logs); the field-definition contract is the public meta-schema at https://collect.bharatlas.com/schema/v1.json. Creating a map programmatically needs an API key (the anti-abuse gate) via the X-API-Key header, since there is no browser Turnstile.

MethodEndpointWhat
POST/collectionscreate a map (X-API-Key, or Turnstile in the browser); returns admin / collect / view links
GET/collections/:idmap metadata + counts
PATCH/collections/:idedit settings (admin)
POST/collections/:id/recordsadd one point (contributor)
GET/collections/:id/recordsrecords as GeoJSON, scoped by token
POST/collections/:id/importbulk import with a source + rights attestation (admin)
POST/records/:id/moderateapprove / reject one point (admin)
POST/collections/:id/publishsubmit approved points to the catalog for review (admin)
# 1. Create a map (needs an API key; body follows the meta-schema)
curl -X POST https://collect.bharatlas.com/api/collect/v1/collections \
  -H "X-API-Key: cak_..." -H "content-type: application/json" \
  -d '{ ...map definition per /schema/v1.json... }'
# returns admin / collect / view links; each link's token lives in its URL fragment

# 2. Review incoming points (admin token from the returned admin link)
curl https://collect.bharatlas.com/api/collect/v1/collections/ID/records \
  -H "authorization: Bearer adm_..."

# 3. Submit approved points to the catalog for review (admin token)
#    a maintainer approves the submission before it appears in the catalog
curl -X POST https://collect.bharatlas.com/api/collect/v1/collections/ID/publish \
  -H "authorization: Bearer adm_..."

Field contributors add points from the browser via the shared collect link (Turnstile-gated), so that step is a tap, not a curl. Or drive the whole flow from an LLM: the bharatlas MCP (npx bharatlas-mcp) authors collect maps too. Register a share link with register_map and its token scope (view / collect / admin) sets what you can do.

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 to query the catalog (schema-first querying, spatial joins) and, with a collect share link, to author your own maps.

How do I collect map data from the field with a shared form?

Use collect (collect.bharatlas.com), the write side. Design a small form, share a link, and anyone who has it adds points from their phone with no account. You review incoming points, then publish the approved ones to this catalog, where a curator approves the submission before it appears. API base: https://collect.bharatlas.com/api/collect/v1.

How do I manage or publish a collect map from an LLM?

Create the map online at collect.bharatlas.com (no account, no key), then use the bharatlas MCP (npx bharatlas-mcp): register_map with a share link. The link scope sets what you can do: view reads and exports published points, collect adds in the browser, admin can edit, moderate, import and publish. The link is the credential, so no API key is needed for maps you made online.

How do I create a collect map programmatically?

POST https://collect.bharatlas.com/api/collect/v1/collections with an X-API-Key header (the anti-abuse gate; the browser flow uses Turnstile instead). It returns admin, collect and view links whose tokens live in the URL fragment. Then GET /collections/:id/records to review and POST /collections/:id/publish to submit approved points to this catalog for review (a maintainer approves before it appears). Or from an LLM: the bharatlas MCP (npx bharatlas-mcp) authors collect maps too, register your share link with register_map then moderate and publish.

Where do published collect maps show up?

As community submissions, once a curator approves them. GET https://bharatlas.com/api/v1/submissions lists approved submissions, and the read MCP tool list_submissions surfaces them to an LLM. An approved collect map is queryable via /api/v1/layers/:id/query like any other layer.

For LLMs

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