Verifikasi Nomor HP dengan WhatsApp OTP: Alur Request → Verify untuk Developer

Verifikasi Nomor HP dengan WhatsApp OTP: Alur Request → Verify untuk Developer

Skenarionya hampir selalu sama. User baru mengisi nomor HP di form registrasi, menekan kirim, lalu menatap layar menunggu SMS berisi kode yang tidak kunjung masuk. Sebagian menekan "kirim ulang" berkali-kali. Sebagian lagi menyerah dan menutup aplikasi, tepat di langkah terakhir sebelum jadi user aktif. Padahal di HP yang sama, notifikasi WhatsApp masuk tanpa hambatan.

Artikel ini membahas cara memverifikasi nomor HP user aplikasi Anda memakai WhatsApp OTP: kenapa channel ini masuk akal untuk aplikasi yang melayani pasar Indonesia, seperti apa alur request → verify di level API, dan proteksi apa saja yang harus ada sebelum fitur ini layak produksi. Contoh kode memakai API OTP.ID V3, tapi konsep alurnya berlaku umum di penyedia mana pun.

Kenapa WhatsApp untuk OTP di Indonesia

Angkanya dulu. Indonesia adalah negara pengguna WhatsApp terbesar ketiga di dunia dengan 112 juta pengguna, di bawah India dan Brasil, dari total 3 miliar pengguna global per kuartal pertama 2025 (data World Population Review, dikutip CNN Indonesia, Mei 2025). Kalau produk Anda melayani pasar Indonesia, kemungkinan besar nomor yang mau diverifikasi memang aktif di WhatsApp.

Arah standar keamanan juga relevan. NIST SP 800-63B mengklasifikasikan verifikasi out-of-band lewat jaringan telepon publik (PSTN), yang mencakup SMS dan panggilan suara, sebagai RESTRICTED (bagian 5.1.3.3). Bukan berarti OTP SMS dilarang; klasifikasi itu menuntut organisasi menilai risikonya dan menyediakan alternatif bagi penggunanya. OTP yang dikirim lewat jalur data seperti WhatsApp berada di luar cakupan klasifikasi tersebut.

Dari sisi user yang menerima kode, pesan WhatsApp menampilkan nama pengirim atau brand, sehingga lebih mudah dikenali dibanding SMS dari nomor acak. Dan dari pengamatan operasional di OTP.ID sendiri, WhatsApp adalah channel yang paling banyak dipakai Client karena keterkirimannya paling baik di antara channel yang tersedia. Angka delivery rate-nya belum kami publikasikan; sesuai prinsip kami, klaim keandalan baru ditulis setelah terukur dari data produksi beserta periodenya.

Ilustrasi verifikasi nomor HP lewat WhatsApp OTP dengan smartphone dan tanda centang

Anatomi alur verifikasi nomor

Alur lengkapnya:

1. Backend aplikasi memanggil API kirim OTP
2. Kode terkirim ke WhatsApp user
3. User mengetik kode di aplikasi
4. Backend memanggil API verifikasi
5. Status final: verified, atau gagal (kode salah / kedaluwarsa / habis percobaan)

Yang membuat fitur ini lebih rumit dari kelihatannya adalah pekerjaan turunan di langkah 1 dan 4: menghasilkan kode yang tidak mudah ditebak, memberlakukan masa berlaku, membatasi jumlah percobaan, memastikan kode hangus setelah dipakai, membatasi kiriman per nomor, sampai memutuskan bagaimana kode disimpan di database. Daftar inilah yang paling sering bocor di implementasi buatan sendiri, dan hampir semuanya bisa dipindahkan ke sisi penyedia API.

Kirim kode: POST /v3/request

Satu request dari backend Anda:

curl -X POST https://api.otp.id/v3/request \
  -H "Authorization: Bearer $OTPID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "destination": "628xxxxxxxxxx",
    "brand": "TokoAnda",
    "otp_length": 6,
    "ttl": 300,
    "external_id": "reg-usr-1042"
  }'

destination diisi nomor HP dalam format internasional tanpa tanda plus, digit saja, minimal 10 digit. brand adalah nama yang tampil di pesan; kalau dikosongkan, dipakai nama brand akun Anda. otp_length default 6 dan dibatasi di rentang 4–8; ttl default 300 detik dan dibatasi 60–900. external_id opsional tapi sebaiknya selalu diisi — perannya dibahas di bagian proteksi.

Response sukses:

{
  "success": true,
  "data": {
    "otp_id": "OTP20260815ABCD000123",
    "status": "sent",
    "channel": "whatsapp",
    "number": "628xxxxxxxxxx",
    "price": 350,
    "last_balance": 99650,
    "expires_at": "2026-08-15 14:05:00"
  },
  "error": null
}

Simpan data.otp_id; itu kunci yang dipakai saat verifikasi. price dan last_balance menunjukkan biaya request ini dan sisa kredit prepaid setelahnya (angka di contoh hanya ilustrasi; harga per channel tampil di dashboard). expires_at memakai zona waktu WIB.

Satu perilaku yang sering terlewat: gagal kirim ke vendor tetap dikembalikan sebagai HTTP 200, dengan data.status bernilai "failed" dan kredit tidak didebit. Jadi periksa data.status di kode Anda, jangan hanya mengandalkan HTTP status code.

Verifikasi kode: POST /v3/verify

Saat user mengetik kodenya, backend memanggil:

curl -X POST https://api.otp.id/v3/verify \
  -H "Authorization: Bearer $OTPID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"otp_id": "OTP20260815ABCD000123", "otp": "123456"}'

Hasilnya sinkron, dan perilakunya perlu dipahami sebelum menulis error handling:

Kondisi HTTP Isi response
Kode cocok 200 verified: true; transaksi berstatus verified
Kode salah 200 verified: false, reason: "mismatch"
Lewat masa berlaku 422 error OTP_EXPIRED
Salah 5 kali 422 error TOO_MANY_ATTEMPTS
Sudah pernah diverifikasi 422 error ALREADY_USED

Kode yang salah dikembalikan sebagai HTTP 200 dengan verified: false. Di backend Anda, jalur ini jangan masuk exception handler; itu respons normal yang tinggal diteruskan ke user sebagai "kode salah, coba lagi".

Tiga proteksi di tabel itu berjalan di server tanpa konfigurasi apa pun: masa berlaku, maksimal 5 percobaan salah untuk channel standar, dan sekali-pakai. Sebagai pembanding, NIST SP 800-63B (bagian 5.1.3.2) mensyaratkan autentikasi out-of-band dianggap tidak valid setelah 10 menit. Default 300 detik jauh di dalam batas itu. Kalau Anda menaikkan ttl, pastikan nilainya tetap sesuai kebijakan risiko aplikasi dan standar yang dipakai organisasi Anda.

Proteksi lain yang sudah berjalan di server

Idempotency lewat external_id menyelamatkan Anda dari kasus retry jaringan. Request ulang dengan external_id dan parameter yang sama dalam 24 jam akan menerima replay response pertama, tanpa kirim ulang dan tanpa debit ulang. Kalau external_id sama dipakai dengan parameter berbeda, server menjawab 409 DUPLICATE_EXTERNAL_ID.

Rate limit bekerja di dua dimensi. Per nomor tujuan: maksimal 5 OTP per 10 menit dan 10 OTP per jam, dijawab 429 DESTINATION_RATE_LIMITED saat terlampaui — pagar terhadap pola penyalahgunaan yang memicu pengiriman OTP massal ke satu nomor. Per API key: 20 request per detik untuk semua endpoint V3.

Kode OTP sendiri disimpan sebagai hash SHA-256 dengan salt per record. Kode tidak pernah muncul di response API maupun log, jadi kebocoran log tidak otomatis jadi kebocoran kode aktif.

Kalau arsitektur Anda butuh notifikasi alih-alih polling, tersedia webhook otp.verified yang dikirim saat verifikasi berhasil, ditandatangani HMAC-SHA256 dengan timestamp untuk dicek di sisi penerima.

Ilustrasi proteksi OTP dengan perisai dan gembok untuk keamanan verifikasi

Satu hal tetap jadi tugas aplikasi: beri cooldown pada tombol "kirim ulang" di UI. Rate limit server adalah pagar terakhir; UX yang baik membuat user tidak pernah menabraknya.

Kalau nomor tidak terdaftar di WhatsApp?

Pengirimannya gagal: data.status bernilai failed dan kredit tidak didebit. OTP.ID tidak melakukan fallback otomatis antar channel; keputusan channel berikutnya ada di tangan Anda sebagai pemilik alur dan biaya.

Praktisnya sederhana. Tangkap status failed, tawarkan pilihan ke user ("kirim lewat SMS saja?"), lalu buat request baru dengan body yang sama dan channel diganti "sms" atau "misscall". Channel Missed Call memverifikasi lewat panggilan tak terjawab: user memasukkan digit terakhir nomor pemanggil sebagai kode.

Checklist sebelum naik produksi

Mulai dari mana

Seluruh alur di atas hanya dua request: satu untuk mengirim kode, satu untuk memverifikasinya; masa berlaku, batas percobaan, dan sisanya ditangani server. Referensi lengkap endpoint, error code, dan webhook ada di dokumentasi API OTP.ID di docs.otp.id. Kalau tidak mau menulis HTTP client sendiri, tersedia SDK resmi untuk Go, PHP, Node.js, dan Python di registry masing-masing (Go module, Packagist, npm, PyPI).

Registrasi publik OTP.ID sudah dibuka di app.otp.id. Merchant baru mendapat kredit gratis Rp2.000 untuk mulai mencoba alur WhatsApp OTP langsung dari dashboard.

← SEMUA ARTIKEL