Refnusa API reference

Indonesian reference data API

Public holidays, minimum wages, region and postal codes, income tax tables, prayer times, and NIK and plate checks for Indonesia, over REST and MCP. Every record names the regulation it comes from and the date that regulation took effect.

Connect from Claude Code
claude mcp add --transport http refnusa https://refnusa.dev/mcp
Base URL
https://refnusa.dev
GET /v1/holidays/2026-08-17
{
  "date": "2026-08-17",
  "is_holiday": true,
  "name": "Proklamasi Kemerdekaan",
  "type": "libur_nasional",
  "source_instrument": "Keputusan Bersama Menteri Agama, Menteri Ketenagakerjaan, dan Menteri Pendayagunaan Aparatur Negara dan Reformasi Birokrasi Republik Indonesia Nomor 1497 Tahun 2025, Nomor 2 Tahun 2025, dan Nomor 5 Tahun 2025 tentang Hari Libur Nasional dan Cuti Bersama Tahun 2026",
  "effective_date": "2025-09-19",
  "source_url": "https://www.kemenkopmk.go.id/sites/default/files/pengumuman/2025-09/SKB%20Libur%20Nasional%20dan%20Cuti%20Bersama%20Tahun%202026.pdf"
}

Datasets

Coverage of this build. A dataset that is not loaded yet answers with a plain 404 that says so, never with a guessed figure.

DatasetSourceCoverageStatus

Public holidays and cuti bersama

holidays
SKB 3 Menteri, one decree per year; each row names its own
Full source

SKB 3 Menteri, one decree per year; each row names its own

Complete
Loaded

Provincial minimum wage (UMP)

wages_ump
Keputusan Gubernur per province; each row names its own
Full source

Keputusan Gubernur per province; each row names its own

27 of 38 provinces
Partial

Regency and city minimum wage (UMK), starter set

wages_umk
Keputusan Gubernur per regency/city; each row names its own
Full source

Keputusan Gubernur per regency/city; each row names its own

9 of 10 kabupaten/kota
Partial

Administrative region codes, province to kelurahan

wilayah
Kepmendagri No 300.2.2-2138 Tahun 2025 as stated in the header of cahyadsn/wilayah db/wilayah.sql (the repository README cites No 300.2.2-2430 Tahun 2025), commit 55a496d, MIT
Full source

Kepmendagri No 300.2.2-2138 Tahun 2025 as stated in the header of cahyadsn/wilayah db/wilayah.sql (the repository README cites No 300.2.2-2430 Tahun 2025), commit 55a496d, MIT

Complete
Loaded

Postal codes per kelurahan and desa

postal_codes
cahyadsn/wilayah_kodepos json/wilayah_kodepos.json, commit ba84971, MIT
Full source

cahyadsn/wilayah_kodepos json/wilayah_kodepos.json, commit ba84971, MIT

Complete
Loaded

PPh 21 effective average rates (TER)

tax_pph21_ter
Peraturan Pemerintah Nomor 58 Tahun 2023 tentang Tarif Pemotongan Pajak Penghasilan Pasal 21 atas Penghasilan Sehubungan dengan Pekerjaan, Jasa, atau Kegiatan Wajib Pajak Orang Pribadi, Lampiran huruf A, B, dan C (Tarif Efektif Bulanan)
Full source

Peraturan Pemerintah Nomor 58 Tahun 2023 tentang Tarif Pemotongan Pajak Penghasilan Pasal 21 atas Penghasilan Sehubungan dengan Pekerjaan, Jasa, atau Kegiatan Wajib Pajak Orang Pribadi, Lampiran huruf A, B, dan C (Tarif Efektif Bulanan)

Complete
Loaded

Non-taxable income (PTKP)

tax_ptkp
Peraturan Menteri Keuangan Nomor 101/PMK.010/2016 tentang Penyesuaian Besarnya Penghasilan Tidak Kena Pajak
Full source

Peraturan Menteri Keuangan Nomor 101/PMK.010/2016 tentang Penyesuaian Besarnya Penghasilan Tidak Kena Pajak

Complete
Loaded

Prayer times, computed

prayer_times
Subuh at 20 degrees as stated by the Dirjen Bimas Islam, Kementerian Agama (kemenag.go.id, 2020-12-21). Isya at 18 degrees, Ashar at shadow ratio 1 and ihtiyat 2 minutes are labelled estimates commonly published for Indonesia. Checked against the Bimas Islam jadwal shalat for Kota Jakarta: within 1 minute on six dates in February and March 2026.
Full source

Subuh at 20 degrees as stated by the Dirjen Bimas Islam, Kementerian Agama (kemenag.go.id, 2020-12-21). Isya at 18 degrees, Ashar at shadow ratio 1 and ihtiyat 2 minutes are labelled estimates commonly published for Indonesia. Checked against the Bimas Islam jadwal shalat for Kota Jakarta: within 1 minute on six dates in February and March 2026.

Complete
Loaded

Vehicle plate prefixes

plate_prefixes
Peraturan Kepolisian Negara Republik Indonesia Nomor 7 Tahun 2021 tentang Registrasi dan Identifikasi Kendaraan Bermotor, Lampiran huruf A (Penentuan kode wilayah berdasarkan wilayah Regident Ranmor)
Full source

Peraturan Kepolisian Negara Republik Indonesia Nomor 7 Tahun 2021 tentang Registrasi dan Identifikasi Kendaraan Bermotor, Lampiran huruf A (Penentuan kode wilayah berdasarkan wilayah Regident Ranmor)

Complete
Loaded

REST reference

Responses are JSON and need no key. Each client may send 60 requests a minute; past that the API answers 429, see Limits and errors.

GET /v1/datasets

Coverage of every dataset: status, row count, source instrument, effective date.

No parameters.

cURL
curl "https://refnusa.dev/v1/datasets"
JavaScript
await fetch("https://refnusa.dev/v1/datasets").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/datasets").json()
200 OK
{
  "datasets": [
    {
      "dataset": "holidays",
      "status": "loaded",
      "row_count": 51,
      "source_instrument": "SKB 3 Menteri, one decree per year; each row names its own",
      "effective_date": "2026-09-15",
      "note": "Years loaded: 2026, 2027."
    },
    {
      "dataset": "wages_ump",
      "status": "partial",
      "row_count": 27,
      "source_instrument": "Keputusan Gubernur per province; each row names its own",
      "effective_date": "2026-01-01",
      "note": "27 of 38 provinces for 2026; not yet sourced: 13, 15, 61, 71, 75, 76, 81, 82, 93, 95, 96."
    },
    {
      "dataset": "wages_umk",
      "status": "partial",
      "row_count": 9,
      "source_instrument": "Keputusan Gubernur per regency/city; each row names its own",
      "effective_date": "2026-01-01",
      "note": "Starter set: Kota Medan, Kabupaten Bogor, Kabupaten Karawang, Kabupaten Bekasi, Kota Bandung, Kota Bekasi, Kota Depok, Kota Semarang, Kota Surabaya. Ten large industrial regencies and cities; the full national UMK set is out of scope for version 1."
    },
    // 6 more
  ]
}

GET /v1/holidays

Public holidays (libur nasional) and joint leave days (cuti bersama) for one year, from that year's SKB 3 Menteri decree.

NameTypeRequiredDescription
yearintegerRequiredCalendar year, for example 2026
cURL
curl "https://refnusa.dev/v1/holidays?year=2026"
JavaScript
await fetch("https://refnusa.dev/v1/holidays?year=2026").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/holidays", params={"year":2026}).json()
200 OK
{
  "year": 2026,
  "source_url": "https://www.kemenkopmk.go.id/sites/default/files/pengumuman/2025-09/SKB%20Libur%20Nasional%20dan%20Cuti%20Bersama%20Tahun%202026.pdf",
  "holidays": [
    {
      "date": "2026-01-01",
      "name": "Tahun Baru 2026 Masehi",
      "type": "libur_nasional",
      "source_instrument": "Keputusan Bersama Menteri Agama, Menteri Ketenagakerjaan, dan Menteri Pendayagunaan Aparatur Negara dan Reformasi Birokrasi Republik Indonesia Nomor 1497 Tahun 2025, Nomor 2 Tahun 2025, dan Nomor 5 Tahun 2025 tentang Hari Libur Nasional dan Cuti Bersama Tahun 2026",
      "effective_date": "2025-09-19"
    },
    {
      "date": "2026-01-16",
      "name": "Isra Mikraj Nabi Muhammad S.A.W.",
      "type": "libur_nasional",
      "source_instrument": "Keputusan Bersama Menteri Agama, Menteri Ketenagakerjaan, dan Menteri Pendayagunaan Aparatur Negara dan Reformasi Birokrasi Republik Indonesia Nomor 1497 Tahun 2025, Nomor 2 Tahun 2025, dan Nomor 5 Tahun 2025 tentang Hari Libur Nasional dan Cuti Bersama Tahun 2026",
      "effective_date": "2025-09-19"
    },
    {
      "date": "2026-02-16",
      "name": "Tahun Baru Imlek 2577 Kongzili",
      "type": "cuti_bersama",
      "source_instrument": "Keputusan Bersama Menteri Agama, Menteri Ketenagakerjaan, dan Menteri Pendayagunaan Aparatur Negara dan Reformasi Birokrasi Republik Indonesia Nomor 1497 Tahun 2025, Nomor 2 Tahun 2025, dan Nomor 5 Tahun 2025 tentang Hari Libur Nasional dan Cuti Bersama Tahun 2026",
      "effective_date": "2025-09-19"
    },
    // 22 more
  ]
}

GET /v1/holidays/:date

Whether one date is a public holiday or cuti bersama, with the decree it was checked against. Weekends count only when the decree names them.

NameTypeRequiredDescription
datedateRequiredDate in YYYY-MM-DD form
cURL
curl "https://refnusa.dev/v1/holidays/2026-08-17"
JavaScript
await fetch("https://refnusa.dev/v1/holidays/2026-08-17").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/holidays/2026-08-17").json()
200 OK
{
  "date": "2026-08-17",
  "is_holiday": true,
  "name": "Proklamasi Kemerdekaan",
  "type": "libur_nasional",
  "source_instrument": "Keputusan Bersama Menteri Agama, Menteri Ketenagakerjaan, dan Menteri Pendayagunaan Aparatur Negara dan Reformasi Birokrasi Republik Indonesia Nomor 1497 Tahun 2025, Nomor 2 Tahun 2025, dan Nomor 5 Tahun 2025 tentang Hari Libur Nasional dan Cuti Bersama Tahun 2026",
  "effective_date": "2025-09-19",
  "source_url": "https://www.kemenkopmk.go.id/sites/default/files/pengumuman/2025-09/SKB%20Libur%20Nasional%20dan%20Cuti%20Bersama%20Tahun%202026.pdf"
}

GET /v1/wages/ump

Provincial minimum wage (UMP) for one year, all provinces or one province, with the governor decree behind each figure.

NameTypeRequiredDescription
yearintegerRequiredCalendar year, for example 2026
province_codestringOptionalKemendagri province code, optional (two digits like 31)
cURL
curl "https://refnusa.dev/v1/wages/ump?year=2026&province_code=31"
JavaScript
await fetch("https://refnusa.dev/v1/wages/ump?year=2026&province_code=31").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/wages/ump", params={"year":2026,"province_code":"31"}).json()
200 OK
{
  "year": 2026,
  "ump": [
    {
      "province_code": "31",
      "province_name": "DKI Jakarta",
      "amount_idr": 5729876,
      "source_instrument": "Keputusan Gubernur Nomor 1142 Tahun 2025 tentang Upah Minimum Provinsi Tahun 2026",
      "effective_date": "2026-01-01",
      "source_url": "https://jdih.jakarta.go.id/dokumen/detail/14763"
    }
  ]
}

GET /v1/wages/umk

Regency or city minimum wage (UMK) for one year, starter set of the largest regencies only.

NameTypeRequiredDescription
yearintegerRequiredCalendar year, for example 2026
regency_codestringRequiredKemendagri kabupaten/kota code (like 32.73)
cURL
curl "https://refnusa.dev/v1/wages/umk?year=2026&regency_code=32.73"
JavaScript
await fetch("https://refnusa.dev/v1/wages/umk?year=2026&regency_code=32.73").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/wages/umk", params={"year":2026,"regency_code":"32.73"}).json()
200 OK
{
  "year": 2026,
  "umk": [
    {
      "regency_code": "32.73",
      "regency_name": "Kota Bandung",
      "province_code": "32",
      "amount_idr": 4737678,
      "source_instrument": "Keputusan Gubernur Jawa Barat Nomor 561.7/Kep.862-Kesra/2025 tentang Upah Minimum Kabupaten/Kota Tahun 2026",
      "effective_date": "2026-01-01",
      "source_url": "https://jdih.jabarprov.go.id/page/eksekusi_download/32/2025kg00320862.pdf"
    }
  ]
}

GET /v1/wilayah

Administrative regions: the 38 provinces, the children of one parent code, or one region by code.

NameTypeRequiredDescription
levelstringOptionalLevel to list; anything below provinsi needs parent_code
parent_codestringOptionalList the children of this code (2, 5, 8 or 13 characters like 31, 31.71, 31.71.01, 31.71.01.1001)
codestringOptionalReturn this one region (2, 5, 8 or 13 characters like 31, 31.71, 31.71.01, 31.71.01.1001)
cURL
curl "https://refnusa.dev/v1/wilayah?parent_code=31"
JavaScript
await fetch("https://refnusa.dev/v1/wilayah?parent_code=31").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/wilayah", params={"parent_code":"31"}).json()
200 OK
{
  "items": [
    {
      "code": "31.01",
      "name": "Kabupaten Administrasi Kepulauan Seribu",
      "level": "kabupaten",
      "parent_code": "31",
      "latitude": -5.746481,
      "longitude": 106.61316,
      "elevation_m": 8,
      "utc_offset": 7
    },
    {
      "code": "31.71",
      "name": "Kota Administrasi Jakarta Pusat",
      "level": "kabupaten",
      "parent_code": "31",
      "latitude": -6.172913,
      "longitude": 106.818696,
      "elevation_m": 5,
      "utc_offset": 7
    },
    {
      "code": "31.72",
      "name": "Kota Administrasi Jakarta Utara ",
      "level": "kabupaten",
      "parent_code": "31",
      "latitude": -6.120028,
      "longitude": 106.892495,
      "elevation_m": 6,
      "utc_offset": 7
    },
    // 3 more
  ],
  "source_instrument": "Kepmendagri No 300.2.2-2138 Tahun 2025 as stated in the header of cahyadsn/wilayah db/wilayah.sql (the repository README cites No 300.2.2-2430 Tahun 2025), commit 55a496d, MIT",
  "effective_date": "2026-02-13"
}

GET /v1/wilayah/:code

One administrative region by code.

NameTypeRequiredDescription
codestringRequiredKemendagri wilayah code (2, 5, 8 or 13 characters like 31, 31.71, 31.71.01, 31.71.01.1001)
cURL
curl "https://refnusa.dev/v1/wilayah/31.71.01.1002"
JavaScript
await fetch("https://refnusa.dev/v1/wilayah/31.71.01.1002").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/wilayah/31.71.01.1002").json()
200 OK
{
  "code": "31.71.01.1002",
  "name": "Cideng",
  "level": "kelurahan",
  "parent_code": "31.71.01",
  "source_instrument": "Kepmendagri No 300.2.2-2138 Tahun 2025 as stated in the header of cahyadsn/wilayah db/wilayah.sql (the repository README cites No 300.2.2-2430 Tahun 2025), commit 55a496d, MIT",
  "effective_date": "2026-02-13"
}

GET /v1/postal-codes/reverse

Regions that carry one postal code.

NameTypeRequiredDescription
codestringRequiredPostal code (five digits)
cURL
curl "https://refnusa.dev/v1/postal-codes/reverse?code=10150"
JavaScript
await fetch("https://refnusa.dev/v1/postal-codes/reverse?code=10150").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/postal-codes/reverse", params={"code":"10150"}).json()
200 OK
{
  "postal_code": "10150",
  "wilayah": [
    {
      "code": "31.71.01.1002",
      "name": "Cideng",
      "level": "kelurahan"
    }
  ],
  "source_instrument": "cahyadsn/wilayah_kodepos json/wilayah_kodepos.json, commit ba84971, MIT",
  "effective_date": "2026-07-17"
}

GET /v1/postal-codes/:wilayah_code

Postal codes of one kelurahan or desa by its wilayah code.

NameTypeRequiredDescription
wilayah_codestringRequiredKemendagri wilayah code (2, 5, 8 or 13 characters like 31, 31.71, 31.71.01, 31.71.01.1001)
cURL
curl "https://refnusa.dev/v1/postal-codes/31.71.01.1001"
JavaScript
await fetch("https://refnusa.dev/v1/postal-codes/31.71.01.1001").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/postal-codes/31.71.01.1001").json()
200 OK
{
  "wilayah_code": "31.71.01.1001",
  "postal_codes": [
    "10110"
  ],
  "source_instrument": "cahyadsn/wilayah_kodepos json/wilayah_kodepos.json, commit ba84971, MIT",
  "effective_date": "2026-07-17"
}

GET /v1/tax/pph21-ter

PPh 21 effective average rate (TER) bracket for a monthly gross income and TER category A, B or C, per PP 58/2023.

NameTypeRequiredDescription
categorystringRequiredTER category A, B or C
income_idrintegerRequiredMonthly gross income in rupiah
cURL
curl "https://refnusa.dev/v1/tax/pph21-ter?category=A&income_idr=10000000"
JavaScript
await fetch("https://refnusa.dev/v1/tax/pph21-ter?category=A&income_idr=10000000").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/tax/pph21-ter", params={"category":"A","income_idr":10000000}).json()
200 OK
{
  "category": "A",
  "income_idr": 10000000,
  "rate_percent": 2,
  "bracket": {
    "lower_idr": 9650001,
    "upper_idr": 10050000
  },
  "source_instrument": "Peraturan Pemerintah Nomor 58 Tahun 2023 tentang Tarif Pemotongan Pajak Penghasilan Pasal 21 atas Penghasilan Sehubungan dengan Pekerjaan, Jasa, atau Kegiatan Wajib Pajak Orang Pribadi, Lampiran huruf A, B, dan C (Tarif Efektif Bulanan)",
  "effective_date": "2024-01-01",
  "source_url": "https://peraturan.bpk.go.id/Download/332609/PP%20Nomor%2058%20Tahun%202023.pdf"
}

GET /v1/tax/ptkp

Annual non-taxable income (PTKP) for a taxpayer status such as TK/0 or K/1.

NameTypeRequiredDescription
statusstringRequiredPTKP status code (TK/0 to TK/3, K/0 to K/3, K/I/0 to K/I/3)
cURL
curl "https://refnusa.dev/v1/tax/ptkp?status=K%2F1"
JavaScript
await fetch("https://refnusa.dev/v1/tax/ptkp?status=K%2F1").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/tax/ptkp", params={"status":"K/1"}).json()
200 OK
{
  "status": "K/1",
  "amount_idr": 63000000,
  "period": "annual",
  "source_instrument": "Peraturan Menteri Keuangan Nomor 101/PMK.010/2016 tentang Penyesuaian Besarnya Penghasilan Tidak Kena Pajak",
  "effective_date": "2016-01-01",
  "source_url": "https://peraturan.bpk.go.id/Download/111866/PMK%20Nomor%20101%20Tahun%202016.pdf"
}

GET /v1/prayer-times

Prayer times for one kabupaten/kota and date, computed by a documented hisab method; not an official Kemenag feed.

NameTypeRequiredDescription
city_codestringRequiredKemendagri kabupaten/kota code; a kecamatan or kelurahan code falls back to its parent (2, 5, 8 or 13 characters like 31, 31.71, 31.71.01, 31.71.01.1001)
datedateRequiredDate in YYYY-MM-DD form
cURL
curl "https://refnusa.dev/v1/prayer-times?city_code=31.71&date=2026-10-01"
JavaScript
await fetch("https://refnusa.dev/v1/prayer-times?city_code=31.71&date=2026-10-01").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/prayer-times", params={"city_code":"31.71","date":"2026-10-01"}).json()
200 OK
{
  "city_code": "31.71",
  "city_name": "Kota Administrasi Jakarta Pusat",
  "date": "2026-10-01",
  "timezone": "WIB",
  "utc_offset": 7,
  "fajr": "04:23",
  "sunrise": "05:35",
  "dzuhur": "11:45",
  "ashr": "14:51",
  "maghrib": "17:50",
  "isha": "18:59",
  "method": "computed, not an official Kemenag feed",
  "parameters": {
    "fajr_angle": 20,
    "isha_angle": 18,
    "asr_factor": 1,
    "ihtiyat_minutes": 2,
    "dhuhr_offset_minutes": 0
  },
  "source_instrument": "Subuh at 20 degrees as stated by the Dirjen Bimas Islam, Kementerian Agama (kemenag.go.id, 2020-12-21). Isya at 18 degrees, Ashar at shadow ratio 1 and ihtiyat 2 minutes are labelled estimates commonly published for Indonesia. Checked against the Bimas Islam jadwal shalat for Kota Jakarta: within 1 minute on six dates in February and March 2026.",
  "effective_date": "2026-09-23"
}

POST /v1/validate/nik

Checks the structure of a 16-digit NIK and looks up its region digits in the wilayah table. Send the NIK in the JSON body; it is never logged.

NameTypeRequiredDescription
nikstringRequiredThe 16-digit NIK

Made-up example number.

cURL
curl -X POST https://refnusa.dev/v1/validate/nik \
  -H "content-type: application/json" \
  -d '{"nik":"3171010101900001"}'
JavaScript
await fetch("https://refnusa.dev/v1/validate/nik", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({"nik":"3171010101900001"})
}).then((r) => r.json());
Python
import requests

requests.post("https://refnusa.dev/v1/validate/nik", json={"nik":"3171010101900001"}).json()
200 OK
{
  "format_valid": true,
  "region_found": true,
  "province": "Daerah Khusus Ibukota Jakarta",
  "kabupaten_kota": "Kota Administrasi Jakarta Pusat",
  "kecamatan": "Gambir",
  "sex": "male",
  "birth": {
    "day": 1,
    "month": 1,
    "year_2digit": "90"
  },
  "structure_source": "Peraturan Pemerintah Republik Indonesia Nomor 40 Tahun 2019 tentang Pelaksanaan Undang-Undang Nomor 23 Tahun 2006 tentang Administrasi Kependudukan sebagaimana telah diubah dengan Undang-Undang Nomor 24 Tahun 2013 tentang Perubahan atas Undang-Undang Nomor 23 Tahun 2006 tentang Administrasi Kependudukan, Pasal 31 ayat (1) (https://peraturan.bpk.go.id/Details/108801/pp-no-40-tahun-2019)",
  "source_instrument": "Kepmendagri No 300.2.2-2138 Tahun 2025 as stated in the header of cahyadsn/wilayah db/wilayah.sql (the repository README cites No 300.2.2-2430 Tahun 2025), commit 55a496d, MIT",
  "effective_date": "2026-02-13"
}

GET /v1/validate/plate

Checks the format of an Indonesian vehicle plate and names the region of its prefix when the prefix table is loaded.

NameTypeRequiredDescription
platestringRequiredPlate such as B 1234 XYZ
cURL
curl "https://refnusa.dev/v1/validate/plate?plate=B+1234+XYZ"
JavaScript
await fetch("https://refnusa.dev/v1/validate/plate?plate=B+1234+XYZ").then((r) => r.json());
Python
import requests

requests.get("https://refnusa.dev/v1/validate/plate", params={"plate":"B 1234 XYZ"}).json()
200 OK
{
  "valid": true,
  "plate": "B 1234 XYZ",
  "prefix": "B",
  "region_name": "Daerah Khusus Ibukota Jakarta; Kab. Kepulauan Seribu; Kota Depok; Kota Bekasi; Kab. Bekasi; Kota Tangerang; Kota Tangerang Selatan",
  "source_instrument": "Peraturan Kepolisian Negara Republik Indonesia Nomor 7 Tahun 2021 tentang Registrasi dan Identifikasi Kendaraan Bermotor, Lampiran huruf A (Penentuan kode wilayah berdasarkan wilayah Regident Ranmor)",
  "effective_date": "2021-05-05"
}

MCP server

Refnusa is a remote MCP server at https://refnusa.dev/mcp over Streamable HTTP, with the same data as the REST API.

Claude Code
claude mcp add --transport http refnusa https://refnusa.dev/mcp

Claude.ai

  1. Settings
  2. Connectors
  3. Add custom connector
  4. Paste https://refnusa.dev/mcp
JSON config
{
  "mcpServers": {
    "refnusa": {
      "type": "http",
      "url": "https://refnusa.dev/mcp"
    }
  }
}

Example call

A tools/call request for get_ump, and its real result.

Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_ump",
    "arguments": {
      "year": 2026,
      "province_code": "31"
    }
  }
}
Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"year\":2026,\"ump\":[{\"province_code\":\"31\",\"province_name\":\"DKI Jakarta\",\"amount_idr\":5729876,\"source_instrument\":\"Keputusan Gubernur Nomor 1142 Tahun 2025 tentang Upah Minimum Provinsi Tahun 2026\",\"effective_date\":\"2026-01-01\",\"source_url\":\"https://jdih.jakarta.go.id/dokumen/detail/14763\"}]}"
      }
    ],
    "structuredContent": {
      "year": 2026,
      "ump": [
        {
          "province_code": "31",
          "province_name": "DKI Jakarta",
          "amount_idr": 5729876,
          "source_instrument": "Keputusan Gubernur Nomor 1142 Tahun 2025 tentang Upah Minimum Provinsi Tahun 2026",
          "effective_date": "2026-01-01",
          "source_url": "https://jdih.jakarta.go.id/dokumen/detail/14763"
        }
      ]
    }
  }
}

Tools

  • get_holidays

    year

    Public holidays (libur nasional) and joint leave days (cuti bersama) for one year, from that year's SKB 3 Menteri decree.

  • check_holiday

    date

    Whether one date is a public holiday or cuti bersama, with the decree it was checked against. Weekends count only when the decree names them.

  • get_ump

    year, province_code (optional)

    Provincial minimum wage (UMP) for one year, all provinces or one province, with the governor decree behind each figure.

  • get_umk

    year, regency_code

    Regency or city minimum wage (UMK) for one year, starter set of the largest regencies only.

  • get_wilayah

    level (optional), parent_code (optional), code (optional)

    Administrative regions: the 38 provinces, the children of one parent code, or one region by code.

  • get_postal_code

    wilayah_code

    Postal codes of one kelurahan or desa by its wilayah code.

  • reverse_postal_code

    postal_code

    Regions (kelurahan or desa) that carry one postal code.

  • get_pph21_ter

    category, income_idr

    PPh 21 effective average rate (TER) bracket for a monthly gross income and TER category A, B or C, per PP 58/2023.

  • get_ptkp

    status

    Annual non-taxable income (PTKP) for a taxpayer status such as TK/0 or K/1.

  • get_prayer_times

    city_code, date

    Prayer times for one kabupaten/kota and date, computed by a documented hisab method; not an official Kemenag feed.

  • validate_nik

    nik

    Checks the structure of a 16-digit NIK and looks up its region digits in the wilayah table. Send the NIK in the JSON body; it is never logged.

  • validate_plate

    plate

    Checks the format of an Indonesian vehicle plate and names the region of its prefix when the prefix table is loaded.

Sources and changelog

Each dataset follows the instrument that sets it. Holidays and cuti bersama come from the yearly joint decree of three ministers (SKB 3 Menteri). Minimum wages come from each governor's decree. Kalimantan Timur publishes its 2026 figure as a governor's announcement (Pengumuman Gubernur), and that row cites it. Region codes follow the Kepmendagri wilayah decree through the cahyadsn/wilayah dataset, and postal codes come from cahyadsn/wilayah_kodepos, both under the MIT licence. The PPh 21 effective rates follow PP 58/2023 and the PTKP amounts follow PMK 101/PMK.010/2016. Prayer times are computed with a documented hisab method and are not an official Kemenag feed.

  • 2026-09-24 wages_umk

    Loaded the 2026 UMK starter set for 9 of 10 large industrial kabupaten/kota (Medan, Kabupaten Bogor, Karawang, Kabupaten Bekasi, Bandung, Kota Bekasi, Depok, Semarang, Surabaya), each from the governor's decree. Kota Makassar is not yet sourced.

  • 2026-09-24 wages_ump

    Added the 2026 UMP for eight more provinces (12, 14, 16, 35, 53, 63, 72, 74), each from its own governor's decree: 27 of 38 provinces are now loaded. The other 11 are not yet sourced.

  • 2026-09-24 wilayah

    The NIK validator now cites PP 40/2019 Pasal 31 ayat (1) for the digit layout.

  • 2026-09-24 plate_prefixes

    Loaded vehicle plate prefixes for 57 regions from the Perpol Lampiran; the note flags that Papua prefixes predate the 2022 province split.

  • 2026-09-24 wages_ump

    Loaded UMP (upah minimum provinsi) 2026 for 19 of 38 provinces, each sourced from its own governor's decree; the other 19 are not yet sourced.

  • 2026-09-24 tax_pph21_ter

    Loaded the monthly PPh 21 effective rate (TER) brackets: 44 brackets in category A, 40 in B and 41 in C, top rate 34 percent in each.

  • 2026-09-24 tax_ptkp

    Loaded the annual PTKP (penghasilan tidak kena pajak) amount for all 12 taxpayer statuses, TK/0 to TK/3, K/0 to K/3 and K/I/0 to K/I/3.

  • 2026-09-24 prayer_times

    Loaded the prayer-time calculation method (Refnusa hisab v1): a solar-position hisab computing Subuh, Terbit, Dzuhur, Ashar, Maghrib and Isya per request from each kabupaten/kota's coordinates and UTC offset. Checked against the Bimas Islam jadwal shalat for Kota Jakarta on six dates in February and March 2026, every time within 1 minute.

  • 2026-09-24 postal_codes

    Loaded postal codes for all 83,762 kelurahan and desa, matched to the wilayah table by code.

  • 2026-09-24 wilayah

    Loaded the Kemendagri administrative region codes: 91,599 regions (38 provinces, 514 kabupaten/kota, 7,285 kecamatan, 83,762 kelurahan/desa), with coordinates and UTC offsets for provinces and kabupaten/kota from cahyadsn/wilayah db/wilayah_level_1_2.sql.

Limits and errors

The free tier has no monthly cap. Each client may send 60 requests a minute; past that the API answers 429 with a Retry-After header.

CodeStatusMeaning
invalid_parameter400A parameter is missing or fails validation.
bad_json400The request body is not valid JSON.
not_found404No record matches the request.
dataset_not_loaded404The dataset behind this route is not loaded yet.
body_too_large413The request body is over 64 KB.
rate_limited429The client has passed 60 requests in the last minute.
server_error500An unexpected error; nothing about the request caused it.