Quick start

  1. Ask for a key. Write to hello@cmstechnosolutions.com with the name of your product, what it does with the data, and a contact address. We make the key and send it to you. It is shown once, so store it safely.
  2. Keep it on your server. Put it in an environment variable. Never in a web page or mobile app that others can open.
    export CHARGELK_KEY=clk_YOUR_KEY
  3. Make a request. The nearest chargers within 10 km of Colombo Fort:
    curl "https://chargelk.com/api/v1/stations?near=6.9271,79.8612&radius_km=10" \
      -H "Authorization: Bearer $CHARGELK_KEY"

The API is read only. It returns chargers, never customers or owners.

Authentication

Send your key with every request, in the Authorization header:

Authorization: Bearer clk_YOUR_KEY

X-Api-Key: clk_YOUR_KEY works too. Base address: https://chargelk.com/api/v1. Everything is JSON, over HTTPS.

GET /stations

List stations with their chargers

A station is a site with one or more chargers. Give "near" to get the closest first, each with distance_km.

Parameters

NameTypeWhat it does
nearquery string A point as "lat,lng", for example 6.9271,79.8612. Returns stations within radius_km, nearest first.
radius_kmquery number Used with near. Default 25.
cityquery string Only stations in this city, spelled as in the data.
statusquery string Only chargers with this status. Stations with no matching charger are left out. availableoccupiedofflinefaultedmaintenance
connectorquery string Only chargers with this connector. CCS2CHAdeMOGBTType2
pagequery integer default 1 Which page of results. 1 is the first.
per_pagequery integer default 100 How many stations on a page, up to 200.

Example request

curl "https://chargelk.com/api/v1/stations?near=6.9271,79.8612&radius_km=10" \
  -H "Authorization: Bearer $CHARGELK_KEY"
const res = await fetch("https://chargelk.com/api/v1/stations?near=6.9271,79.8612&radius_km=10", {
  headers: { Authorization: `Bearer ${process.env.CHARGELK_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).message);
const { data, meta } = await res.json();
console.log(data);
import os, requests

res = requests.get(
    "https://chargelk.com/api/v1/stations?near=6.9271,79.8612&radius_km=10",
    headers={"Authorization": "Bearer " + os.environ["CHARGELK_KEY"]},
    timeout=10,
)
res.raise_for_status()
print(res.json()["data"])
<?php
$ch = curl_init("https://chargelk.com/api/v1/stations?near=6.9271,79.8612&radius_km=10");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("CHARGELK_KEY")],
]);
$body = json_decode(curl_exec($ch), true);
print_r($body["data"]);

Example response 200 OK

{
  "data": [
    {
      "id": 12,
      "name": "Galle Face Car Park",
      "address": "1 Galle Road, Colombo 3",
      "city": "Colombo",
      "location": {
        "lat": 6.9271,
        "lng": 79.8438
      },
      "opening_hours": "Daily 06:00 to 22:00",
      "amenities": [
        "seating",
        "washrooms",
        "wifi"
      ],
      "distance_km": 1.4,
      "chargers": [
        {
          "id": "CP-001",
          "status": "available",
          "status_checked_at": "2026-11-02T09:14:52+00:00",
          "connector": {
            "type": "CCS2",
            "current": "DC",
            "count": 1
          },
          "power_kw": 30,
          "price": {
            "currency": "LKR",
            "per_kwh": {
              "lkr": 100,
              "cents": 10000
            },
            "idle_fee_per_minute": {
              "lkr": 0,
              "cents": 0
            },
            "tax_included": true
          },
          "planned_outage": null
        }
      ]
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "per_page": 100,
    "generated_at": "2026-11-02T09:15:01+00:00"
  }
}

Errors this can return

401422429

GET /stations/{id}

One station

Parameters

NameTypeWhat it does
id requiredpath integer

Example request

curl "https://chargelk.com/api/v1/stations/12" \
  -H "Authorization: Bearer $CHARGELK_KEY"
const res = await fetch("https://chargelk.com/api/v1/stations/12", {
  headers: { Authorization: `Bearer ${process.env.CHARGELK_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).message);
const { data, meta } = await res.json();
console.log(data);
import os, requests

res = requests.get(
    "https://chargelk.com/api/v1/stations/12",
    headers={"Authorization": "Bearer " + os.environ["CHARGELK_KEY"]},
    timeout=10,
)
res.raise_for_status()
print(res.json()["data"])
<?php
$ch = curl_init("https://chargelk.com/api/v1/stations/12");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("CHARGELK_KEY")],
]);
$body = json_decode(curl_exec($ch), true);
print_r($body["data"]);

Example response 200 OK

{
  "data": {
    "id": 12,
    "name": "Galle Face Car Park",
    "address": "1 Galle Road, Colombo 3",
    "city": "Colombo",
    "location": {
      "lat": 6.9271,
      "lng": 79.8438
    },
    "opening_hours": "Daily 06:00 to 22:00",
    "amenities": [
      "seating",
      "washrooms",
      "wifi"
    ],
    "chargers": [
      {
        "id": "CP-001",
        "status": "available",
        "status_checked_at": "2026-11-02T09:14:52+00:00",
        "connector": {
          "type": "CCS2",
          "current": "DC",
          "count": 1
        },
        "power_kw": 30,
        "price": {
          "currency": "LKR",
          "per_kwh": {
            "lkr": 100,
            "cents": 10000
          },
          "idle_fee_per_minute": {
            "lkr": 0,
            "cents": 0
          },
          "tax_included": true
        },
        "planned_outage": null
      }
    ]
  },
  "meta": {
    "generated_at": "2026-11-02T09:15:01+00:00"
  }
}

Errors this can return

401404429

GET /chargers/{id}

One charger by its id

Parameters

NameTypeWhat it does
id requiredpath string The charger id, for example CP-001.

Example request

curl "https://chargelk.com/api/v1/chargers/CP-001" \
  -H "Authorization: Bearer $CHARGELK_KEY"
const res = await fetch("https://chargelk.com/api/v1/chargers/CP-001", {
  headers: { Authorization: `Bearer ${process.env.CHARGELK_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).message);
const { data, meta } = await res.json();
console.log(data);
import os, requests

res = requests.get(
    "https://chargelk.com/api/v1/chargers/CP-001",
    headers={"Authorization": "Bearer " + os.environ["CHARGELK_KEY"]},
    timeout=10,
)
res.raise_for_status()
print(res.json()["data"])
<?php
$ch = curl_init("https://chargelk.com/api/v1/chargers/CP-001");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("CHARGELK_KEY")],
]);
$body = json_decode(curl_exec($ch), true);
print_r($body["data"]);

Example response 200 OK

{
  "data": {
    "id": "CP-001",
    "status": "available",
    "status_checked_at": "2026-11-02T09:14:52+00:00",
    "connector": {
      "type": "CCS2",
      "current": "DC",
      "count": 1
    },
    "power_kw": 30,
    "price": {
      "currency": "LKR",
      "per_kwh": {
        "lkr": 100,
        "cents": 10000
      },
      "idle_fee_per_minute": {
        "lkr": 0,
        "cents": 0
      },
      "tax_included": true
    },
    "planned_outage": null,
    "station_id": 12
  },
  "meta": {
    "generated_at": "2026-11-02T09:15:01+00:00"
  }
}

Errors this can return

401404429

What the fields mean

Charger status

ValueMeaning
availableOnline and free: plug in and start.
occupiedOnline and charging, or a vehicle is plugged in.
offlineNot connected to ChargeLK right now (no contact for 10 minutes).
faultedThe charger reports a fault and is being repaired.
maintenanceUnder announced planned maintenance. See planned_outage for when it is back.

status_checked_at is when the charger last spoke to us. It is a live reading, not a forecast: a charger that is free now may be taken a minute later.

Connector and power

connector.type is CCS2, CHAdeMO, GBT (GB/T) or Type2. connector.current is AC (Type 2) or DC (fast). power_kw is the most the charger can deliver.

Price

Prices are in Sri Lankan rupees and include any tax. per_kwh is what a driver pays for each kWh the charger's meter counts. idle_fee_per_minute is zero unless the charger bills for staying plugged in after charging. Each price is given as lkr (rupees, with decimals) and cents (whole cents, for exact arithmetic). The price a driver pays is fixed when they press Start.

Facilities

amenities lists what the site offers:

  • seating Seating
  • washrooms Washrooms
  • food Food and drink
  • wifi Wi-Fi
  • shelter Covered parking
  • security Security (CCTV or guard)
  • accessible Step-free access

Planned maintenance

planned_outage is null, or an object with starts_at, ends_at and active for maintenance within the next 14 days or happening now. While it is active the status is maintenance.

Times

All times are ISO 8601 with an offset, such as 2026-11-02T09:14:52+00:00.

Limits and errors

Each key may make 60 requests a minute unless we agreed another figure. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining.

401The key is missing, wrong, expired or revoked.
{
  "message": "An API key is required. Send it as \"Authorization: Bearer <key>\".",
  "code": "missing_api_key"
}
404No such station or charger, or it is not in service.
{
  "message": "Not Found."
}
422A parameter is not valid. "errors" says which.
{
  "message": "The status field must be one of available, occupied, offline, faulted, maintenance.",
  "errors": {
    "status": [
      "The selected status is invalid."
    ]
  }
}
429This key used up its requests for the minute. Wait for the next one.
{
  "message": "Too many requests for this API key. Wait a minute and try again.",
  "code": "rate_limited"
}

Errors always carry a message you can show or log. Test code in your software, not the message wording.

Good practice

  • Ask for what you need. Use near and radius_km, or city, instead of fetching every station on each request.
  • Do not poll faster than you need. Status is updated as each charger reports it, usually within seconds. Once every 30 seconds for an area is plenty for a map, and asking faster only uses up your allowance.
  • Show how old the reading is. Use status_checked_at, and treat offline as unknown, not as broken.
  • Use cents for sums and lkr for display.
  • Keep the key on your server. If it leaks, tell us and we will revoke it and make a new one.
  • Ignore fields you do not know. Version 1 only ever gains new, optional fields.

Versions and support

Version 1 only gets new, optional fields. A change that could break your software would be a version 2, announced to every key holder first, with the old version kept running for a stated time.

The full machine-readable description (OpenAPI 3.0) can be read here, or fetched by your tools from /api/v1/openapi.json. Import it into Postman, Insomnia or Swagger UI, or generate a client from it.

Questions, a higher limit, or a problem with a key: hello@cmstechnosolutions.com.

Chat on WhatsApp