SchoolGateway Dokumentasi API docs/api.md
Daftar isi
  1. Bentuk response
  2. Parameter filter wilayah
  3. Rate limiting
  4. Caching
  5. Ringkasan endpoint
  6. 1. Daftar provinsi
  7. 2. Daftar kabupaten/kota
  8. 3. Daftar kecamatan
  9. Cascading select
  10. 4. Daftar sekolah
  11. 5. Detail sekolah
  12. Error (HTTP 404)
  13. 6. Daftar perguruan tinggi
  14. 7. Detail perguruan tinggi
  15. Error (HTTP 404)
  16. 8. Daftar program studi
  17. 9. Status scraping
  18. Menjalankan scraper
  19. Struktur database
  20. Kolom sekolahs
  21. Kolom sekolah_details (relasi detail)
  22. Kolom perguruan_tinggis
  23. Kode status HTTP
  24. Contoh integrasi
  25. Deploy

SchoolGateway API — Dokumentasi

Base URL: http://<host>:9004/api/v1

Semua endpoint public (tanpa autentikasi) dan mengembalikan Content-Type: application/json.


Bentuk response

Endpoint daftar (list) selalu:

{
    "success": true,
    "meta": {
        "current_page": 1,
        "per_page": 50,
        "total": 120,
        "last_page": 3
    },
    "data": [ ... ]
}

Endpoint detail selalu:

{ "success": true, "data": { ... } }

Error selalu:

{ "success": false, "message": "..." }

Semua list endpoint memakai paginasi: per_page default 50, maks 100; page default 1. Angka di meta.total adalah jumlah baris yang cocok dengan filter, bukan jumlah baris di data.

Parameter filter wilayah

provinsi, kabupaten, dan kecamatan pada semua endpoint di bawah dicocokkan terhadap nama, bukan kode.

Salah Benar
?kabupaten=3171 ?kabupaten=Jakarta
?provinsi=010000 ?provinsi=Jakarta

Untuk pencocokan berdasarkan kode, lihat kolom *_kode yang dikembalikan tiap baris.

Rate limiting

60 request per menit per IP. Melebihi batas menghasilkan HTTP 429.

Caching

Hasil di-cache di Redis, TTL per endpoint:

Endpoint TTL
/provinsi 24 jam
/kabupaten, /kecamatan 12 jam
/sekolah 1 jam
/sekolah/{npsn} 6 jam
/perguruan-tinggi 24 jam
/perguruan-tinggi/{kode} 6 jam
/program-studi 24 jam
/scrape/status 1 menit

Hasil kosong (list) dan 404 (detail) tidak pernah di-cache, sehingga record yang baru discrape langsung terlihat tanpa menunggu TTL.


Ringkasan endpoint

Method Path Deskripsi
GET /api/v1/provinsi Daftar provinsi
GET /api/v1/kabupaten Daftar kabupaten/kota
GET /api/v1/kecamatan Daftar kecamatan
GET /api/v1/sekolah Cari / filter daftar sekolah
GET /api/v1/sekolah/{npsn} Detail satu sekolah
GET /api/v1/perguruan-tinggi Cari / filter perguruan tinggi (PDDikti)
GET /api/v1/perguruan-tinggi/{kode} Detail satu perguruan tinggi
GET /api/v1/program-studi Cari / filter program studi
GET /api/v1/scrape/status Jumlah record & waktu update terakhir per tabel

1. Daftar provinsi

GET /api/v1/provinsi

Param Tipe Contoh Keterangan
q string jawa Pencarian nama (LIKE)
jenjang string dikmen Hanya provinsi yang punya data jenjang ini
per_page integer 20 Default 50, maks 100
page integer 2 Default 1
curl "http://localhost:9004/api/v1/provinsi"
curl "http://localhost:9004/api/v1/provinsi?q=jawa"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 3, "total": 39, "last_page": 13},
    "data": [
        {"kode": "060000", "nama": "Aceh"},
        {"kode": "220000", "nama": "Bali"},
        {"kode": "280000", "nama": "Banten"}
    ]
}

2. Daftar kabupaten/kota

GET /api/v1/kabupaten

Param Tipe Contoh Keterangan
provinsi string Jakarta Nama provinsi induk (LIKE)
q string bandung Pencarian nama (LIKE)
jenjang string dikmen Filter jenjang
per_page, page integer Seperti di atas
curl "http://localhost:9004/api/v1/kabupaten?provinsi=Jakarta"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 50, "total": 6, "last_page": 1},
    "data": [
        {"kode": "010100", "nama": "Kab. Adm. Kep. Seribu"},
        {"kode": "016200", "nama": "Kota Adm. Jakarta Barat"}
    ]
}

3. Daftar kecamatan

GET /api/v1/kecamatan

Param Tipe Contoh Keterangan
kabupaten string Jakarta Nama kabupaten induk (LIKE)
q string menteng Pencarian nama (LIKE)
jenjang string dikmen Filter jenjang
per_page, page integer Seperti di atas
curl "http://localhost:9004/api/v1/kecamatan?kabupaten=Jakarta"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 50, "total": 22, "last_page": 1},
    "data": [
        {"kode": "016005", "nama": "Cempaka Putih"},
        {"kode": "016207", "nama": "Cengkareng"}
    ]
}

Cascading select

/api/v1/provinsi                      -> pilih provinsi (kode/nama)
/api/v1/kabupaten?provinsi=Jakarta    -> pilih kabupaten
/api/v1/kecamatan?kabupaten=Jakarta   -> pilih kecamatan
/api/v1/sekolah?kabupaten=Jakarta     -> hasil

4. Daftar sekolah

GET /api/v1/sekolah

Param Tipe Contoh Keterangan
q string SMAN Cari nama atau npsn (LIKE), diurutkan relevansi: persis > diawali > mengandung
nama string SMAN Nama (LIKE) — alias q, tetap didukung
npsn string 2010 NPSN (LIKE)
provinsi string Jakarta Nama provinsi (LIKE)
kabupaten string Jakarta Nama kabupaten (LIKE)
kecamatan string Senen Nama kecamatan (LIKE)
jenjang string dikmen DIKDAS / DIKMEN (otomatis di-uppercase)
status string NEGERI NEGERI / SWASTA (otomatis di-uppercase)
per_page, page integer Seperti di atas
curl "http://localhost:9004/api/v1/sekolah?jenjang=dikmen&provinsi=Jakarta"
curl "http://localhost:9004/api/v1/sekolah?nama=SMAN&status=NEGERI&per_page=20"
curl "http://localhost:9004/api/v1/sekolah?q=SMAN%203"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 3, "total": 52, "last_page": 18},
    "data": [
        {
            "npsn": "60725437",
            "nama": "MAS AL QALAM",
            "alamat": "...",
            "kelurahan": "...",
            "status": "SWASTA",
            "jenjang_pendidikan": "DIKMEN",
            "kecamatan": "Senen",
            "kabupaten_kota": "Kota Adm. Jakarta Pusat",
            "provinsi": "D.K.I. Jakarta"
        }
    ]
}

Response list hanya memuat kolom terpilih di atas; kolom *_kode dan created_at/updated_at hanya ada di endpoint detail.


5. Detail sekolah

GET /api/v1/sekolah/{npsn}

curl "http://localhost:9004/api/v1/sekolah/20107185"
{
    "success": true,
    "data": {
        "npsn": "20107185",
        "nama": "SMAN 69 JAKARTA",
        "alamat": "PULAU PRAMUKA RT 003/05",
        "kelurahan": "PULAU PANGGANG",
        "kecamatan": "KEPULAUAN SERIBU UTARA",
        "kabupaten_kota": "ADM. KEP. SERIBU",
        "provinsi": "D.K.I. JAKARTA",
        "kecamatan_kode": "010102",
        "kabupaten_kode": "010100",
        "provinsi_kode": "010000",
        "status": "NEGERI",
        "jenjang_pendidikan": "DIKMEN",
        "detail": {
            "akreditasi": "A",
            "kementerian_pembina": "Kementerian Pendidikan Dasar dan Menengah",
            "naungan": "Pemerintah Daerah",
            "luas_tanah": "5445.00",
            "sumber_listrik": "PLN",
            "akses_internet": null,
            "telepon": "02170611769",
            "fax": "02146214455",
            "email": "ka_sman_69@yahoo.com",
            "website": "http://sman69jkt.sch.id",
            "operator": "SITI MUKHLISHOH",
            "lintang": "-5.74763200",
            "bujur": "106.61348640"
        }
    }
}

detail bisa null bila tahap scraping detail belum berjalan untuk NPSN tersebut.

Error (HTTP 404)

{ "success": false, "message": "Sekolah tidak ditemukan" }

6. Daftar perguruan tinggi

GET /api/v1/perguruan-tinggi

Sumber: PDDikti.

Param Tipe Contoh Keterangan
nama string akademi Nama (LIKE)
jenis string Swasta Swasta / Negeri (case-sensitive sesuai data)
status string Aktif Aktif, Tutup, Alih Bentuk, Alih Kelola, Pembinaan
akreditasi string Baik Nilai akreditasi
provinsi string ACEH Nama provinsi (LIKE)
kabupaten string Yogyakarta Nama kabupaten/kota (LIKE)
per_page, page integer Seperti di atas

Perhatian: bila status tidak dikirim (atau dikirim kosong), endpoint ini otomatis membatasi hasil ke status_pt = "Aktif" sehingga meta.total hanya menghitung PT aktif. Kirim ?status= dengan nilai yang valid (Tutup, Alih Bentuk, Alih Kelola, Pembinaan, Aktif) untuk melihat status lain.

curl "http://localhost:9004/api/v1/perguruan-tinggi?per_page=3"
curl "http://localhost:9004/api/v1/perguruan-tinggi?status=Tutup"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 3, "total": 62, "last_page": 21},
    "data": [
        {
            "id": 76,
            "kode_pt": null,
            "nama_normalized": "AKADEMI FARMASI PUTRA INDONESIA MALANG",
            "nama": "Akademi Farmasi Putra Indonesia Malang",
            "nama_singkat": null,
            "jenis_pt": "Swasta",
            "status_pt": "Aktif",
            "akreditasi": null,
            "provinsi": "JAWA TIMUR",
            "kabupaten_kota": "Kota Malang",
            "jumlah_prodi": 0,
            "biaya_min": null,
            "biaya_max": null,
            "alamat": null,
            "kelompok": null,
            "pembina": null,
            "created_at": "2026-10-06T15:24:38.000000Z",
            "updated_at": "2026-10-06T15:24:38.000000Z"
        }
    ]
}

kode_pt hanya terisi untuk PT yang sudah melewati tahap scraping detail. Sisanya null.


7. Detail perguruan tinggi

GET /api/v1/perguruan-tinggi/{kode}

{kode} diterima dalam dua bentuk:

  1. Kode PT — mis. 053019.
  2. Fallback nama_normalized — nama huruf besar persis seperti disimpan scraper, mis. SEKOLAH%20TINGGI%20ILMU%20ADMINISTRASI%20AAN. Dipakai untuk PT yang kode_pt-nya masih null.
Param Tipe Keterangan
with_prodi boolean Hanya kembalikan PT yang punya minimal satu program studi
curl "http://localhost:9004/api/v1/perguruan-tinggi/053019"
curl "http://localhost:9004/api/v1/perguruan-tinggi/053019?with_prodi=1"
{
    "success": true,
    "data": {
        "id": 4,
        "kode_pt": "053019",
        "nama_normalized": "SEKOLAH TINGGI ILMU ADMINISTRASI AAN",
        "nama": "Sekolah Tinggi Ilmu Administrasi Aan",
        "nama_singkat": "STIA \"AAN\"",
        "jenis_pt": "Swasta",
        "status_pt": "Aktif",
        "akreditasi": "Baik Sekali",
        "provinsi": "D.I. YOGYAKARTA",
        "kabupaten_kota": "Kota Yogyakarta",
        "jumlah_prodi": 4,
        "biaya_min": 980000,
        "biaya_max": 16025000,
        "alamat": "Blunyahrejo Karangwaru Tegalrejo",
        "kode_pos": "55241",
        "kecamatan": "Kec. Tegalrejo",
        "email": "stiaaan79@gmail.com",
        "telepon": "0274-517471",
        "fax": "0274-517471",
        "website": "www.stia-aan.ac.id",
        "lintang": "-7.77032700",
        "bujur": "110.36616100",
        "kelompok": "Perguruan Tinggi Swasta",
        "pembina": "LLDIKTI V",
        "sk_pendirian_sp": "629/KPT/I/2018",
        "tgl_berdiri_pt": "1979-06-07T00:00:00.000000Z",
        "program_studi": []
    }
}

program_studi berisi daftar prodi PT tersebut. Kosong bila tahap scraping prodi belum dijalankan.

Error (HTTP 404)

{ "success": false, "message": "Perguruan tinggi tidak ditemukan" }

8. Daftar program studi

GET /api/v1/program-studi

Param Tipe Contoh Keterangan
nama string teknik Nama prodi (LIKE)
kode_pt string 053019 Prodi milik PT tersebut
jenjang string S1 Jenjang prodi (otomatis di-uppercase)
akreditasi string Baik Akreditasi prodi
status string Aktif Status prodi (otomatis di-uppercase)
provinsi string Yogyakarta Provinsi PT induk (LIKE)
per_page, page integer Seperti di atas
curl "http://localhost:9004/api/v1/program-studi?kode_pt=053019"
{
    "success": true,
    "meta": {"current_page": 1, "per_page": 50, "total": 0, "last_page": 1},
    "data": []
}

Setiap baris menyertakan relasi perguruan_tinggi (id, kode_pt, nama).


9. Status scraping

GET /api/v1/scrape/status

Param Tipe Contoh Keterangan
jenjang string dikmen Hanya menyaring tabel provinsi, kabupaten, kecamatan, sekolahs. Tabel PDDikti tidak punya kolom jenjang.
curl "http://localhost:9004/api/v1/scrape/status"
curl "http://localhost:9004/api/v1/scrape/status?jenjang=dikmen"
{
    "success": true,
    "meta": {"jenjang": "DIKMEN", "generated_at": "2026-10-06T09:07:09+00:00"},
    "data": {
        "provinsi":         {"total": 39,  "updated_at": "2026-10-06T15:35:19+00:00"},
        "kabupaten":        {"total": 526, "updated_at": "2026-10-06T15:35:52+00:00"},
        "kecamatan":        {"total": 24,  "updated_at": "2026-10-06T15:35:56+00:00"},
        "sekolah":          {"total": 52,  "updated_at": "2026-10-06T15:35:59+00:00"},
        "sekolah_detail":   {"total": 12,  "updated_at": "2026-10-06T15:36:09+00:00"},
        "perguruan_tinggi": {"total": 101, "updated_at": "2026-10-06T15:34:37+00:00"},
        "program_studi":    {"total": 0,   "updated_at": null}
    }
}

updated_at adalah MAX(updated_at) kolom pada tabel tersebut — null berarti tabel masih kosong.


Menjalankan scraper

# Sekolah (perlu --profile scraper; resume otomatis, lanjut dari progres terakhir)
docker compose --profile scraper run --rm scraper --jenjang dikmen
docker compose --profile scraper run --rm scraper --jenjang dikdas

# Periksa proxy sebelum mulai
docker compose --profile scraper run --rm scraper --proxy-check

# Perguruan tinggi + program studi
docker compose --profile scraper run --rm scraper run_pt.py --limit 100 --detail

Struktur database

Table Deskripsi
provinsi Provinsi (kode, nama, jenjang)
kabupaten Kabupaten/kota + FK provinsi_kode
kecamatan Kecamatan + FK kabupaten_kode, provinsi_kode
sekolahs Sekolah utama (NPSN, nama, alamat, FK kode wilayah)
sekolah_details Detail sekolah (akreditasi, kontak, koordinat)
perguruan_tinggis Perguruan tinggi dari PDDikti
program_studis Program studi, FK perguruan_tinggi_id

Kolom sekolahs

Field Jenis Keterangan
npsn string Primary key bisnis (8 digit)
nama string Nama sekolah
alamat text Alamat lengkap
kelurahan string Kelurahan / desa
kecamatan string Nama kecamatan
kabupaten_kota string Nama kabupaten/kota
provinsi string Nama provinsi
kecamatan_kode string Kode BPS kecamatan
kabupaten_kode string Kode BPS kabupaten/kota
provinsi_kode string Kode BPS provinsi
status string NEGERI / SWASTA
jenjang_pendidikan string DIKDAS / DIKMEN

Kolom sekolah_details (relasi detail)

Field Jenis Keterangan
akreditasi string A/B/C/-
kementerian_pembina string Kementerian pembina
naungan string Lembaga naungan
luas_tanah string Luas tanah (m²)
sumber_listrik string Sumber listrik
akses_internet string Jenis akses internet
telepon, fax, email, website string Kontak
operator string Nama operator data
lintang, bujur string Koordinat

Kolom perguruan_tinggis

Field Jenis Keterangan
kode_pt string Kode PDDikti — null bila tahap detail belum jalan
nama_normalized string Nama huruf besar, dipakai sebagai fallback {kode}
nama, nama_singkat string Nama lengkap dan singkat
jenis_pt string Swasta / Negeri
status_pt string Aktif, Tutup, Alih Bentuk, Alih Kelola, Pembinaan
akreditasi string Akreditasi PT
provinsi, kabupaten_kota, kecamatan, alamat, kode_pos string Wilayah dan alamat
jumlah_prodi int Jumlah program studi
biaya_min, biaya_max int Rentang biaya (Rp)
kelompok, pembina string Kelompok PT dan LLDIKTI
sk_pendirian_sp, tgl_berdiri_pt string Dasar pendirian
lintang, bujur string Koordinat

Kode status HTTP

Status Kasus
200 Sukses (daftar / detail)
404 {npsn} atau {kode} tidak ditemukan
429 Rate limit terlampaui (60 req/menit per IP)
500 Internal server error

Contoh integrasi

$base = 'http://localhost:9004/api/v1';

// 1. Pilih provinsi
$provinsi = Http::get($base.'/provinsi')->json('data');

// 2. Kabupaten pada provinsi tersebut
$kabupaten = Http::get($base.'/kabupaten', ['provinsi' => 'Jakarta'])->json('data');

// 3. Sekolah, gabungkan semua filter
$sekolah = Http::get($base.'/sekolah', [
    'jenjang'   => 'dikmen',
    'kabupaten' => 'Jakarta',
    'per_page'  => 100,
])->json();

foreach ($sekolah['data'] as $s) {
    // $s['npsn'], $s['nama'], $s['alamat'], ...
}

// 4. Detail sekolah lengkap (termasuk koordinat)
$detail = Http::get($base.'/sekolah/'.$s['npsn'])->json('data');

// 5. Perguruan tinggi
$pt = Http::get($base.'/perguruan-tinggi', [
    'status' => 'Aktif',
    'nama'   => 'akademi',
])->json();

Deploy

# Jalankan semua container
docker compose up -d

# Scraper sekolah (resume otomatis)
docker compose --profile scraper run --rm scraper --jenjang dikmen

# Scraper perguruan tinggi
docker compose --profile scraper run --rm scraper run_pt.py --limit 100 --detail

Nginx melayani port 9004.