Native Message: Saldo, Inquiry QRIS & E-Wallet
{BASE_URL}/native/message adalah halaman WebView tanpa tampilan. Native mengirim permintaan lewat postMessage, halaman mengerjakannya di server, lalu membalas ke native. Halaman ini hanya untuk data baca-saja: tidak ada pembayaran, transfer, atau PIN di sini.
Type yang Tersedia
| Type | Body | Isi data balasan |
|---|---|---|
| GETBALANCE | {} | Saldo QoinCash user. |
| GETINQUIRYQRIS | { qrvalue } | Data inquiry QRIS untuk pembayaran. |
| GETWALLETLIST | {} | Daftar e-wallet (grup produk). |
| GETWALLETDENOM | { walletType } | Daftar nominal untuk satu e-wallet. |
| GETWALLETINQUIRY | { phoneNumber, code } | Inquiry top up e-wallet (nama pemilik, nominal, biaya admin). |
| GETPHONECREDITDENOM | { phoneNumber, kind? } | Daftar nominal pulsa / paket data (provider, produk, productsToken). |
| GETPHONECREDITINQUIRY | { phoneNumber, kind?, code, productsToken } | Inquiry pulsa / paket data (nominal, biaya admin, inquiryToken). |
| GETHISTORYTRANSACTION | { page?, size? } | Riwayat transaksi QoinCash per halaman (default page 1, size 5; size maksimal 25). |
1. Cara Memanggil
- Muat WebView (boleh headless, misalnya
HeadlessInAppWebView) ke{BASE_URL}/native/message. Cookie store dan penyimpanan lokal harus sama dengan WebView yang terlihat (di iOS jangan pakaiWKWebsiteDataStore.nonPersistent()), kalau tidak sesi tidak terbaca. - Setelah halaman dimuat, kirim satu permintaan
postMessage(JSON string). Ulangi kirim tiap ±500 ms sampai balasan datang. - Tangkap balasan lewat bridge native. Begitu diterima, hentikan WebView tersebut.
// Format umum: { type, body }. TIDAK perlu mengirim Signature.
window.postMessage(JSON.stringify({ type: "GETBALANCE", body: {} }), "*");
window.postMessage(JSON.stringify({ type: "GETINQUIRYQRIS", body: { qrvalue: "<string QRIS>" } }), "*");
window.postMessage(JSON.stringify({ type: "GETWALLETLIST", body: {} }), "*");
window.postMessage(JSON.stringify({ type: "GETWALLETDENOM", body: { walletType: "DANA" } }), "*");
window.postMessage(JSON.stringify({ type: "GETWALLETINQUIRY", body: { phoneNumber: "085777142098", code: "DANA10H" } }), "*");
window.postMessage(JSON.stringify({ type: "GETPHONECREDITDENOM", body: { phoneNumber: "081234567890", kind: "pulsa" } }), "*");
window.postMessage(JSON.stringify({ type: "GETPHONECREDITINQUIRY", body: { phoneNumber: "081234567890", kind: "pulsa", code: "TSEL10", productsToken: "<token>" } }), "*");
window.postMessage(JSON.stringify({ type: "GETHISTORYTRANSACTION", body: { page: 1, size: 5 } }), "*"); // page & size opsional (default 1 dan 5)body.Signature, nilainya diabaikan (permintaan tetap diproses). Jika penyimpanan tidak berisi Signature, artinya perangkat belum pernah aktivasi: halaman langsung membalas 401 tanpa memanggil API apa pun.close. Native yang memutuskan kapan WebView ditutup. Halaman tetap hidup dan boleh menerima permintaan berikutnya. Permintaan bertipe sama yang sedang berjalan akan diabaikan, jadi aman mengirim ulang tiap 500 ms.2. Format Balasan
{
"type": "GETBALANCE",
"code": 200,
"message": "Berhasil mengambil saldo",
"data": { "amount": 150000, "grossAmount": 160000, "monthlyTotal": 1120000, "hasIdrAsset": true }
}| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| 200 | number | Opsional | Sukses. Data ada di properti data. |
| 400 | number | Opsional | Permintaan tidak valid: type tidak didukung, body bukan objek, atau field wajib (qrvalue, walletType, phoneNumber, code) kosong/tidak valid. Dicek lebih dulu dan tidak memanggil API. |
| 401 | number | Opsional | Belum aktivasi (tidak ada Signature di penyimpanan, tanpa panggilan API) atau sesi tidak bisa dipakai. Buka WebView biasa ke / untuk aktivasi. |
| 403 | number | Opsional | Sesi habis tetapi akun sudah pernah aktivasi: minta user memasukkan PIN lewat WebView biasa. (GETINQUIRYQRIS hanya mengenal 401.) |
| 500 | number | Opsional | Kesalahan sistem atau penyedia layanan. Pesan ada di message. |
| 0 | number | Opsional | Jaringan terputus. |
Tipe di luar daftar dibalas code 400 dengan type yang sama (huruf besar, angka, dan garis bawah saja), atau UNKNOWN.
3. GETBALANCE
Mengambil saldo QoinCash user. Body kosong. Saldo ditentukan oleh sesi login (JWT), bukan Signature. Aktivasi ulang mereset sesi, sehingga permintaan berikutnya mendapat 401 atau 403.
{ "amount": 150000, "grossAmount": 160000, "monthlyTotal": 1120000, "hasIdrAsset": true }4. GETINQUIRYQRIS
Memvalidasi string QRIS (hasil scan native) dan mengembalikan data yang dibutuhkan untuk membayar. Ini hanya inquiry, tidak ada pembayaran. Hasilnya dipakai pada halaman pembayaran QRIS.
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| qrvalue | string | Wajib | Isi QR QRIS (payload EMVCo) apa adanya, maksimal 1024 karakter. Nama kunci tidak peka huruf besar/kecil (qrValue, QRValue juga diterima). Contoh: 00020101021126610014COM.GO-JEK.WWW0118936009143055035934... |
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| PaymentId | string | Wajib | ID pembayaran dari inquiry. |
| ReferenceNumber | string | Wajib | Nomor referensi dari inquiry. Hanya bisa dipakai sekali. |
| AccountName | string | Opsional | Nama merchant. |
| Amount | string | Wajib | Nominal dari QR. "0" untuk QR statis (nominal diisi native); selain itu nominal sudah ditentukan QR. Contoh: "1000" |
| TipAmount | string | Wajib | Tip dari inquiry ("0" bila tidak ada). |
| TerminalId | string | Wajib | ID terminal merchant. |
| TicketId | string | Opsional | ID tiket inquiry. |
| inquiryToken | string | Opsional | Token buram dari server yang mengunci PaymentId, ReferenceNumber, merchant, dan nominal QR dinamis. Teruskan apa adanya ke /payment/qris. Akan menjadi wajib (lihat Bayar QRIS dari Native). |
inquiryToken, productsToken, dan token lain dari halaman ini adalah string buram (opaque). Simpan dan teruskan apa adanya; jangan memeriksa awalan, jumlah titik, atau panjangnya, karena formatnya bisa berubah tanpa pemberitahuan./native/message: PIN wajib diketik di WebView yang terlihat dan tidak pernah dikirim lewat postMessage.5. E-Wallet: GETWALLETLIST, GETWALLETDENOM, GETWALLETINQUIRY
Tiga type berurutan untuk menyiapkan top up e-wallet: ambil daftar e-wallet, pilih nominal, lalu inquiry nomor tujuan. Seluruhnya baca-saja. Eksekusi pembayaran tidak tersedia lewat halaman ini.
GETWALLETLIST
Tanpa body. Balasan data.groups berisi daftar e-wallet; nilai pGroup dipakai sebagai walletType. Daftarnya diteruskan apa adanya (tidak ada penyaringan provider seperti di layar Top Up).
{ "groups": [ { "pGroup": "DANA" }, { "pGroup": "OVO" } ] }GETWALLETDENOM
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| walletType | string | Wajib | Nilai pGroup dari GETWALLETLIST. Huruf atau angka di awal, lalu huruf, angka, spasi, titik, garis bawah, & atau tanda hubung; maksimal 64 karakter. Nama kunci tidak peka huruf besar/kecil. Contoh: DANA |
Balasan data.products berisi nominal untuk e-wallet itu (urutan mentah dari server). Nilai pCode dipakai sebagai code pada GETWALLETINQUIRY.
{ "products": [ { "pCode": "DANA10H", "pDenom": "10000", "pPrice": "10500" } ] }GETWALLETINQUIRY
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| phoneNumber | string | number | Wajib | Nomor HP tujuan top up. Hanya digit yang dipakai; awalan 62 atau 0 dibuang lalu dibentuk menjadi 08…, dan harus 10–15 digit. +62 857-7714-2098, 6285777142098, dan 085777142098 dianggap sama. Contoh: 085777142098 |
| code | string | Wajib | Kode produk (pCode) dari GETWALLETDENOM. Huruf atau angka di awal, lalu huruf, angka, titik, garis bawah, & atau tanda hubung (tanpa spasi); maksimal 64 karakter. Contoh: DANA10H |
{ "custNumber": "085777142098", "custName": "…", "productCode": "DANA10H", "productDesc": "…", "amount": 10000, "adminFee": 500, "period": "0", "freeTexts": [], "inquiryToken": "<token>" }data.inquiryToken adalah token tersegel yang dipakai saat pembayaran. Teruskan apa adanya ke WebView /payment/ewallet(lihat Bayar E-Wallet dari Native); jangan diubah. Token terikat ke akun user dan berlaku singkat (±5 menit). Jika inquiry sukses tetapi token tidak tersedia, balasannya code 500, bukan 200.6. Pulsa & Paket Data: GETPHONECREDITDENOM, GETPHONECREDITINQUIRY
Dua type berurutan untuk menyiapkan pembelian pulsa & paket data dari native: ambil daftar nominal sesuai operator nomor HP, lalu inquiry sebelum pembayaran. Operator dideteksi otomatis oleh server dari prefix nomor HP dan dikembalikan sebagai data.provider.
GETPHONECREDITDENOM
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| phoneNumber | string | number | Wajib | Nomor HP tujuan. Digit saja, awalan 62 atau 0 dinormalkan menjadi 08… (10–15 digit). Contoh: 081234567890 |
| kind | string | Opsional | Jenis produk: "pulsa" atau "data". Default "pulsa" bila tidak dikirim. Nilai lain ditolak 400. Contoh: "pulsa" |
Balasan data.products memuat daftar nominal operator tersebut, dan data.productsToken adalah token allowlist produk yang WAJIB dikirimkan kembali ke GETPHONECREDITINQUIRY.
{
"provider": "TELKOMSEL",
"products": [
{ "pCode": "TSEL10", "pName": "Telkomsel 10.000", "pPrice": 11000, "pGroup": "TELKOMSEL" }
],
"productsToken": "<token>"
}GETPHONECREDITINQUIRY
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| phoneNumber | string | number | Wajib | Nomor HP tujuan (10–15 digit). Contoh: 081234567890 |
| kind | string | Opsional | Jenis produk ("pulsa" atau "data"). Default "pulsa". Contoh: "pulsa" |
| code | string | Wajib | Kode produk (pCode) yang dipilih dari daftar DENOM. Contoh: TSEL10 |
| productsToken | string | Wajib | Token tersegel dari balasan GETPHONECREDITDENOM (data.productsToken). Contoh: <token> |
{
"custNumber": "081234567890",
"custName": "",
"productCode": "TSEL10",
"productDesc": "Telkomsel 10.000",
"amount": 10000,
"adminFee": 1000,
"period": "0",
"freeTexts": [],
"inquiryToken": "<token>"
}data.inquiryToken diteruskan ke WebView /payment/phonecredit (lihat Bayar Pulsa & Paket Data dari Native). Jika token nominal kedaluwarsa (> 5 menit), server mengembalikan code 410 ("Daftar nominal sudah tidak berlaku"); jika kode produk tidak tersedia untuk operator tersebut, dikembalikan code 422.7. Riwayat: GETHISTORYTRANSACTION
Mengambil riwayat transaksi QoinCash user per halaman. Baca-saja. Memakai data yang sama dengan layar Riwayat di WebView.
| Parameter | Tipe Data | Status | Deskripsi & Contoh |
|---|---|---|---|
| page | number | Opsional | Nomor halaman, bilangan bulat mulai dari 1. Angka atau string digit saja ("2"). Tidak dikirim atau null = 1. Contoh: 1 |
| size | number | Opsional | Jumlah item per halaman, bilangan bulat 1 sampai 25. Tidak dikirim atau null = 5. Lebih dari 25 ditolak langsung dengan code 400 dan pesan, tanpa memanggil API. Contoh: 5 |
{
"items": [
{
"trxId": "…", "trxReceipt": "…", "trxProductName": "…",
"trxCategory": "payment", "trxCategoryLabel": "…",
"trxAmount": 10000, "trxDirection": "D",
"trxDate": "…", "trxStatus": 1, "trxStatusString": "…"
}
],
"pagination": { "page": 1, "pageSize": 5, "totalPage": 3, "totalRecord": 27 }
}pagination.totalPage untuk tahu halaman terakhir. User tanpa transaksi dijawab code 200 dengan items kosong. Kirim satu permintaan per halaman; permintaan GETHISTORYTRANSACTION yang masih berjalan akan mengabaikan permintaan berikutnya.