API dan database wilayah administrasi pemerintahan Indonesia sesuai Kepmendagri No 300.2.2-2430 Tahun 2025.
Live preview: https://wilayah.indoplatform.id
- 4-level hierarchical data: Provinsi → Kabupaten/Kota → Kecamatan → Kelurahan/Desa
- 9 public REST API endpoints dengan caching 24 jam
- JSON response terstruktur dengan pagination
- Protected admin endpoints (IP whitelist + API key)
- Auto-sync dari 2 sumber resmi:
- cahyadsn/wilayah (GitHub, MIT License) — bulk SQL import
- wilayah.id — incremental REST API
- Admin dashboard dengan HTTP Basic Auth
- Auto-compress upload (max 3MB per file)
- SQLite-friendly syntax dengan PostgreSQL native types
- Framework: Next.js 14.2 App Router, TypeScript strict
- ORM: Prisma 5.22 + PostgreSQL 17
- Auth: HTTP Basic Auth + bcrypt + jwt (jose)
- UI: Tailwind 3 + Radix UI + lucide-react
- Cache: in-memory + HTTP
Cache-Control: public, max-age=86400
pnpm install
pnpm db:push # Buat schema di DB lokal
pnpm db:seed # Opsional: import data dari SQL
pnpm dev # http://localhost:3010Copy .env.example → .env:
DATABASE_URL="postgresql://postgres@localhost:5432/wilayah?schema=public"
NEXTAUTH_SECRET="<generate-random-32-byte>"
NEXTAUTH_URL="http://localhost:3010"
WILAYAH_ID_API_BASE="https://wilayah.id/api"
NEXT_PUBLIC_INTERNAL_API_KEY="<generate-random>"
WILAYAH_INTERNAL_API_KEY="<generate-random>"
SESSION_SECRET="<generate-random>"Generate secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Semua endpoint return JSON dengan struktur { data, meta, pagination }.
GET /api/v1/provinsi → list 38 provinsi Indonesia
GET /api/v1/provinsi/{kode} → detail provinsi + list kabupaten (kode 2 digit BPS)
GET /api/v1/kabupaten?provinsi={kode} → list kabupaten/kota per provinsi
GET /api/v1/kabupaten/{kode} → detail kabupaten + list kecamatan (kode 4 digit)
GET /api/v1/kecamatan?kabupaten={kode} → list kecamatan per kabupaten
GET /api/v1/kecamatan/{kode} → detail kecamatan + list kelurahan (kode 6 digit)
GET /api/v1/kelurahan?kecamatan={kode} → list kelurahan per kecamatan
GET /api/v1/kelurahan/{kode} → detail kelurahan (kode 10 digit)
GET /api/v1/search?q={keyword} → search cross-level (min 2 karakter)
Response shape:
{
"data": [...],
"meta": { "total": 38, "page": 1, "pageSize": 50, "level": 1 },
"pagination": { "page": 1, "pageSize": 50, "totalPages": 1, "hasNext": false, "hasPrev": false }
}Headers:
Cache-Control: public, max-age=86400, stale-while-revalidate=3600(24h cache)ETaguntuk conditional GET
POST /api/admin/sync → trigger sync (body: { source: "CAHYADSN_SQL" | "WILAYAH_ID_API", trigger: "MANUAL" | "SCHEDULED" | "INITIAL" })
GET /api/admin/sync/log → last 20 sync runs
GET /api/admin/stats → table counts
GET /api/admin/whitelist → list IP whitelist
POST /api/admin/whitelist → add IP (body: { ipAddress, label })
DELETE /api/admin/whitelist?id={id} → remove IP
Public API endpoints (/api/v1/*) dilindungi IP whitelist. Default allow:
127.0.0.1,::1,localhost- IP yang ada di tabel
ip_whitelist
Admin IP whitelist dimanage via dashboard /admin atau API di atas.
Path: /admin
Login dengan HTTP Basic Auth (user disimpan di tabel User dengan role: "ADMIN").
Fitur:
- Stats total records (5 model utama)
- Sinkronisasi data (Sync dari SQL / Refresh dari wilayah.id API)
- Riwayat sinkronisasi (auto-refresh 5 detik)
- IP Whitelist manager (CRUD)
- Dari SQL (cahyadsn/wilayah): Download JSON dari GitHub, bulk upsert via Prisma.
- Dari wilayah.id API: Incremental fetch per parent code, cek
updated_at.
# 1. Buat DB di Postgres
psql -U postgres -c "CREATE DATABASE wilayah;"
# 2. Push schema
pnpm db:push
# 3. Sync data (via UI atau API)
curl -X POST https://wilayah.indoplatform.id/api/admin/sync \
-H "Content-Type: application/json" \
-H "X-Internal-Api-Key: YOUR_KEY" \
-d '{"source": "WILAYAH_ID_API", "trigger": "INITIAL"}'
# 4. Setup systemd service (lihat scripts/deploy/)- cahyadsn/wilayah (GitHub, MIT License) — database SQL
- wilayah.id — API publik untuk incremental refresh
5 model utama (prisma/schema.prisma):
model Provinsi {
id Int @id // BPS 2-digit code
kode String @unique @db.VarChar(4)
nama String
kabupaten Kabupaten[]
}
model Kabupaten {
id Int @id // 4-digit code
kode String @unique @db.VarChar(6)
provinsiId Int
nama String
jenis String // "KABUPATEN" | "KOTA"
kecamatan Kecamatan[]
}
model Kecamatan {
id Int @id // 6-digit code
kode String @unique @db.VarChar(8)
kabupatenId Int
nama String
kelurahan Kelurahan[]
}
model Kelurahan {
id Int @id // 10-digit code
kode String @unique @db.VarChar(13)
kecamatanId Int
nama String
}
// Infrastructure
model SyncLog { ... } // sync history
model IpWhitelist { ... } // IP whitelist rulesMIT — Data licensed under Kepmendagri No 300.2.2-2430 Tahun 2025 (public domain).