DEWA OTP API v1.0.0

Base URL https://dewaotp.top/api · Autentikasi: cookie otp_token (JWT httpOnly)

Dokumentasi API dewaotp.top (brand: DEWA OTP), toko nomor virtual / OTP.

Semua endpoint berada di bawah satu catch-all route Next.js sehingga setiap path diawali /api. Autentikasi memakai JWT di cookie httpOnly bernama otp_token; tidak ada Bearer token. Klien non-browser harus mengirim cookie tersebut sendiri.

Alur utama:
1. POST /auth/register atau POST /auth/login, cookie otp_token terpasang
2. POST /deposits membuat tagihan QRIS BoomPay beserta qrPayload untuk dirender menjadi QR
3. Pembeli membayar; status berubah PAID otomatis lewat webhook BoomPay (atau POST /deposits/{id}/check-status bila webhook belum terdaftar)
4. POST /orders membeli nomor; POST /orders/{id}/poll mengambil kode OTP

Catatan uang: saldo wallet disimpan dalam USD, tetapi semua angka yang dilihat pengguna ditampilkan dalam Rupiah memakai kurs efektif platform (GET /exchange-rate). Nominal yang ditagih QRIS = harga order + fee + kode unik dari gateway, sehingga bisa berbeda beberapa rupiah dari perhitungan fee internal (feeInfo.totalAmount hanya perkiraan).

Semua endpoint (47)

Detail endpoint

GET /

Health check

Grup: Publik · Autentikasi: Publik (tanpa login)

Respons

KodeArtiSkema
200API hidupobject

GET /exchange-rate

Kurs USD ke IDR yang dipakai platform

Rate sudah termasuk spread platform; dipakai untuk menampilkan saldo dan harga dalam Rupiah.

Grup: Publik · Autentikasi: Publik (tanpa login)

Respons

KodeArtiSkema
200Kurs aktifExchangeRate

GET /qris-fee-info

Konfigurasi biaya QRIS (untuk tampilan)

Grup: Publik · Autentikasi: Publik (tanpa login)

Respons

KodeArtiSkema
200Konfigurasi biayaQrisFeeInfo

POST /auth/register

Registrasi akun baru

Password minimal 8 karakter. Cookie sesi langsung dipasang bila berhasil.

Grup: Auth · Autentikasi: Publik (tanpa login)

Body permintaan

FieldTipeKeterangan
fullName wajibstring Budi Santoso
email wajibstring · email
password wajibstring

Respons

KodeArtiSkema
200Akun dibuatobject
400Permintaan tidak validError

POST /auth/login

Login

Mengembalikan Set-Cookie otp_token (httpOnly, sameSite=lax). remember=true memperpanjang sesi menjadi 30 hari, default 7 hari.

Grup: Auth · Autentikasi: Publik (tanpa login)

Body permintaan

FieldTipeKeterangan
email wajibstring · email
password wajibstring
rememberboolean

Respons

KodeArtiSkema
200Berhasilobject
401Email atau password salahError

POST /auth/logout

Logout (hapus cookie sesi)

Grup: Auth · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

GET /auth/me

Data pengguna yang sedang login

Grup: Auth · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
401Belum loginError

POST /auth/forgot-password

Minta tautan reset password

Selalu menjawab sukses walau email tidak terdaftar, untuk mencegah enumerasi akun.

Grup: Auth · Autentikasi: Publik (tanpa login)

Body permintaan

FieldTipeKeterangan
email wajibstring · email

Respons

KodeArtiSkema
200Permintaan diterimaobject

POST /auth/reset-password

Setel password baru dengan token reset

Grup: Auth · Autentikasi: Publik (tanpa login)

Body permintaan

FieldTipeKeterangan
token wajibstring
password wajibstring

Respons

KodeArtiSkema
200Password digantiobject
400Token tidak valid atau kedaluwarsaError

PATCH /profile

Ubah nama tampilan

Grup: Profil · Autentikasi: Cookie otp_token

Body permintaan

FieldTipeKeterangan
fullName wajibstring

Respons

KodeArtiSkema
200OKobject
401Belum loginError

POST /profile/password

Ganti password

Grup: Profil · Autentikasi: Cookie otp_token

Body permintaan

FieldTipeKeterangan
current wajibstringPassword lama
next wajibstringPassword baru

Respons

KodeArtiSkema
200OKobject
400Password lama salah atau password baru terlalu pendekError

GET /dashboard/summary

Ringkasan akun

Grup: Dashboard · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
401Belum loginError

GET /numbers/countries

Daftar negara yang tersedia

Grup: Katalog Nomor · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
401Belum loginError

GET /numbers/services

Daftar layanan untuk satu negara

Grup: Katalog Nomor · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
countryqueryyastring

Respons

KodeArtiSkema
200OKobject
400Parameter country wajibError

GET /numbers/prices

Harga per layanan (sudah termasuk markup platform)

Grup: Katalog Nomor · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
countryqueryyastring

Respons

KodeArtiSkema
200OKobject
400Parameter country wajibError

GET /numbers/balance

Saldo penyedia nomor (internal)

Grup: Katalog Nomor · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
502Provider tidak dapat dihubungiError

POST /orders

Beli nomor

Saldo wallet harus cukup (USD). Harga final dihitung server. Bila pembelian gagal, saldo dikembalikan otomatis.

Grup: Order · Autentikasi: Cookie otp_token

Body permintaan

FieldTipeKeterangan
servicestring wa
countrystring 6
serviceNamestring WhatsApp
countryNamestring Indonesia

Respons

KodeArtiSkema
200Nomor berhasil dibeliobject
400Saldo kurang, layanan habis, atau provider menolakError

GET /orders

Riwayat order (paginasi)

Grup: Order · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
statusquerytidakstring · WAITING | RECEIVED | CANCELLED | EXPIRED | FAILED
searchquerytidakstring

Respons

KodeArtiSkema
200OKPaginated

GET /orders/active

Order yang masih menunggu OTP

Grup: Order · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

POST /orders/{id}/poll

Cek OTP terbaru untuk satu order

Memanggil provider; bila OTP sudah masuk, order berubah menjadi RECEIVED.

Grup: Order · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject
400Order tidak bisa diprosesError

POST /orders/{id}/cancel

Batalkan order

Membatalkan order di provider dan mengembalikan saldo bila memenuhi syarat.

Grup: Order · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject
400Order tidak bisa dibatalkanError

POST /deposits

Buat tagihan top-up QRIS

Minimal Rp 10.000. Server membuat charge ke BoomPay dan mengembalikan qrPayload (string QRIS EMVCo) untuk dirender menjadi QR di klien.

Nominal yang benar-benar ditagih adalah deposit.providerData.billedAmount (harga order + fee gateway + kode unik). feeInfo.totalAmount hanya perkiraan internal untuk tampilan, bukan angka tagihan.

Grup: Deposit · Autentikasi: Cookie otp_token

Body permintaan

FieldTipeKeterangan
amountintegerNominal top up dalam Rupiah 10000

Respons

KodeArtiSkema
200Tagihan dibuatobject
400Nominal di bawah minimumError
502Gateway gagal; deposit otomatis ditandai CANCELLEDError

GET /deposits

Riwayat deposit pengguna

Grup: Deposit · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

POST /deposits/{id}/check-status

Sinkronkan status deposit ke gateway

Menanyakan status ke BoomPay dengan API key server sendiri (bukan mempercayai klien). Bila sudah dibayar, deposit menjadi PAID dan saldo dikreditkan tepat satu kali. Aman dipanggil berulang (idempoten).

Grup: Deposit · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200Status terbaruobject
404Deposit tidak ditemukan atau bukan milik pengguna iniError
500Pengecekan gagal (gateway tidak merespons)Error

POST /deposits/{id}/cancel

Batalkan deposit yang masih PENDING

BoomPay tidak punya endpoint cancel, jadi pembatalan ditandai di database.

Grup: Deposit · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject
400Status deposit bukan PENDINGError

POST /deposits/{id}/confirm

[DEPRECATED] Konfirmasi manual

Endpoint ini sudah DEPRECATED.

Tidak lagi memproses apa pun. Konfirmasi hanya lewat webhook BoomPay atau check-status.

Grup: Deposit · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200Status saat ini dikembalikan apa adanyaobject

GET /transactions

Semua transaksi saldo pengguna

Grup: Riwayat · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

GET /balance-history

Riwayat saldo (paginasi dan filter)

Grup: Riwayat · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
typequerytidakstring · DEPOSIT | PURCHASE | REFUND | MANUAL | BONUS | FEE
searchquerytidakstring
fromquerytidakstring · date
toquerytidakstring · date

Respons

KodeArtiSkema
200OKPaginated
403Tidak berhakError

GET /admin/overview

Ringkasan seluruh platform

Grup: Admin · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
403Butuh role adminError

GET /admin/users

Daftar pengguna

Grup: Admin · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
searchquerytidakstring
rolequerytidakstring · user | admin

Respons

KodeArtiSkema
200OKPaginated
403Butuh role adminError

GET /admin/orders

Daftar order semua pengguna

Grup: Admin · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
searchquerytidakstring
statusquerytidakstring

Respons

KodeArtiSkema
200OKPaginated
403Butuh role adminError

GET /admin/deposits

Daftar deposit semua pengguna

Grup: Admin · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
searchquerytidakstring
statusquerytidakstring

Respons

KodeArtiSkema
200OKPaginated
403Butuh role adminError

GET /admin/profit

Laporan profit

Semua angka dalam USD (akuntansi internal).

Grup: Admin · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
pagequerytidakinteger
pageSizequerytidakinteger
fromquerytidakstring · date
toquerytidakstring · date

Respons

KodeArtiSkema
200OKobject
403Butuh role adminError

GET /admin/provider-balance

Saldo penyedia nomor dari sisi admin

Grup: Admin · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject
403Butuh role adminError
502Provider tidak dapat dihubungiError

POST /boompay/webhook

Callback dari BoomPay (didaftarkan di dashboard BoomPay)

Bukan untuk pengguna. URL terdaftar: https://dewaotp.top/api/boompay/webhook

Isi body tidak dipercaya. Handler mengambil merchant_order_id lalu memverifikasi ulang ke GET https://app.boompay.io/api/v1/pg/charge/{id} memakai API key server. Hanya jawaban API yang boleh mengkreditkan saldo. Idempoten: pengiriman ulang tidak menambah saldo lagi.

Grup: Webhook · Autentikasi: Publik (tanpa login)

Body permintaan

FieldTipeKeterangan
merchant_order_idstring DEP-ab3f2c29-17e7-468f-83a5-0c030a7da0a3

Respons

KodeArtiSkema
200Diterima; applied=false bila belum lunas atau sudah dikreditkanobject
500Gagal diproses; pengirim akan mencoba ulang dan handler idempoten—

GET /reseller/balance

Saldo wallet penjual

Nilai disimpan USD; ekuivalen Rupiah memakai kurs efektif platform.

Grup: API Penjual · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKResellerBalance
401API key tidak ada / tidak valid—

GET /reseller/countries

Daftar negara

Grup: API Penjual · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

GET /reseller/services

Layanan + harga + stok untuk satu negara

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
countryqueryyastring

Respons

KodeArtiSkema
200OKobject
400country wajib—

GET /reseller/prices

Harga per layanan

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
countryqueryyastring

Respons

KodeArtiSkema
200OKobject

POST /reseller/orders

Beli nomor (memotong saldo)

Saldo wallet pemilik kunci dipotong sebesar price_usd; bila penyedia gagal, saldo tidak ditarik.

Idempotensi: kirim header Idempotency-Key (berlaku 24 jam). Rate limit: 20 permintaan/menit per kunci.

Grup: API Penjual · Autentikasi: Cookie otp_token

Body permintaan

FieldTipeKeterangan
service wajibstring wa
country wajibstring 6
serviceNamestring WhatsApp
countryNamestring Indonesia
max_pricenumberBatas harga modal per nomor (dari /reseller/tiers). Nomor dibeli pada paket harga ini atau lebih murah.
operatorstringKode operator (opsional), lihat daftar operator di /reseller/tiers telkomsel

Respons

KodeArtiSkema
200OKobject
400Field kurang / SERVICE_NOT_AVAILABLE—
402INSUFFICIENT_BALANCE—
429RATE_LIMITED (lihat header retry-after)—

GET /reseller/orders

Riwayat order milik kunci

Grup: API Penjual · Autentikasi: Cookie otp_token

Respons

KodeArtiSkema
200OKobject

GET /reseller/orders/{id}

Detail satu order

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject
404Tidak ditemukan / bukan milik kunci ini—

POST /reseller/orders/{id}/poll

Ambil OTP terbaru

Memanggil penyedia. Saat OTP pertama masuk, webhook dikirim ke URL kunci (3 percobaan, backoff 1s & 3s, header x-signature).

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject

POST /reseller/orders/{id}/cancel

Batalkan order + refund

Saldo dikembalikan lewat ledger sebagai transaksi REFUND.

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
idpathyastring · uuid

Respons

KodeArtiSkema
200OKobject

GET /reseller/offers

Pilihan harga lintas negara untuk satu layanan

Semua negara yang menyediakan layanan ini, diurutkan dari termurah ke termahal. `tier`: termurah | hemat | standar | premium (kuantil harga).

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
servicequeryyastring
limitquerytidakinteger

Respons

KodeArtiSkema
200OKobject
400service wajib—
502PRICES_UNAVAILABLE—

GET /reseller/tiers

Paket harga (tier) untuk satu layanan di satu negara

Daftar harga bertingkat dari penyedia: harga → jumlah nomor tersedia, diurutkan dari termurah. `provider_price_usd` dipakai sebagai `max_price` saat membeli.

Grup: API Penjual · Autentikasi: Cookie otp_token

Parameter

NamaLokasiWajibTipe
servicequeryyastring
countryqueryyastring

Respons

KodeArtiSkema
200OKobject
400service dan country wajib—
502TIERS_UNAVAILABLE—

Skema data

Error

FieldTipeKeterangan
errorstring Unauthorized

ExchangeRate

FieldTipeKeterangan
basestring USD
targetstring IDR
liveRatenumber 18154.555202
spreadnumber 1.03
effectiveRatenumberRate yang dipakai platform, termasuk spread 18699.19185806
oneUsdInIdrnumber 18699.19185806
fetchedAtintegerEpoch milidetik

QrisFeeInfo

FieldTipeKeterangan
enabledboolean
percentnumber 0.7
lowFixedinteger 310
highPercentnumber
highFixedinteger
thresholdinteger 105000
feePaidByUserboolean

User

FieldTipeKeterangan
idstring · uuid
fullNamestring
emailstring · email
balancenumberSaldo dalam USD; UI menampilkannya sebagai Rupiah 0.5348
rolestring · user | admin
createdAtstring · date-time
updatedAtstring · date-time

Order

FieldTipeKeterangan
idstring · uuid
orderNumberinteger 1416
orderNumberFormattedstring 001416
externalOrderIdstring
servicestring wa
serviceNamestring WhatsApp
countrystring 6
countryNamestring Indonesia
phoneNumberstring 628123456789
otpCodestring
pricenumberHarga jual (USD) 0.18
originalPricenumberHarga modal (USD)
profitnumberMargin per order (USD)
statusstring · WAITING | RECEIVED | CANCELLED | EXPIRED | FAILED
createdAtstring · date-time

Deposit

FieldTipeKeterangan
idstring · uuid
userIdstring · uuid
amountintegerNominal top up (Rupiah) 10000
adminFeeinteger 392
feePercentnumber
statusstring · PENDING | PAID | EXPIRED | CANCELLED
paymentReferencestringmerchant_order_id di BoomPay DEP-ab3f2c29-17e7-468f-83a5-0c030a7da0a3
qrPayloadstringString QRIS EMVCo untuk dirender menjadi QR
qrImageUrlstring
providerDataobject
usdCreditnumberSaldo yang dikreditkan (USD) 0.5348
effectiveRatenumber
createdAtstring · date-time
paidAtstring · date-time

Transaction

FieldTipeKeterangan
idstring · uuid
typestring · DEPOSIT | PURCHASE | REFUND | MANUAL | BONUS | FEE
amountnumberPerubahan saldo (USD); negatif untuk pengeluaran
balanceBeforenumber
balanceAfternumber
descriptionstring
referenceTypestring
referenceIdstring
createdAtstring · date-time

Paginated

FieldTipeKeterangan
itemsarray<any>
totalinteger 42
pageinteger 1
pageSizeinteger 20

ResellerOrder

FieldTipeKeterangan
idstring · uuid
order_numberstring 001932
servicestring tg
countrystring 6
phone_numberstring 6283123512142
statusstring · WAITING | RECEIVED | CANCELLED | EXPIRED | FAILED
otp_codestring 123456
price_usdnumber 0.1224
created_atstring · date-time

ResellerBalance

FieldTipeKeterangan
balance_usdnumber 0.9549
balance_idrinteger 17810
currency_displaystring IDR

PriceOffer

FieldTipeKeterangan
country_idstring 6
country_namestring Indonesia
flagstring ID
price_usdnumber 0.2519
stockinteger 5782
is_physicalboolean
tierstring · termurah | hemat | standar | premium
rankinteger

PriceTier

FieldTipeKeterangan
price_usdnumber 0.252
provider_price_usdnumber 0.21
stockinteger 29406