⚠️ Disclaimer: API ini adalah agregator tidak resmi yang membungkus data harga pangan dari PIHPS Bank Indonesia menjadi API JSON. Bukan produk resmi Bank Indonesia atau Badan Pangan Nasional. Lihat bagian Disclaimer.
API read-only, gratis, dan open source untuk mengambil data harga pangan strategis Indonesia (beras, cabai, bawang, daging, minyak goreng, gula, telur, dll) per provinsi dan kabupaten/kota. Data diperbarui otomatis setiap hari oleh scraper internal.
- Data harga eceran Pasar Tradisional (sesuai sumber PIHPS BI)
- Cakupan: 21 komoditas, 34 provinsi, 110+ kabupaten/kota
- Riwayat hingga 90 hari
- Tanpa autentikasi — semua endpoint publik, dilindungi rate limit berbasis IP
- Dokumentasi OpenAPI interaktif (Swagger UI)
- Base URL
- Format Response
- Endpoint
- Contoh Pemakaian
- Rate Limit
- Header HTTP
- Menjalankan Lokal
- Pengembangan
- Lisensi
- Disclaimer
| Environment | URL |
|---|---|
| Produksi | https://harga-pangan.fly.dev |
| Lokal | http://localhost:8080 |
Dokumentasi interaktif: GET /docs (Swagger UI) · GET /openapi.json (spek raw).
Setiap respons selalu memuat field berikut agar konsumen API tahu asal & umur data:
Error memakai HTTP status standar dan pesan dalam Bahasa Indonesia:
{
"sumber": "PIHPS Bank Indonesia",
"error": "Parameter tidak valid.",
"issues": ["hari: Number must be less than or equal to 90"]
}Daftar komoditas yang tersedia (referensi). id (com_*) adalah id internal sumber
data (PIHPS BI) — dipakai sebagai filter komoditas=.
{
"data": [
{ "id": "com_1", "nama": "Beras Kualitas Bawah I", "satuan": "kg", "urutan": 1, "kategori": "Beras" }
]
}Daftar provinsi & kabupaten/kota.
| Query | Tipe | Keterangan |
|---|---|---|
level |
str | Filter level: provinsi atau kabupaten_kota |
provinsi |
str | Filter nama provinsi (mendukung sebagian kata) |
Snapshot harga terbaru semua komoditas (opsional filter). Respons dikelompokkan per
komoditas, dengan tanggal data di level atas.
| Query | Tipe | Keterangan |
|---|---|---|
komoditas |
str | Nama/id komoditas (sebagian kata, mis. beras) |
provinsi |
str | Nama provinsi |
kota |
str | Nama kabupaten/kota (mis. surabaya) |
{
"tanggal": "2026-08-14",
"data": [
{
"komoditas": { "id": "com_1", "nama": "Beras Kualitas Bawah I", "satuan": "kg" },
"harga": [
{ "wilayah": { "level": "provinsi", "nama": "Jawa Timur", "provinsi": null }, "harga": 13550 },
{ "wilayah": { "level": "kabupaten_kota", "nama": "Kota Surabaya", "provinsi": "Jawa Timur" }, "harga": 15150 }
]
}
]
}Sama format & param seperti /harga/terbaru, tetapi wajib minimal satu filter
(komoditas, provinsi, atau kota) — 400 jika kosong.
Riwayat harga N hari terakhir, dikelompokkan per komoditas × wilayah.
| Query | Tipe | Wajib | Keterangan |
|---|---|---|---|
komoditas |
str | ya | Nama/id komoditas |
kota |
str | ya* | Nama kabupaten/kota (atau gunakan provinsi) |
provinsi |
str | ya* | Nama provinsi (alternatif kota) |
hari |
int | tidak | Jumlah hari riwayat, default 30, maks 90 |
*Wajib salah satu dari
kotaatauprovinsi.
{
"data": [
{
"komoditas": { "id": "com_1", "nama": "Beras Kualitas Bawah I", "satuan": "kg" },
"wilayah": { "level": "kabupaten_kota", "nama": "Kota Surabaya", "provinsi": "Jawa Timur" },
"riwayat": [
{ "tanggal": "2026-08-12", "harga": 15000 },
{ "tanggal": "2026-08-13", "harga": 15100 },
{ "tanggal": "2026-08-14", "harga": 15150 }
]
}
]
}# Semua komoditas
curl "https://harga-pangan.fly.dev/komoditas"
# Harga terbaru beras di Surabaya
curl "https://harga-pangan.fly.dev/harga?komoditas=beras&kota=surabaya"
# Snapshot semua harga di Jawa Timur
curl "https://harga-pangan.fly.dev/harga/terbaru?provinsi=jawa%20timur"
# Riwayat 30 hari cabai di Surabaya
curl "https://harga-pangan.fly.dev/harga/historis?komoditas=cabai&kota=surabaya&hari=30"Pakai
http://localhost:8080kalau menjalankan lokal (lihat Menjalankan Lokal).
const BASE = "https://harga-pangan.fly.dev";
const { data: komoditas } = await fetch(`${BASE}/komoditas`).then((r) => r.json());
console.log(komoditas.map((k) => `${k.nama} (${k.id})`));
const { data: beras } = await fetch(
`${BASE}/harga/historis?komoditas=beras&kota=surabaya&hari=30`,
).then((r) => r.json());
for (const seri of beras) {
console.log(`${seri.komoditas.nama} @ ${seri.wilayah.nama}:`);
for (const { tanggal, harga } of seri.riwayat) {
console.log(` ${tanggal}: Rp ${harga}`);
}
}Tanpa autentikasi, semua permintaan dibatasi 120 request/menit per IP (jendela
tetap). Ketika terlampaui, respons 429 dengan header Retry-After. Atur ulang
lewat env RATE_LIMIT_MAX. Endpoint /health dikecualikan dari penghitungan kuota.
- CORS: semua endpoint mengizinkan cross-origin (
Access-Control-Allow-Origin: *), termasuk preflightOPTIONS. - Cache: respons sudah diset untuk caching oleh CDN/proxy/browser —
Cache-Controlberbeda per tipe data:Endpoint Cache-Control /komoditas,/wilayahpublic, max-age=3600/harga*public, max-age=300error ( 4xx/5xx),/healthno-store/,/docs,/openapi.jsonno-cache - Semua respons JSON menyertakan
X-Content-Type-Options: nosniff.
Prasyarat: Bun ≥ 1.3.
bun install
bun run dev # scheduler + API (http://localhost:8080)
bun run scrape # jalankan scraper sekali (mode full)
bun run test # unit test
bun run typecheck # type checkMode lain: bun src/index.ts api (hanya API), bun src/index.ts full,
bun src/index.ts smoke.
Konfigurasi via env:
| Env | Default | Keterangan |
|---|---|---|
PORT |
8080 |
Port API |
DB_PATH |
data/harga-pangan.db |
Lokasi database SQLite |
RATE_LIMIT_MAX |
120 |
Maks request per menit per IP |
API_PUBLIC_URL |
http://localhost:8080 |
Base URL yang ditampilkan di OpenAPI |
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID |
— | Notifikasi scraper ke Telegram (opsional) |
Struktur:
src/
scraper/ # fetcher + parsing + deteksi anomali + scheduler
db/ # skema & query SQLite
routes/ # endpoint API (Hono + zod-openapi)
middleware/ # rate limit
notify/ # notifikasi Telegram
util/
Stack: Bun · TypeScript · Hono (@hono/zod-openapi) · SQLite (bun:sqlite)
· Zod. Skema Zod dipakai untuk validasi input sekaligus generate dokumentasi OpenAPI.
API ini bukan produk resmi Bank Indonesia maupun Badan Pangan Nasional, dan
tidak berafiliasi dengan keduanya. Data diambil dari situs PIHPS
(bi.go.id/hargapangan) lewat endpoint internal yang tidak terdokumentasi secara
resmi, sehingga:
- struktur data sumber bisa berubah sewaktu-waktu tanpa pemberitahuan;
- keakuratan tidak dijamin; gunakan dengan pertimbangan Anda sendiri;
- periksa ketentuan penggunaan data masing-masing sumber sebelum memakai API ini secara komersial.
Atribusi sumber wajib dipertahankan di aplikasi yang memakai API ini.
{ "sumber": "PIHPS Bank Indonesia", // dari mana data ini "tanggal_update": "2026-08-16T07:30:00Z", // kapan terakhir diperbarui di server "disclaimer": "Agregator tidak resmi — ...", // atribusi & batasan "data": [ ... ] // isi sesuai endpoint }