Integrating the India EV Charging Station API in Python and Node.js

Paging through results, reading the error envelope, honouring Retry-After on 429, and keeping the BEE attribution — with runnable Node.js and Python.

5 min read


## Overview The API is keyless and read-only. Every response is either { success: true, data, meta } or { success: false, error: { code, message, details } }, and every success carries meta.attribution, which you should keep wherever you show the data.

Node.js: page through a city ```javascript const BASE_URL = 'https://ev-charging-stations-api.vercel.app';

async function getJson(url) { for (let attempt = 0; attempt < 3; attempt += 1) { const response = await fetch(url); if (response.status === 429) { const wait = Number(response.headers.get('retry-after') || 60); await new Promise((resolve) => setTimeout(resolve, wait * 1000)); continue; } const body = await response.json(); if (!body.success) throw new Error(body.error.code + ': ' + body.error.message); return body; } throw new Error('rate limited three times'); }

async function allStations(query) { const out = []; for (let page = 1; ; page += 1) { const body = await getJson(BASE_URL + '/v1/stations?' + query + '&limit=100&page=' + page); out.push(...body.data); if (page >= body.meta.total_pages) return { stations: out, attribution: body.meta.attribution }; } }

const { stations, attribution } = await allStations('city=Kochi&vehicle=car'); console.log(stations.length + ' stations in Kochi with a gun a car can use'); console.log(attribution); ```

Python: fast DC chargers for cars near a point ```python import json import urllib.error import urllib.parse import urllib.request

BASE_URL = "https://ev-charging-stations-api.vercel.app"

params = urllib.parse.urlencode({ "lat": 28.6139, "lng": 77.2090, "radius": 10, "vehicle": "car", "current": "dc", "min_power_kw": 50, "limit": 5, }) try: with urllib.request.urlopen(f"{BASE_URL}/v1/stations/near?{params}") as response: body = json.load(response) except urllib.error.HTTPError as error: body = json.load(error) raise SystemExit(f"{error.code} {body['error']['code']}: {body['error']['message']}")

for station in body["data"]: print(f"{station['distance_km']} km {station['operator']} {station['max_power_kw']} kW {station['address']}") print(body["meta"]["attribution"]) ```

Errors are specific A misspelled parameter is `400 UNKNOWN_PARAMETER` with the accepted names in `error.details.allowed`; an unknown value such as `vehicle=truck` is `404 UNKNOWN_VEHICLE` with `error.details.valid_values`. Nothing is silently ignored, so an empty `data` array really means no match.