Addy Geo API

Vietnam Administrative Geography, as an API

Provinces and wards (post-2025 reform) as shared master data. Read-only, cached, CORS-enabled. Drop in the script, call a function, done.

Base URL

Try it live

These controls call the real API from your browser right now.

// …

Quick start

<script src="__HOST__/sdk/addy-geo.js"></script>
<script>
  // base URL is auto-detected from the script's host
  AddyGeo.provinces().then(function (provinces) {
    console.log(provinces.length + " provinces");
  });

  AddyGeo.wards("1").then(function (wards) {
    console.log("Ha Noi wards:", wards);   // province 1 = Ha Noi
  });
</script>
import AddyGeo from "__HOST__/sdk/addy-geo.esm.js";
import { useEffect, useState } from "react";

AddyGeo.configure({ baseUrl: "__HOST__" });

export function ProvinceSelect() {
  const [provinces, setProvinces] = useState([]);
  useEffect(() => { AddyGeo.provinces().then(setProvinces); }, []);
  return (
    <select>
      {provinces.map((p) => (
        <option key={p.nationalCode} value={p.nationalCode}>{p.name}</option>
      ))}
    </select>
  );
}
// server component / route handler — fetch directly:
async function getProvinces() {
  const res = await fetch("__HOST__/api/v1/provinces", {
    next: { revalidate: 86400 }, // cache a day; data is near-static
  });
  const { data } = await res.json();
  return data;
}
// Download AddyGeoClient.java (below); needs Jackson on the classpath.
var geo = new AddyGeoClient("__HOST__");

List<AddyGeoClient.Region> provinces = geo.provinces();
List<AddyGeoClient.Region> wards = geo.wards("1");   // wards of Ha Noi
AddyGeoClient.Region baDinh = geo.ward("4");
System.out.println(baDinh.name() + " -> " + baDinh.parentName());
curl __HOST__/api/v1/provinces
curl __HOST__/api/v1/provinces/1/wards
curl __HOST__/api/v1/wards/4
curl "__HOST__/api/v1/regions/search?q=Ba%20%C4%90%C3%ACnh&level=LOCAL"
curl __HOST__/api/v1/export.csv -o vn-geo.csv

Endpoints

GET /api/v1/provincesAll provinces
GET /api/v1/provinces/{code}/wardsWards of a province
GET /api/v1/provinces/{code}/treeProvince + wards nested (bulk)
GET /api/v1/provinces/{n}Resolve a province by its number
GET /api/v1/wards/{n}Resolve a ward by its number (with parent)
GET /api/v1/regions/searchSearch by q, level, parent; paged
GET /api/v1/export · /export.csvFull dataset (JSON / CSV)

Codes are level-prefixed: P1 = province, W4 = ward. Every response is { success, message, data }.

Download the SDK

Full guides: Script tag · React · Next.js · Java · API (EN) · API (VN)

Prefer generating your own client? Point openapi-generator at /v3/api-docs.