Cloud Cybersoft · Integrasi PDAM · v1

Spesifikasi API PDAM

Kontrak API yang harus disediakan server PDAM agar bisa dihubungkan ke Cloud Cybersoft lewat menu Settings → PDAM. Setiap subscriber bisa menambahkan PDAM-nya sendiri dan memilih PDAM untuk tiap channel. Semua contoh respons diambil dari API Perumda Air Minum Tirta Amertha Jembrana yang aktif saat ini (9 Oktober 2026). Nama, alamat, koordinat, dan nomor sambungan sudah diganti dengan data fiktif. Angka tagihan dan strukturnya asli.

Endpoint
5 URL (4 GET, 1 POST)
Format
JSON, UTF-8
Otentikasi
api_user + api_key
Batas waktu
15 detik per panggilan

Ringkasan endpoint

Setiap PDAM mengisi lima URL di Cloud. Nama path bebas; Cloud hanya memakai URL lengkap yang diisi admin. Kolom "Dipakai di" menunjukkan tombol di halaman Chats yang memanggil endpoint tersebut.

Kolom di CloudMetodeContoh URL (Jembrana)Dipakai di
URL TagihanGET…/waba/checkCek Tagihan, email tagihan, tagihan ke chat Telegram/LINE/Messenger/Instagram/Live Chat
URL CustomerGET…/waba/customerCek Pelanggan (cari nama/alamat)
URL HistoryGET…/waba/historyRiwayat Pembayaran
URL InvoicePOST…/waba/invoiceKirim Tagihan ke WhatsApp pelanggan (khusus channel WhatsApp)
URL Resend InvoiceGET…/waba/resendKirim ulang bukti bayar dari tabel riwayat (khusus channel WhatsApp)

Aturan umum

  • Balas dengan header Content-Type: application/json. Respons non-JSON ditampilkan ke agen sebagai teks mentah.
  • Kirim semua nilai sebagai string, termasuk angka: "113000", bukan 113000. Nilai uang di endpoint tagihan berupa digit polos tanpa titik ribuan. Cloud sendiri yang memformat Rupiah.
  • Gunakan HTTP 200 untuk semua jawaban yang valid, termasuk "data tidak ditemukan". Status hasil dibedakan lewat field code di dalam JSON.
  • Kirim pesan yang bisa dibaca manusia di field result. Cloud menampilkan isinya apa adanya ke agen saat terjadi error.
  • Kredensial dikirim sebagai query parameter (api_user, api_key) pada GET dan sebagai field JSON pada POST. Lihat catatan keamanan di bagian Checklist.

Nilai field code

codeArtiContoh result dari Jembrana
"200"Berhasil. Untuk tagihan: masih ada rekening yang belum lunas.REKENING YANG BELUM DILUNASI ADALAH BULAN OKTOBER 2026
"300"Tagihan: semua rekening sudah lunas. Data rekening terakhir tetap dikirim lengkap dengan tanggal lunas.SELURUH REKENING TAGIHAN AIR TELAH LUNAS !
"350"Tagihan: nomor sambungan tidak dikenal atau tagihan bulan ini belum terbit.Tagihan dengan No. Sambungan 99999999 Belum Muncul !
"400"Pencarian pelanggan tidak menemukan data.DATA BY (CAT = NAME, KEYWORD = …, AREA = ALL) NOT FOUND !

Rumus tagihan

Rumus ini diturunkan dari data asli Jembrana dan harus dipatuhi oleh PDAM lain agar rincian di email dan chat cocok sampai rupiah terakhir.

jumlah = air + b_adm + b_dmeter + ppn
total = jumlah + denda + adm_bank
total_xxx = penjumlahan field xxx dari semua rekening
total_jumlah = Σ jumlah
grand_total = Σ total

Contoh nyata, sambungan dengan 2 rekening menunggak (data lengkap di sampel 3):

Periodeairb_admb_dmeterppnjumlahdendaadm_banktotal
DESEMBER 2017247.5003.00021.5002.450274.450250.0000524.450
JANUARI 201847.4003.00021.5002.45074.35035.0000109.350
Ringkasan294.9006.00043.0004.900348.800285.0000633.800

Komponen biaya tambahan boleh ditambahkan sebagai field angka baru di tiap rekening (misalnya b_limbah). Cloud otomatis menampilkannya dengan label dari nama field. Field total ringkasannya diberi awalan total_ (contoh total_b_limbah).

GET

Cek tagihan

URL Tagihan

Mengembalikan data pelanggan dan semua rekening yang belum lunas untuk satu nomor sambungan. Jika semua sudah lunas, kirim rekening terakhir beserta tanggal lunas dan "lunas": "true".

Request

ParameterStatusKeterangan
nosamWAJIBNomor sambungan pelanggan.
api_userWAJIBDiisi Cloud dari kolom API User.
api_keyWAJIBDiisi Cloud dari kolom API Key.
Contoh request · shell
curl -s "https://pdam-anda.example/api/check?nosam=100140&api_user=ACC-XXXX&api_key=XXXX"

Field respons: pelanggan

FieldStatusContohKeterangan
codeWAJIB"200"Lihat tabel nilai code.
resultWAJIBREKENING YANG BELUM…Kalimat status, tampil di email dan chat.
nosamWAJIB"100140"Tanpa nosam dan rekening, Cloud menganggap tagihan tidak ditemukan.
namaWAJIBI MADE CONTOHNama pelanggan.
rekeningWAJIBarrayDaftar rekening. Boleh kosong hanya jika code bukan 200/300.
lunasWAJIB"false"String "true" atau "false". Menentukan label LUNAS / BELUM LUNAS.
alamatDISARANKANJl. Contoh No. 1
kode_gol, golDISARANKANRT3, RUMAH TANGGA 3Digabung menjadi "RT3 - RUMAH TANGGA 3".
kode_area, areaDISARANKAN101, NEGARA-01
diameterDISARANKAN"0.50"Dalam inci. Cloud menambahkan tanda ".
stsDISARANKANAKTIF, CABUTStatus sambungan.
taDISARANKANNORMALKondisi meter.
total_air, total_badm, total_bdmeter, total_ppn, total_denda, total_bankDISARANKAN"98000"Jika tidak dikirim, Cloud menjumlahkan sendiri dari rekening.
total_jumlah, grand_totalDISARANKAN"113000"grand_total adalah angka "Total yang harus dibayar".
total_rekeningDISARANKAN"1"
terbilangDISARANKANSeratus Tiga Belas RibuCloud menambahkan kata "Rupiah".
keteranganDISARANKANBULAN OKTOBER 2026
lpd, lokasi, koordinat, latitude, longitudeOPSIONAL-8.3500,114.6100Dikirim Jembrana, belum dipakai Cloud.

Field respons: tiap item rekening[]

FieldStatusContohKeterangan
bulan, tahunWAJIBOKTOBER, 2026Periode rekening.
airWAJIB"98000"Harga air.
b_admWAJIB"3000"Biaya administrasi.
b_dmeterWAJIB"12000"Dana meter.
ppn, denda, adm_bankWAJIB"0"Kirim "0" jika tidak ada, jangan dihilangkan.
jumlahWAJIB"113000"Lihat rumus.
totalWAJIB"113000"Lihat rumus.
jatuh_tempoWAJIB20 Oktober 2026Teks bebas, tampil apa adanya.
no_rekeningDISARANKAN"261000000"
mtr_lalu, mtr_skrng, kubikasiDISARANKAN1462, 1483, 21Stand meter dan pemakaian m³.
tgl_lunas, jam_lunasJIKA LUNAS05 OKT 2026, 11:15:12Jika ada, rekening ditandai lunas.
kode_transaksi, operatorJIKA LUNASKOLEKTIF LPDTempat pembayaran.
noOPSIONAL"1"Nomor urut.

Contoh respons

1 · Satu rekening belum lunas (code 200) · tagihan-belum-lunas.json
{
  "nosam": "100140",
  "kode_area": "101",
  "area": "NEGARA-01",
  "nama": "I MADE CONTOH",
  "alamat": "Jl. Contoh No. 1",
  "kode_gol": "RT3",
  "gol": "RUMAH TANGGA 3",
  "lpd": "LPD CONTOH",
  "diameter": "0.50",
  "lokasi": "-8.3500,114.6100",
  "koordinat": "-8.3500,114.6100",
  "latitude": "-8.3500",
  "longitude": "114.6100",
  "ta": "NORMAL",
  "sts": "AKTIF",
  "rekening": [
    {
      "no": "1",
      "no_rekening": "261000000",
      "bulan": "OKTOBER",
      "tahun": "2026",
      "mtr_lalu": "1462",
      "mtr_skrng": "1483",
      "kubikasi": "21",
      "b_adm": "3000",
      "b_dmeter": "12000",
      "ppn": "0",
      "air": "98000",
      "denda": "0",
      "adm_bank": "0",
      "jumlah": "113000",
      "jatuh_tempo": "20 Oktober 2026",
      "total": "113000"
    }
  ],
  "total_badm": "3000",
  "total_bdmeter": "12000",
  "total_ppn": "0",
  "total_air": "98000",
  "total_denda": "0",
  "total_bank": "0",
  "total_jumlah": "113000",
  "grand_total": "113000",
  "total_rekening": "1",
  "terbilang": "Seratus Tiga Belas Ribu ",
  "keterangan": "BULAN OKTOBER 2026",
  "result": "REKENING YANG BELUM DILUNASI ADALAH BULAN OKTOBER 2026",
  "lunas": "false",
  "code": "200"
}
2 · Sudah lunas, dibayar lewat LPD dengan admin bank (code 300) · tagihan-lunas.json
{
  "nosam": "100315",
  "kode_area": "101",
  "area": "NEGARA-01",
  "nama": "NI LUH SAMPEL",
  "alamat": "Jl. Sampel Gg. II No. 7",
  "kode_gol": "RT3",
  "gol": "RUMAH TANGGA 3",
  "lpd": "",
  "diameter": "0.50",
  "lokasi": "-8.3560,114.6200",
  "koordinat": "-8.3560,114.6200",
  "latitude": "-8.3560",
  "longitude": "114.6200",
  "ta": "NORMAL",
  "sts": "AKTIF",
  "rekening": [
    {
      "no": "1",
      "no_rekening": "261001000",
      "kode_transaksi": "00001/PDAM.TEL/X/2026",
      "bulan": "OKTOBER",
      "tahun": "2026",
      "mtr_lalu": "4804",
      "mtr_skrng": "4863",
      "kubikasi": "59",
      "b_adm": "3000",
      "b_dmeter": "12000",
      "ppn": "0",
      "air": "307000",
      "denda": "0",
      "adm_bank": "2500",
      "jumlah": "322000",
      "jatuh_tempo": "20 Oktober 2026",
      "total": "324500",
      "tgl_lunas": "05 OKT 2026",
      "jam_lunas": "11:15:12",
      "operator": "KOLEKTIF LPD"
    }
  ],
  "total_badm": "3000",
  "total_bdmeter": "12000",
  "total_ppn": "0",
  "total_air": "307000",
  "total_denda": "0",
  "total_bank": "2500",
  "total_jumlah": "322000",
  "grand_total": "324500",
  "total_rekening": "1",
  "terbilang": "Tiga Ratus Dua Puluh Empat Ribu Lima Ratus",
  "keterangan": "BULAN OKTOBER 2026",
  "lunas": "true",
  "result": "SELURUH REKENING TAGIHAN AIR TELAH LUNAS !",
  "code": "300"
}
3 · Dua rekening menunggak dengan denda (code 200) · tagihan-dua-bulan-denda.json
{
  "nosam": "100393",
  "kode_area": "101",
  "area": "NEGARA-01",
  "nama": "KETUT PERCOBAAN",
  "alamat": "Jl. Percobaan No. 12",
  "kode_gol": "RT",
  "gol": "RUMAH TANGGA 1",
  "lpd": "LPD CONTOH",
  "diameter": "0.75",
  "lokasi": "-8.3600,114.6170",
  "koordinat": "-8.3600,114.6170",
  "latitude": "",
  "longitude": "",
  "ta": "NORMAL",
  "sts": "CABUT",
  "rekening": [
    {
      "no": "1",
      "no_rekening": "462199",
      "bulan": "DESEMBER",
      "tahun": "2017",
      "mtr_lalu": "2528",
      "mtr_skrng": "2589",
      "kubikasi": "61",
      "b_adm": "3000",
      "b_dmeter": "21500",
      "ppn": "2450",
      "air": "247500",
      "denda": "250000",
      "adm_bank": "0",
      "jumlah": "274450",
      "jatuh_tempo": "20 Desember 2017",
      "total": "524450"
    },
    {
      "no": "2",
      "no_rekening": "484686",
      "bulan": "JANUARI",
      "tahun": "2018",
      "mtr_lalu": "2589",
      "mtr_skrng": "2605",
      "kubikasi": "16",
      "b_adm": "3000",
      "b_dmeter": "21500",
      "ppn": "2450",
      "air": "47400",
      "denda": "35000",
      "adm_bank": "0",
      "jumlah": "74350",
      "jatuh_tempo": "22 Januari 2018",
      "total": "109350"
    }
  ],
  "total_badm": "6000",
  "total_bdmeter": "43000",
  "total_ppn": "4900",
  "total_air": "294900",
  "total_denda": "285000",
  "total_bank": "0",
  "total_jumlah": "348800",
  "grand_total": "633800",
  "total_rekening": "2",
  "terbilang": "Enam Ratus Tiga Puluh Tiga Ribu Delapan Ratus",
  "keterangan": "BULAN DESEMBER 2017 DAN BULAN JANUARI 2018",
  "result": "REKENING YANG BELUM DILUNASI ADALAH BULAN DESEMBER 2017 DAN BULAN JANUARI 2018",
  "lunas": "false",
  "code": "200"
}
4 · Nomor sambungan tidak dikenal (code 350) · tagihan-tidak-ditemukan.json
{
  "result": "Tagihan dengan No. Sambungan 99999999 Belum Muncul !",
  "code": "350"
}
GET

Cari pelanggan

URL Customer

Agen mencari nomor sambungan berdasarkan nama atau alamat. Hasil ditampilkan sebagai tabel dengan tombol salin nomor sambungan.

Request

ParameterStatusKeterangan
catWAJIBname atau address.
keywordWAJIBKata kunci, dicocokkan sebagian (LIKE).
areaWAJIBKode area (misalnya 101) atau all.
api_user, api_keyBELUM DIKIRIMSaat ini Cloud tidak mengirim kredensial untuk endpoint ini. Lihat catatan di bawah.
Contoh request · shell
curl -s "https://pdam-anda.example/api/customer?cat=name&keyword=contoh&area=all"

Field respons

FieldStatusKeterangan
codeWAJIBHanya "200" yang dianggap berhasil. Selain itu isi result tampil sebagai error.
pelanggan[]WAJIBArray hasil pencarian.
pelanggan[].nosam, .namaWAJIB
pelanggan[].alamat, .golongan, .area, .statusDISARANKANTeks siap tampil, misalnya "RUMAH TANGGA 3 (RT3)" dan "NEGARA-01 (101)".
pelanggan[].noOPSIONALCloud membuat nomor urut sendiri.

Catatan kode area. Pilihan area di Chats saat ini masih tertulis tetap untuk wilayah Jembrana (Negara 101–110, Melaya 201–213, Pekutatan 301–307, Mendoyo 401–407). PDAM lain tetap bisa memakai all. Jika PDAM baru butuh daftar areanya sendiri, daftar itu perlu dibuat bisa diatur per PDAM di Cloud.

Contoh respons

Ditemukan (dipotong menjadi 3 dari 56 baris) · customer-search.json
{
  "pelanggan": [
    {
      "no": "1",
      "nosam": "100140",
      "nama": "I MADE CONTOH",
      "alamat": "Jl. Contoh No. 1",
      "golongan": "RUMAH TANGGA 3 (RT3)",
      "area": "NEGARA-01 (101)",
      "status": "Normal"
    },
    {
      "no": "2",
      "nosam": "100315",
      "nama": "NI LUH SAMPEL",
      "alamat": "Jl. Sampel Gg. II No. 7",
      "golongan": "RUMAH TANGGA 3 (RT3)",
      "area": "NEGARA-01 (101)",
      "status": "Normal"
    },
    {
      "no": "3",
      "nosam": "100393",
      "nama": "KETUT PERCOBAAN",
      "alamat": "Jl. Percobaan No. 12",
      "golongan": "RUMAH TANGGA 3 (RT3)",
      "area": "NEGARA-01 (101)",
      "status": "Cabut"
    }
  ],
  "code": "200"
}
Tidak ditemukan (code 400) · customer-search-tidak-ditemukan.json
{
  "result": "DATA BY (CAT = NAME, KEYWORD = CONTOH, AREA = ALL) NOT FOUND !",
  "code": "400"
}
GET

Riwayat pembayaran

URL History

Daftar pembayaran yang sudah lunas untuk satu nomor sambungan, terbaru lebih dulu. Format Jembrana memakai objek dengan kunci angka ("0", "1", …) ditambah code dan result. Cloud mengurutkan baris menurut kunci angka itu.

Request

ParameterStatusKeterangan
nosamWAJIBNomor sambungan.
api_user, api_keyWAJIB
Contoh request · shell
curl -s "https://pdam-anda.example/api/history?nosam=100140&api_user=ACC-XXXX&api_key=XXXX"

Field tiap baris

FieldStatusContohKeterangan
bulan, tahunWAJIBSep, 2026Periode, tampil di tabel.
tagihanWAJIB"113.000"Teks siap tampil (dengan titik ribuan).
tgl_lunasWAJIB20 SEP 2026
bln_rek, thn_rek, bln_dt, thn_dtWAJIB9, 2026, 09, 2026Dikirim balik apa adanya ke endpoint Resend. Bulan/tahun rekening dan bulan/tahun data.
tipeWAJIBvendor, kasirKanal pembayaran. Juga dikirim balik ke Resend.
kode_transaksiDISARANKAN00001/PDAM.BRI/IX/2026
gol, stand, kubikasiDISARANKANRT3, 1.441 - 1.462, 21

Contoh respons

Ada riwayat (dipotong menjadi 3 dari 92 baris) · history.json
{
  "0": {
    "kode_transaksi": "00001/PDAM.BRI/IX/2026",
    "bulan": "Sep",
    "tahun": "2026",
    "gol": "RT3",
    "stand": "1.441 - 1.462",
    "kubikasi": "21",
    "tagihan": "113.000",
    "tgl_lunas": "20 SEP 2026",
    "tipe": "vendor",
    "bln_rek": "9",
    "thn_rek": "2026",
    "bln_dt": "09",
    "thn_dt": "2026"
  },
  "1": {
    "kode_transaksi": "00002/PDAM.BRI/VIII/2026",
    "bulan": "Agu",
    "tahun": "2026",
    "gol": "RT3",
    "stand": "1.420 - 1.441",
    "kubikasi": "21",
    "tagihan": "113.000",
    "tgl_lunas": "18 AUG 2026",
    "tipe": "vendor",
    "bln_rek": "8",
    "thn_rek": "2026",
    "bln_dt": "08",
    "thn_dt": "2026"
  },
  "2": {
    "kode_transaksi": "KSR002026",
    "bulan": "Apr",
    "tahun": "2026",
    "gol": "RT3",
    "stand": "1.312 - 1.350",
    "kubikasi": "38",
    "tagihan": "206.500",
    "tgl_lunas": "18 APR 2026",
    "tipe": "kasir",
    "bln_rek": "4",
    "thn_rek": "2026",
    "bln_dt": "04",
    "thn_dt": "2026"
  },
  "code": "200",
  "result": "success"
}
Tidak ada riwayat: array kosong · history-kosong.json
[]
POST

Kirim invoice

URL Invoice

Cloud meminta server PDAM mengirim tagihan ke nomor WhatsApp pelanggan. Hanya dipakai untuk channel WhatsApp. Channel Telegram, LINE, Messenger, Instagram, dan Live Chat menerima tagihan langsung dari Cloud lewat endpoint Cek Tagihan.

Bukan dari data asli. Endpoint ini mengirim WhatsApp sungguhan, jadi tidak dipanggil saat menyusun dokumen ini. Bentuk request di bawah sama persis dengan yang dikirim Cloud. Contoh respons adalah bentuk minimal yang diterima Cloud.

Request body (JSON)

FieldStatusKeterangan
no_customerWAJIBNomor sambungan.
phone_numberWAJIBNomor WhatsApp pelanggan dari percakapan, format 62….
name_instanceDISARANKANNama channel WhatsApp di Cloud, untuk memilih nomor pengirim.
api_user, api_keyWAJIB
Request body · invoice-request.json
{
  "no_customer": "100140",
  "phone_number": "6281234567890",
  "name_instance": "CS PDAM Contoh",
  "api_user": "ACC-XXXXXXXX-XXXX-XXXX",
  "api_key": "xxxxxxxxxxxxxxxxxxxxxx"
}
Respons berhasil: code harus "200" · invoice-response-sukses.json
{
  "code": "200",
  "result": "Invoice No. Sambungan 100140 berhasil dikirim ke 6281234567890"
}
Respons gagal: pesan diambil dari error, lalu message · invoice-response-gagal.json
{
  "code": "422",
  "error": "Nomor WhatsApp tidak valid"
}
GET

Kirim ulang bukti bayar

URL Resend Invoice

Dipanggil dari tombol kirim pada tabel Riwayat. Nilai periode dan tipe diambil dari baris riwayat yang dipilih. Sama seperti Kirim Invoice, endpoint ini mengirim WhatsApp sungguhan dan tidak dipanggil saat menyusun dokumen.

ParameterStatusSumber
nosamWAJIBInput agen.
bln_rek, thn_rek, bln_dt, thn_dt, tipeWAJIBDari baris riwayat.
no_waWAJIBNomor WhatsApp dari percakapan.
channelDISARANKANNama channel WhatsApp di Cloud.
api_user, api_keyWAJIB
Contoh request · shell
curl -s "https://pdam-anda.example/api/resend?nosam=100140&bln_dt=09&thn_dt=2026&bln_rek=9&thn_rek=2026&tipe=vendor&no_wa=6281234567890&channel=CS%20PDAM%20Contoh&api_user=ACC-XXXX&api_key=XXXX"
Respons berhasil: code "200", result tampil ke agen · resend-response-sukses.json
{
  "code": "200",
  "result": "Bukti pembayaran Sep 2026 berhasil dikirim ulang"
}

Checklist PDAM baru

  • Kelima URL bisa diakses dari server Cloud lewat HTTPS dan menjawab dalam 15 detik.
  • Semua nilai berupa string, uang tanpa titik ribuan di endpoint tagihan.
  • jumlah dan total mengikuti rumus. Komponen yang nol tetap dikirim sebagai "0".
  • "Tidak ditemukan" dijawab HTTP 200 dengan code dan result, bukan HTTP 404/500.
  • Kredensial benar-benar divalidasi. Server PDAM harus menolak api_user/api_key yang salah dengan {"code": "401", "result": "API key tidak valid"}, karena data pelanggan adalah data pribadi.
  • Tambahkan PDAM di Settings → PDAM (URL Tagihan wajib, URL lain bisa menyusul), lalu klik tombol tes (ikon petir) dengan satu nomor sambungan asli. Hasil tes menampilkan status HTTP, waktu respons, dan nama pelanggan.
  • Pilih PDAM tersebut untuk channel yang dipakai di tabel "PDAM per channel", lalu coba Cek Tagihan dari Chats.

File sampel

Semua contoh di atas juga tersimpan sebagai file JSON di server Cloud, siap dipakai sebagai fixture saat membangun atau menguji API PDAM baru:

FileIsiSumber
tagihan-belum-lunas.json1 · Satu rekening belum lunas (code 200)API Jembrana (dianonimkan)
tagihan-lunas.json2 · Sudah lunas, dibayar lewat LPD dengan admin bank (code 300)API Jembrana (dianonimkan)
tagihan-dua-bulan-denda.json3 · Dua rekening menunggak dengan denda (code 200)API Jembrana (dianonimkan)
tagihan-tidak-ditemukan.json4 · Nomor sambungan tidak dikenal (code 350)API Jembrana (dianonimkan)
customer-search.jsonDitemukan (dipotong menjadi 3 dari 56 baris)API Jembrana (dianonimkan)
customer-search-tidak-ditemukan.jsonTidak ditemukan (code 400)API Jembrana (dianonimkan)
history.jsonAda riwayat (dipotong menjadi 3 dari 92 baris)API Jembrana (dianonimkan)
history-kosong.jsonTidak ada riwayat: array kosongAPI Jembrana (dianonimkan)
invoice-request.jsonRequest bodyContoh bentuk (bukan data live)
invoice-response-sukses.jsonRespons berhasil: code harus "200"Contoh bentuk (bukan data live)
invoice-response-gagal.jsonRespons gagal: pesan diambil dari error, lalu messageContoh bentuk (bukan data live)
resend-response-sukses.jsonRespons berhasil: code "200", result tampil ke agenContoh bentuk (bukan data live)

Lokasi di server Cloud: docs/pdam-api/samples/ (minta ke tim Cybersoft)