Dokumentasi API

Referensi lengkap REST API OTPZap untuk integrasi nomor virtual dan verifikasi OTP.

Informasi Koneksi

Base URLhttps://otpzap.com/api/v1
AutentikasiAuthorization: Bearer YOUR_API_KEY
Rate Limit300 request/menit per API key
FormatJSON (request & response)

Panduan Singkat

OTPZap mendukung 3 server dengan cara kerja berbeda:

Akun & Saldo

GET/balance

Cek saldo akun.

Response: {"success":true,"data":{"balance":50000,"currency":"IDR"}}
POST/topup/create

Buat invoice deposit via QRIS (rupiah). Arahkan customer ke payment_url untuk menyelesaikan pembayaran. Saldo dikreditkan otomatis ketika pembayaran sukses. Invoice berlaku 30 menit.

Body: {"amount":50000}
Response: {"success":true,"data":{"order_id":"APIDEP-3-xxx","amount":50000,"total_amount":50017,"payment_url":"https://otpzap.com/pay/APIDEP-3-xxx","expired_at":"2026-05-19 10:30:00 WIB"}}
GET/topup/check?order_id=APIDEP-3-xxx

Cek status deposit. Status: pending | success | expired | failed. Polling juga otomatis mendorong rekonsiliasi.

Response: {"success":true,"data":{"order_id":"APIDEP-3-xxx","amount":50000,"status":"success","paid_at":"2026-05-19 09:45:12 WIB","created_at":"2026-05-19 09:30:00 WIB"}}

🪙 Pembayaran Crypto

Untuk saat ini, deposit crypto (BTC, USDT, ETH, USDC, dll) hanya tersedia melalui dashboard web - tidak tersedia melalui Public API. Customer bisa memilih metode pembayaran crypto langsung di halaman Deposit Saldo di dashboard. Window pembayaran crypto: 25 menit setelah invoice dibuat.

Server 1

Gunakan product_id dari endpoint /products. 1 product = 1 layanan + 1 negara + 1 tier harga. Catalog diambil fresh oleh OTPZap; fetch ulang sebelum create order dan hindari cache client yang terlalu lama.

GET/countries

Daftar negara tersedia (Server 1).

Response: {"success":true,"data":{"countries":[{"id":7,"name":"Indonesia"}]}}
GET/services?country_id=7

Daftar platform/layanan. Parameter opsional: country_id.

Response: {"success":true,"data":{"services":[{"id":1,"code":"whatsapp","name":"WhatsApp"}]}}
GET/products?platform_id=1&country_id=7

Daftar produk + harga + stok. Parameter: platform_id, country_id, page, limit, sort.

Response: {"success":true,"data":{"products":[{"id":814090256,"name":"WhatsApp - Indonesia","price":2835,"stock":547}]}}

Server 2

Gunakan service_id + country_id + operator_id. Mendukung multiservice dan layanan spesial. Data layanan juga fresh dari sistem OTPZap.

GET/s2/countries

Daftar negara tersedia (Server 2).

Response: {"success":true,"data":{"countries":[{"id":7,"name":"Indonesia"}]}}
GET/s2/services?country_id=7

Daftar layanan + harga per negara.

Response: {"success":true,"data":{"services":[{"service_id":101,"service_name":"WhatsApp","price":1500}]}}
GET/s2/operators?country_id=7

Daftar operator per negara.

Response: {"success":true,"data":{"operators":["random","telkomsel","indosat"]}}
GET/s2/special

Daftar layanan spesial (tanpa parameter country/operator). Layanan ini menggunakan nomor virtual yang sudah dialokasikan oleh sistem untuk platform tertentu.

Response: {"success":true,"data":{"services":[{"service_id":501,"service_name":"Gojek Special","price":3500}]}}

Server 3 - Email OTP

Gunakan Server 3 untuk sewa inbox email. Pilih target site dan domain dulu, lalu buat order email. 20 menit pertama adalah window tunggu; setelah pesan masuk, masa aktif sesi mengikuti policy domain/service email.

GET/s3/sites

Saran target website. Ini hanya suggestion; domain site valid apa pun bisa dikirim ke endpoint create.

Response: {"success":true,"data":{"sites":[{"site":"openai.com","name":"OpenAI / ChatGPT","category":"ai"}],"total":30}}
GET/s3/domains?site=openai.com

Domain email tersedia, stok, harga, activation rate, dan estimasi biaya cancel.

Response: {"success":true,"data":{"domains":[{"name":"gmail.com","price_idr":12000,"stock":25,"cancel_fee_idr":0}]}}
POST/order/email-create

Beli Email OTP. Field opsional: qty, subject, regex, atau domains[] untuk aggregator mode.

Body: {"site":"openai.com","domain":"gmail.com","qty":1}
Response: {"success":true,"data":{"order":{"order_id":88,"ref":"APIE-3-xxx","server":3,"order_type":"email","email":"[email protected]","status":"pending"}}}
GET/order/email-check?ref=APIE-3-xxx

Polling status dan pesan email. Response berisi inbox preview, OTP/headline yang diekstrak, timeline pesan, dan expires_at terbaru.

POST/order/email-reorder

Minta pesan baru pada inbox email yang sama. Window tunggu reset ke 20 menit dan saldo OTPZap tidak dipotong lagi.

Body: {"ref":"APIE-3-xxx"}
POST/order/email-cancel

Cancel sebelum pesan masuk. Refund bisa dipotong biaya cancel provider.

Body: {"ref":"APIE-3-xxx"}
POST/order/email-finish

Selesaikan order email setelah pesan masuk dan tutup aktivasi provider.

Body: {"ref":"APIE-3-xxx"}

Order & Manajemen

Endpoint berikut berlaku untuk order SMS di Server 1 dan Server 2. Email OTP memakai endpoint khusus Server 3 di atas.

POST/order/create

Beli nomor OTP. Header opsional Idempotency-Key untuk mencegah duplikasi pada retry. Ambil ID dari catalog terbaru. Field service_name opsional; jika dikirim harus cocok dengan nama layanan untuk ID yang dipilih.

Server 1: {"server":1,"product_id":814090256,"country_id":7,"platform_id":1}
Server 2 reguler: {"server":2,"service_id":101,"country_id":7,"operator_id":"random"}
Server 2 spesial: {"server":2,"service_id":501,"is_special":true}
Server 2 multiservice: {"server":2,"service_ids":[101,102,103],"country_id":7,"operator_id":"random"}
Response (single): {"success":true,"data":{"order_id":65,"ref":"API3-xxx","server":1,"phone":"628xxx","service":"WhatsApp","price":2835,"currency":"IDR","status":"pending","multiservice":false,"created_at":"..."}}
GET/orders.php?limit=20&offset=0&status=success&server=1

Daftar order milik API key ini, urutan terbaru. Filter opsional: status, server, limit (maks. 100), dan offset.

Response: {"success":true,"data":{"orders":[{"order_id":65,"ref":"API3-xxx","status":"success","otp_code":"123456"}],"total":25,"limit":20,"offset":0}}
GET/orders/active.php

Daftar seluruh order aktif milik API key ini dengan status pending atau otp_received. Cocok untuk polling beberapa order sekaligus.

Response: {"success":true,"data":{"orders":[],"total":0,"limit":20,"offset":0}}
GET/order/check?order_id=65

Cek status & ambil OTP. Poll endpoint ini setiap 5 detik. Status flow: pendingotp_received (S1, nomor masih aktif) → success. Order yang gagal otomatis di-refund.

Response: {"success":true,"data":{"order_id":65,"ref":"API3-xxx","server":1,"phone":"628xxx","service":"WhatsApp","otp_code":"123456","otps":[{"code":"123456","received_at":"2026-05-19 10:35:12 WIB"}],"price":2835,"currency":"IDR","status":"otp_received","resend_count":0,"last_resend_at":null,"resend_locked_until":null,"created_at":"2026-05-19 10:30:00 WIB","updated_at":"2026-05-19 10:35:12 WIB"}}

Field penting: otp_code = OTP terbaru/final untuk integrasi otomatis. otps[] = timeline semua OTP yang masuk (oldest first), jadi jangan ambil item pertama sebagai OTP utama. Berguna saat resend menambah OTP baru - kamu bisa detect new entry by length perubahan. resend_count = berapa kali resend sudah dipakai. resend_locked_until = timestamp WIB sampai kapan resend di-lock (null kalau available).

POST/order/cancel

Batalkan order pending. Cooldown 2 menit berlaku untuk semua order (single maupun multiservice). Saldo otomatis dikembalikan jika sistem mengonfirmasi pembatalan. Error codes: 409 jika status bukan pending, 429 jika cooldown belum habis (cek header Retry-After), 502 jika sistem menolak.

Body: {"order_id":65}
Response (success): {"success":true,"data":{"order_id":65,"refunded":2835}}
POST/order/finish

Tandai order selesai. Gunakan setelah OTP diterima dan nomor sudah tidak diperlukan.

Body: {"order_id":65}
POST/order/resend

Kirim ulang SMS. Per-OTP gating: setelah satu kali resend, panggilan berikutnya akan menerima HTTP 429 sampai OTP baru masuk via polling. Status dan OTP yang sudah ada tidak direset - OTP baru muncul sebagai entry tambahan di field otps[]. Tidak semua platform mendukung resend.

Body: {"order_id":65}
POST/order/replace

Server 1 saja. Cancel order lama dan buat order baru di harga produk yang sama secara atomik. Saldo lama di-refund, saldo baru dipotong dalam satu transaksi.

Body: {"order_id":65}
Response: {"success":true,"data":{"order_id":99,"old_ref":"API3-xxx","ref":"API3-yyy","phone":"628yyy","price":2835,"status":"pending"}}

Webhook

OTPZap mengirim POST request ke URL webhook kamu saat event terjadi. Konfigurasi via dashboard atau API endpoint di bawah.

Events:

Manajemen Webhook

GET/webhook/get

Ambil konfigurasi webhook saat ini. secret tidak pernah di-return di endpoint ini (alasan keamanan, hanya ditampilkan sekali saat set/update).

Response (configured): {"success":true,"data":{"configured":true,"url":"https://yoursite.com/hook","events":["order.otp_received","order.finished"],"is_active":true,"updated_at":"2026-05-19 10:00:00 WIB"}}
Response (belum set): {"success":true,"data":{"configured":false,"url":null,"events":[],"is_active":false}}
PATCH/webhook/update

Buat atau update konfigurasi webhook. Method PATCH (bukan POST). URL wajib HTTPS dan resolve ke IP publik (private IP otomatis ditolak untuk anti-SSRF).

Body: {"url":"https://yoursite.com/hook","events":["order.otp_received","order.finished","order.replaced"],"secret":"OPTIONAL_MIN_16_CHARS","is_active":true}
Response: {"success":true,"data":{"url":"https://yoursite.com/hook","secret":"abc123def456...","events":[...],"is_active":true,"note":"Save the secret now. It will not be shown again for security."}}

Field opsional: secret minimal 16 karakter (kalau gak provide atau kurang, OTPZap auto-generate 48-char hex). Simpan secret ini di tempat aman - tidak akan ditampilkan lagi di /webhook/get. is_active default true; bisa di-set false untuk pause sementara tanpa hapus config.

Error 422: URL bukan HTTPS, URL resolve ke IP private/loopback (anti-SSRF), atau ada event yang tidak valid (lihat list di atas).

Keamanan Webhook

Verifikasi Signature:

// PHP $body = file_get_contents('php://input'); $expected = 'sha256=' . hash_hmac('sha256', $body, YOUR_SECRET); if (!hash_equals($expected, $_SERVER['HTTP_X_OTPZAP_SIGNATURE'])) die('Invalid'); // Node.js const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex'); if (req.headers['x-otpzap-signature'] !== expected) return res.status(401).end();

Butuh bantuan? Hubungi kami via Telegram.