VTechOTP VTechOTP v1 IDR

Dokumentasi VTechOTP Developer API v1

Akses terprogram untuk sewa nomor virtual, otomatisasi penerimaan SMS/OTP, pengecekan saldo, dan notifikasi real-time webhook berbasis mata uang Rupiah (1 Coin = 1 IDR).

Arsitektur RESTful Standar: Developer API ini dirancang mengikuti format standar RESTful sehingga mudah dihubungkan dengan bot Telegram, skrip otomatisasi, bot Discord, maupun sistem reseller Anda.

Autentikasi

Setiap request ke API harus menyertakan API Token Anda pada HTTP Header Authorization dengan format Bearer token:

HTTP Header
Authorization: Bearer vtk_your_api_token_here

Anda dapat membuat atau memperbarui API Token kapan saja melalui menu Profil > Developer API & Webhook di aplikasi VTechOTP.

Base URL

Semua request API diarahkan ke endpoint resmi berikut:

https://vtechotp.web.id/api/v1

Cek Saldo & Profil

GET /balance atau /user

Mengambil informasi saldo koin akun (1 koin = Rp 1), jumlah order aktif, dan status konfigurasi akun Anda.

cURL Example
curl -s https://vtechotp.web.id/api/v1/balance \
  -H "Authorization: Bearer vtk_your_api_token_here"
200 OK Response
{
  "success": true,
  "data": {
    "user_id": "6a8218b04fb8bbfcd472a981",
    "email": "user@example.com",
    "display_name": "DevUser",
    "balance": 75000,
    "currency": "IDR",
    "active_orders": 1,
    "total_orders": 68,
    "success_orders": 65,
    "webhook_configured": true,
    "api_enabled": true
  }
}

Daftar Saluran Pembayaran & Cek Status Live (ON/OFF)

GET /deposits/channels (alias: /deposit/channels)

Mendapatkan daftar seluruh metode/saluran pembayaran yang didukung payment gateway secara real-time. Endpoint ini menampilkan status aktif/gangguan (status: "ON" atau "OFF"), batas minimum/maksimum nominal, dan biaya fee pada masing-masing saluran sehingga bot atau aplikasi Anda dapat memvalidasi saluran mana yang sedang online sebelum membuat tagihan invoice.

Daftar Kode Saluran (service_id) Populer:
• QRIS Realtime: 11 (Min. Rp 100 / Rp 1.000, Max. Rp 10.000.000) - Rekomendasi Utama
• Virtual Account (VA): BCA (1), BRI (2), BNI (4), Mandiri (5), CIMB (3), Permata (7), Danamon (8), BSI (9), Neo (10), OCBC (21), Muamalat (22) (Min. Rp 10.000)
• E-Wallet: OVO (12 - butuh parameter phone)
• Gerai Retail: Alfamart/Alfamidi (18), Indomaret/Ceriamart (19) (Min. Rp 10.000)
cURL Request
curl -s https://vtechotp.web.id/api/v1/deposits/channels
200 OK Response (Contoh JSON)
{
  "success": true,
  "data": {
    "payment_gateway": "configured_gateway",
    "deposit_fee_flat": 100,
    "deposit_fee_percent": 0,
    "total_channels": 16,
    "active_channels": 16,
    "channels": [
      {
        "id": "11",
        "service_id": "11",
        "name": "QRIS Realtime",
        "type": "QRIS",
        "minimum": 1000,
        "maximum": 10000000,
        "fee": "0.7%",
        "icon_url": "/assets/app-deposit.png",
        "status": "ON",
        "is_active": true
      },
      {
        "id": "1",
        "service_id": "1",
        "name": "Virtual Account Bank BCA",
        "type": "VA",
        "minimum": 10000,
        "maximum": 10000000,
        "fee": 4900,
        "icon_url": "/assets/app-deposit.png",
        "status": "ON",
        "is_active": true
      },
      {
        "id": "2",
        "service_id": "2",
        "name": "Virtual Account Bank BRI",
        "type": "VA",
        "minimum": 10000,
        "maximum": 50000000,
        "fee": 2500,
        "icon_url": "/assets/app-deposit.png",
        "status": "ON",
        "is_active": true
      },
      {
        "id": "18",
        "service_id": "18",
        "name": "ALFAMART",
        "type": "RETAIL",
        "minimum": 10000,
        "maximum": 5000000,
        "fee": 2500,
        "icon_url": "/assets/app-deposit.png",
        "status": "ON",
        "is_active": true
      }
    ]
  }
}

Buat Tagihan Deposit (QRIS, VA, E-Wallet, Retail)

POST /deposits/create (alias: /deposit/create, /deposits)

Membuat tagihan invoice deposit saldo koin baru via payment gateway. Mendukung pembuatan tagihan otomatis untuk QRIS Realtime (mengembalikan gambar PNG, Base64, dan raw payload), Virtual Account (mengembalikan nomor VA), E-Wallet, dan Gerai Retail (Alfamart/Indomaret).

Parameter BodyTipeWajib?Deskripsi
amountintegerWajibNominal deposit dalam Rupiah (min. Rp 1.000 untuk QRIS, min. Rp 10.000 untuk VA/Retail)
service_idstring / integerOpsionalKode saluran pembayaran (contoh: "11" = QRIS, "1" = BCA VA, "2" = BRI VA, "4" = BNI VA, "18" = Alfamart, dll. Default: "11")
methodstringOpsionalMetode pembayaran jika tidak mengirim service_id: "QRIS", "VA", "E-Wallet", "Retail"
phonestringOpsionalNomor HP pelanggan (wajib jika memilih metode OVO / service_id "12")
curl -s -X POST https://vtechotp.web.id/api/v1/deposits/create \
  -H "Authorization: Bearer vtk_your_api_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "service_id": "11"
  }'
201 Created Response (Contoh QRIS)
{
  "success": true,
  "data": {
    "id": "66ce30d97960cf1c8152e9f1",
    "internal_ref": "VTO1740645600000A1B",
    "method": "QRIS",
    "provider": "configured_gateway",
    "channel_code": "11",
    "channel_name": "QRIS Realtime",
    "amount": 10000,
    "fee": 100,
    "total_payment": 10100,
    "net_coins": 10000,
    "status": "pending",
    "qr_string": "00020101021226540014ID.LINKAJA.WWW0118936009110022201382021520021610212345...",
    "qr_image_url": "https://vtechotp.web.id/api/qr?data=00020101021226540014ID.LINKAJA.WWW0118...",
    "qr_image_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAFACAYAAAD6umHTAA...",
    "virtual_account": "",
    "payment_code": "",
    "payment_url": "https://vtechotp.web.id/payment/checkout/VTO1740645600000A1B",
    "payment_guide": null,
    "expires_at": "2026-08-30T17:40:00.000Z",
    "paid_at": null,
    "credited_at": null,
    "created_at": "2026-08-30T17:10:00.000Z",
    "instructions": "Silakan scan kode QRIS menggunakan aplikasi m-banking atau e-wallet (BCA, Mandiri, BRI, BNI, GoPay, OVO, DANA, ShopeePay). Saldo koin akan otomatis bertambah setelah pembayaran berhasil diverifikasi."
  }
}
💡 Panduan Menampilkan Gambar QRIS di Bot Telegram & Web:
  • Bot Telegram (Node.js/Telegraf): ctx.replyWithPhoto(data.qr_image_url, { caption: 'Silakan scan QRIS di atas...' })
  • Bot Telegram (Python/telebot): bot.send_photo(chat_id, photo=data['qr_image_url'], caption="Scan QRIS...")
  • Aplikasi Web / Frontend: Gunakan tag <img src="data.qr_image_url" alt="QRIS" width="280" /> atau render inline via data.qr_image_base64 tanpa perlu download manual.

Cek Status & Sinkronisasi Live Deposit

GET /deposits/{id} (alias: /deposits/{id}/status, /deposit/{id})

Mengecek status tagihan deposit menggunakan ID MongoDB (_id) atau Kode Referensi Internal (internal_ref). Jika deposit berstatus pending, endpoint ini secara otomatis melakukan live-sync ke payment gateway untuk memeriksa status pembayaran, mengkreditkan koin ke saldo Anda, dan memicu notifikasi serta webhook real-time jika telah lunas.

Parameter PathTipeWajib?Deskripsi
idstringWajibID deposit (MongoDB ObjectId) atau kode internalRef (contoh: VTO1740645600000A1B)
curl -s https://vtechotp.web.id/api/v1/deposits/VTO1740645600000A1B \
  -H "Authorization: Bearer vtk_your_api_token_here"
200 OK Response (Setelah Pembayaran Berhasil)
{
  "success": true,
  "data": {
    "id": "66ce30d97960cf1c8152e9f1",
    "internal_ref": "VTO1740645600000A1B",
    "method": "QRIS",
    "provider": "configured_gateway",
    "channel_code": "11",
    "channel_name": "QRIS Realtime",
    "amount": 10000,
    "fee": 100,
    "total_payment": 10100,
    "net_coins": 10000,
    "status": "credited",
    "qr_string": "000201010212...",
    "qr_image_url": "https://vtechotp.web.id/api/qr?data=000201010212...",
    "qr_image_base64": "data:image/png;base64,iVBORw0KGgo...",
    "expires_at": "2026-08-30T17:40:00.000Z",
    "paid_at": "2026-08-30T17:15:42.000Z",
    "credited_at": "2026-08-30T17:15:43.000Z",
    "created_at": "2026-08-30T17:10:00.000Z",
    "instructions": "Silakan scan kode QRIS menggunakan aplikasi m-banking atau e-wallet..."
  }
}

Riwayat Transaksi Deposit

GET /deposits (alias: /deposit/history)

Mengambil daftar seluruh riwayat pembuatan tagihan deposit yang pernah dibuat pada akun Anda, lengkap dengan pagination dan filter status.

Query ParamTipeWajib?Deskripsi
pageintegerTidakHalaman data (default: 1)
limitintegerTidakJumlah data per halaman (1 - 100, default: 20)
statusstringTidakFilter status transaksi: pending, credited, expired, failed
cURL Request
curl -s "https://vtechotp.web.id/api/v1/deposits?page=1&limit=10&status=credited" \
  -H "Authorization: Bearer vtk_your_api_token_here"
200 OK Response
{
  "success": true,
  "data": {
    "deposits": [
      {
        "id": "66ce30d97960cf1c8152e9f1",
        "internal_ref": "VTO1740645600000A1B",
        "method": "QRIS",
        "provider": "configured_gateway",
        "channel_code": "11",
        "channel_name": "QRIS Realtime",
        "amount": 10000,
        "fee": 100,
        "total_payment": 10100,
        "net_coins": 10000,
        "status": "credited",
        "qr_string": "000201010212...",
        "qr_image_url": "https://vtechotp.web.id/api/qr?data=000201010212...",
        "qr_image_base64": "data:image/png;base64,iVBORw0KGgo...",
        "expires_at": "2026-08-30T17:40:00.000Z",
        "paid_at": "2026-08-30T17:15:42.000Z",
        "credited_at": "2026-08-30T17:15:43.000Z",
        "created_at": "2026-08-30T17:10:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "total_pages": 1
    }
  }
}

Konfigurasi & Biaya Fee Deposit

GET /deposits/config (alias: /deposit/config)

Mendapatkan informasi batas minimum deposit, maksimum deposit, dan pengaturan biaya admin (fee) flat yang sedang aktif di sistem.

cURL Request
curl -s https://vtechotp.web.id/api/v1/deposits/config
200 OK Response
{
  "success": true,
  "data": {
    "min_deposit": 5000,
    "max_deposit": 5000000,
    "deposit_fee_flat": 100,
    "deposit_fee_percent": 0,
    "payment_provider": "configured_gateway",
    "supported_methods": ["QRIS", "Virtual Account", "E-Wallet", "Retail"],
    "currency": "IDR",
    "notes": "1 Coin = Rp 1. Biaya admin fee ditambahkan ke total tagihan pembayaran."
  }
}

Daftar Negara

GET /catalog/countries

Mendapatkan seluruh daftar negara yang tersedia beserta ID, kode ISO, dan kode panggilan telepon.

Daftar Layanan / Platform

GET /catalog/services

Mendapatkan daftar platform/aplikasi yang didukung (seperti WhatsApp, Telegram, Google, TikTok, Instagram, dll.).

Daftar Harga Produk (Pricelist)

GET /catalog/products

Mendapatkan daftar harga sewa nomor virtual real-time (setelah markup), ketersediaan stok, ID operator, dan catalog_product_id.

Query ParamTipeWajib?Deskripsi
country_idintegerTidakFilter berdasarkan ID negara (misal 6 untuk Indonesia)
platform_idintegerTidakFilter berdasarkan ID layanan (misal 1 untuk WhatsApp)
operator_idintegerTidakFilter berdasarkan ID operator tertentu

Buat Order (Sewa Nomor Virtual)

POST /orders/create

Membuat pesanan sewa nomor baru. Saldo koin akun Anda akan dipotong otomatis sesuai harga setelah markup.

Parameter BodyTipeWajib?Deskripsi
product_idintegerOpsionalID produk spesifik
catalog_product_idintegerOpsionalID katalog produk untuk routing otomatis
country_idintegerOpsionalID negara tujuan
platform_idintegerOpsionalID layanan/aplikasi
max_priceintegerOpsionalBatas harga maksimum dalam Rupiah
quantityintegerOpsionalJumlah nomor (1 - 10, default: 1)
cURL Request
curl -s -X POST https://vtechotp.web.id/api/v1/orders/create \
  -H "Authorization: Bearer vtk_your_api_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "country_id": 6,
    "platform_id": 1,
    "max_price": 3000
  }'
201 Created Response
{
  "success": true,
  "data": {
    "orders": [
      {
        "id": "6a85817c80524ba18c72834b",
        "order_id": 982145,
        "product_id": 142,
        "service": "WhatsApp",
        "country": "Indonesia",
        "phone_number": "+6281234567890",
        "price": 2500,
        "status": "ACTIVE",
        "expires_at": "2026-08-16T20:45:00.000Z",
        "created_at": "2026-08-16T20:25:00.000Z"
      }
    ]
  }
}

Detail Order & Status OTP

GET /orders/{id}

Mengambil status terkini nomor, waktu kedaluwarsa, dan kode SMS/OTP yang telah masuk.

Batalkan Order & Refund Saldo

POST /orders/{id}/cancel atau /orders/cancel

Membatalkan order yang masih berstatus ACTIVE (belum menerima SMS). Saldo koin yang telah dipotong akan langsung di-refund 100% ke akun Anda.

Selesaikan Order

POST /orders/{id}/finish atau /orders/finish

Menandai pesanan telah selesai setelah Anda berhasil memverifikasi OTP di aplikasi tujuan.

Notifikasi Webhook Real-time

Alih-alih melakukan polling manual, daftarkan Webhook URL (HTTPS) agar server VTechOTP otomatis mengirimkan notifikasi HTTP POST instan saat SMS/OTP tiba atau pesanan selesai.

Daftar Event Webhook:
• order.otp_received - Kode OTP telah masuk
• order.completed - Pesanan ditandai selesai
• order.canceled - Pesanan dibatalkan & saldo di-refund
• order.expired - Waktu sewa habis & saldo di-refund otomatis
• deposit.credited - Tagihan QRIS berhasil dibayar & saldo koin masuk ke akun
Contoh JSON Webhook Payload
{
  "event": "order.otp_received",
  "timestamp": 1786905500,
  "data": {
    "order_id": 982145,
    "service": "WhatsApp",
    "country": "Indonesia",
    "phone_number": "+6281234567890",
    "price": 2500,
    "status": "OTP_RECEIVED",
    "otp_code": "482910",
    "otp_message": "Kode WhatsApp Anda adalah 482-910",
    "expires_at": "2026-08-16T20:45:00.000Z"
  }
}

Verifikasi HMAC-SHA256 Signature

Setiap panggilan webhook menyertakan header X-Webhook-Signature untuk memastikan request benar-benar berasal dari server resmi VTechOTP.

const crypto = require('crypto');

app.post('/my-webhook-handler', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const webhookSecret = 'sec_your_webhook_secret_here';

  const expectedSig = 'sha256=' + crypto
    .createHmac('sha256', webhookSecret)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (signature !== expectedSig) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;
  if (event === 'order.otp_received') {
    console.log(`OTP Masuk: ${data.otp_code} untuk ${data.phone_number}`);
  } else if (event === 'deposit.credited') {
    console.log(`Deposit Berhasil: Rp ${data.net_coins} telah masuk.`);
  }

  res.status(200).send('OK');
});

Daftar Kode Error (Error Codes)

Kode ErrorHTTP StatusKeterangan
UNAUTHORIZED401Header API Token tidak disertakan dalam request
INVALID_TOKEN401API Token salah atau tidak terdaftar
PHONE_NOT_VERIFIED403Nomor WhatsApp belum diverifikasi pada akun Anda
API_ACCESS_DISABLED403Akses API untuk akun Anda dinonaktifkan oleh admin
SERVICE_MAINTENANCE503Layanan API secara global sedang dalam pemeliharaan
INSUFFICIENT_BALANCE409Saldo koin tidak mencukupi untuk melakukan order
MAX_ACTIVE_ORDERS_EXCEEDED429Maksimal 5 pesanan aktif secara bersamaan telah tercapai
NO_OFFER_AVAILABLE422Stok nomor untuk layanan/negara tersebut sedang kosong
ORDER_NOT_FOUND404Pesanan tidak ditemukan
MIN_DEPOSIT_ERROR422Nominal deposit di bawah batas minimum saluran pembayaran
MAX_DEPOSIT_ERROR422Nominal deposit melebihi batas maksimum saluran pembayaran
DEPOSIT_NOT_FOUND404Tagihan deposit tidak ditemukan
PAYMENT_CHANNEL_OFFLINE502 / 422Saluran pembayaran yang dipilih sedang gangguan/offline di payment gateway
GATEWAY_ERROR502Gagal berkomunikasi dengan gateway pembayaran