Skip to content
Thursday, 7 May 2026 — Jakarta Issue №127


Developer Notes

Public API.

In brief: Streetside Jakarta exposes a small read-only JSON API at /api/cameras returning the full active camera catalogue with id, name, neighbourhood, coordinates, and HLS stream URL per entry. The endpoint is edge-cached behind Cloudflare and intended for hobby projects, research, and civic mapping. No authentication is required; attribution to Streetside Jakarta and DKI Jakarta is requested.


The same JSON the Streetside front-end consumes is yours to consume too. There is no API key, no signup, no quota dashboard, no OAuth dance — just two endpoints that return the camera catalogue and per-camera detail. The data is edge-cached for sixty seconds at our Cloudflare boundary, so even an inefficient client will not meaningfully tax the upstream. Two requests, please: rate-limit yourself to roughly one request per second, and if you publish anything built on this data, attribute back to Streetside Jakarta with a link. That is the entire contract. Build a dashboard, a Telegram bot, a research notebook, a screensaver — whatever pleases you. The endpoints are documented below in the order you will probably need them.


GET /api/cameras

Request

GET /api/cameras
Accept: application/json

Returns the full active camera catalogue as a JSON array under the cameras key. Cameras without coordinates and disabled cameras are filtered out at the edge before you ever see them. Field shapes mirror the upstream Molecool API verbatim, with the exception of latitude and longitude which may arrive as either numbers or numeric strings — coerce defensively.

Response shape

{
  "cameras": [
    {
      "id": 1234,
      "cctv_name": "Bundaran HI",
      "city_name": "Jakarta Pusat",
      "district_name": "Menteng",
      "subdistrict_name": "Gondangdia",
      "latitude": -6.1944,
      "longitude": 106.8229,
      "address": "Jl. M.H. Thamrin, Bundaran HI"
    }
  ]
}

The response carries Cache-Control: public, max-age=60 and an X-Cache header of either KV-HIT or MISS. The catalogue refresh cadence is sixty seconds; polling more often than that will simply hit the same cached payload.


GET /api/cameras/[id]

Request

GET /api/cameras/1234
Accept: application/json

Returns the detail record for a single camera, including the live HLS playlist URL and the most recent still image. The id URL parameter is a string in the path but corresponds to the numeric id field from the list endpoint. Unknown ids return 404; upstream failures return 502.

Response shape

{
  "camera": {
    "id": 1234,
    "cctv_name": "Bundaran HI",
    "city_name": "Jakarta Pusat",
    "district_name": "Menteng",
    "subdistrict_name": "Gondangdia",
    "latitude": -6.1944,
    "longitude": 106.8229,
    "address": "Jl. M.H. Thamrin, Bundaran HI",
    "image1": "https://.../snapshot.jpg",
    "hls": "https://.../stream.m3u8",
    "description": "Traffic camera at Bundaran HI roundabout."
  }
}

Detail responses are also cached for sixty seconds at the edge. Note that image1 is a short-lived signed URL from the upstream — typically valid for about an hour — so do not bookmark it. The hls URL points at our /stream/[...path] proxy and stays valid as long as the camera remains in the index.


Terms

  • Free for non-commercial use. Commercial use requires a quick email first.
  • Attribute as "Streetside Jakarta" with a link back to streetside.mugnimaestra.dev.
  • Don't hammer the endpoints — at least one second between requests is plenty, and the catalogue itself only changes every sixty seconds.
  • Underlying CCTV feeds are sourced from the DKI Jakarta provincial government. See data sources for the full provenance, refresh cadence, and licence.