Calabay API
Developer Portal
Calabay API
Developer Portal
Semua Layanan REST API Normal & Berjalan

Dokumentasi Developer API OTP

Akses nomor virtual OTP secara terprogram untuk aktivasi akun WhatsApp dan berbagai provider SMS. Dibangun dengan arsitektur RESTful murni, autentikasi Bearer Token, dan format respon JSON yang konsisten.

7
Endpoint REST
4
Provider Gateway
60/m
Rate Limit Per Key
100%
Refund Otomatis

Base URL API

Semua request HTTP dikirimkan ke alamat server utama (Base URL) berikut:

Production API Endpoint HTTPS Active
BASE URL
Seluruh contoh cURL, Node.js, dan Python di bawah ini siap langsung Anda salin dan gunakan.

Autentikasi Bearer Token

Setiap request ke endpoint API harus menyertakan API Key aktif di dalam header Authorization.

Cara Mendapatkan API Key

  1. Buka bot Telegram Anda
  2. Tekan tombol menu 🔑 API Key (atau ketik perintah /apikey)
  3. Klik tombol Buat API Key Baru
  4. Salin dan simpan key berformat ck_live_... di tempat yang aman

Header Format

HTTP Header
Authorization: Bearer ck_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Perhatian Keamanan: Jangan membagikan API Key Anda ke repositori publik. Saldo koin yang digunakan oleh API adalah saldo akun bot Telegram Anda.

Rate Limiting

Setiap API key dibatasi maksimal 60 request per menit (sliding 60-second window). Status limit dikirimkan melalui response header:

Header Tipe Keterangan
X-RateLimit-Limit Integer Batas kuota maksimal per window (60)
X-RateLimit-Remaining Integer Sisa kuota request yang masih dapat digunakan
X-RateLimit-Reset Timestamp Waktu reset kuota dalam format detik Unix

Format & Kode Error

Semua respon error memiliki struktur JSON terpadu dengan HTTP status code yang representatif.

JSON Schema Error
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Saldo coin kamu tidak cukup. Silakan top up via bot."
  }
}
HTTP Error Code Penyebab & Solusi
401 UNAUTHORIZED Header Bearer token tidak ada atau tidak valid
402 INSUFFICIENT_BALANCE Saldo koin akun tidak mencukupi untuk order nomor ini
404 ORDER_NOT_FOUND Order ID tidak ditemukan atau milik user lain
404 SERVICE_NOT_FOUND ID Layanan atau provider tidak tersedia
409 ALREADY_PAID OTP telah sukses diterima, order tidak dapat dibatalkan
429 RATE_LIMITED Melebihi batas 60 req/menit. Tunggu sebelum request kembali
502 ORDER_FAILED Gateway provider sedang kehabisan stok atau error teknis
503 PROVIDER_DISABLED Provider tersebut sedang dinonaktifkan sementara

Daftar Endpoint REST

Klik pada setiap endpoint untuk melihat rincian parameter request, format header, dan struktur balasan payload.

GET /services Katalog layanan, harga koin, & stok

Mengambil seluruh daftar layanan nomor virtual yang tersedia beserta provider, harga koin, dan ketersediaan stok.

Query Parameters

ParameterTipeStatusDeskripsi
server string Opsional Filter server: server_1, server_2, sms_1, sms_2

Contoh Respon (200 OK)

200 OK JSON
{
  "success": true,
  "data": {
    "whatsapp": [
      {
        "service_id": "12",
        "name": "WhatsApp",
        "price": 2500,
        "stock": 180,
        "server": "server_1",
        "type": "whatsapp"
      }
    ],
    "sms": [
      {
        "service_id": "wa",
        "name": "WhatsApp (SMS)",
        "price": 3500,
        "stock": 500,
        "server": "sms_1",
        "type": "sms"
      }
    ]
  },
  "total": 32
}
GET /balance Cek saldo koin akun

Mengembalikan informasi saldo koin pengguna yang terasosiasi dengan API Key.

Contoh Respon (200 OK)

200 OK JSON
{
  "success": true,
  "data": {
    "balance": 50000,
    "balance_formatted": "Rp50.000",
    "is_reseller": false,
    "total_trx": 42
  }
}
POST /order Order & pesan nomor baru

Membuat pesanan nomor virtual baru. Saldo koin akan langsung dipotong sesuai tarif layanan.

Request Body (application/json)

FieldTipeStatusDeskripsi
service_id string Wajib ID layanan dari daftar /services
server string Wajib server_1 | server_2 | sms_1 | sms_2
country_id string SMS Saja ID negara (wajib jika memesan layanan SMS)
operator_id string Opsional ID operator tertentu

Contoh Request Body

Payload JSON
{
  "service_id": "12",
  "server": "server_1"
}

Contoh Respon (201 Created)

201 Created JSON
{
  "success": true,
  "data": {
    "order_id": "TRX_9281726481",
    "phone": "+6281234567890",
    "service": "WhatsApp",
    "server": "server_1",
    "price": 2500,
    "balance_after": 47500,
    "expires_at": "2026-09-22T02:24:00.000Z",
    "status": "waiting"
  }
}
GET /order/:id Cek status & ambil kode OTP

Lakukan polling ke endpoint ini setiap 3-5 detik sampai status berubah menjadi completed atau pesanan kedaluwarsa.

Tips Polling: Nilai :id adalah order_id yang didapat dari pemanggilan POST /order.

Contoh Respon — OTP Diterima (200 OK)

200 OK (Completed)
{
  "success": true,
  "data": {
    "order_id": "TRX_9281726481",
    "phone": "+6281234567890",
    "status": "completed",
    "otp": "892104",
    "sms_message": "Kode verifikasi WhatsApp Anda: 892-104",
    "service": "WhatsApp",
    "price": 2500
  }
}
POST /order/:id/cancel Batalkan order & refund koin

Membatalkan pesanan yang belum menerima kode OTP (status waiting). Seluruh koin dikembalikan 100% ke saldo akun.

Proteksi Anti-Exploit: Pesanan yang sudah menerima kode OTP tidak dapat dibatalkan dan akan mengembalikan error 409 ALREADY_PAID.

Contoh Respon (200 OK)

200 OK JSON
{
  "success": true,
  "data": {
    "order_id": "TRX_9281726481",
    "status": "cancelled",
    "refunded": true,
    "refund_amount": 2500,
    "balance_after": 50000
  }
}
POST /order/:id/retry Minta ulang kirim OTP (WA)

Meminta pengiriman ulang kode OTP untuk provider WhatsApp (maksimal 3 kali percobaan per order).

Contoh Respon (200 OK)

200 OK JSON
{
  "success": true,
  "data": {
    "order_id": "TRX_9281726481",
    "phone": "+6281234567890",
    "retry_count": 1,
    "max_retries": 3,
    "status": "waiting"
  }
}
GET /history Riwayat transaksi order

Mengambil daftar riwayat transaksi pemesanan nomor OTP dari akun Anda.

Query Parameters

ParameterTipeDefaultDeskripsi
limit integer 20 Jumlah data yang dikembalikan (maksimal 100)

Contoh Respon (200 OK)

200 OK JSON
{
  "success": true,
  "data": [
    {
      "order_id": "TRX_9281726481",
      "phone": "+6281234567890",
      "service": "WhatsApp",
      "price": 2500,
      "server": "server_1",
      "refunded": false,
      "date": "2026-09-22T01:45:12.000Z"
    }
  ],
  "total": 1
}

Contoh Integrasi Lengkap

Alur standar integrasi: 1. Beli Nomor2. Polling OTP3. Auto Cancel jika Timeout.

Shell / Bash
# 1. Pesan nomor OTP baru
curl -X POST __BASE_URL__/order \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service_id": "12", "server": "server_1"}'

# 2. Periksa status dan ambil kode OTP
curl -X GET __BASE_URL__/order/TRX_9281726481 \
  -H "Authorization: Bearer YOUR_API_KEY"

# 3. Batalkan pesanan jika tidak menerima kode
curl -X POST __BASE_URL__/order/TRX_9281726481/cancel \
  -H "Authorization: Bearer YOUR_API_KEY"
JavaScript / ES Modules
const axios = require("axios");

const API_KEY = "YOUR_API_KEY";
const BASE_URL = "__BASE_URL__";
const headers = { 
  Authorization: `Bearer ${API_KEY}`,
  "Content-Type": "application/json"
};

async function getOtpFlow() {
  try {
    // 1. Pesan nomor
    const orderRes = await axios.post(
      `${BASE_URL}/order`,
      { service_id: "12", server: "server_1" },
      { headers }
    );
    const order = orderRes.data.data;
    console.log("Nomor diperoleh:", order.phone);
    console.log("Order ID:", order.order_id);

    // 2. Polling kode OTP selama maksimal 2 menit (setiap 5 detik)
    for (let attempt = 0; attempt < 24; attempt++) {
      await new Promise(resolve => setTimeout(resolve, 5000));
      
      const pollRes = await axios.get(`${BASE_URL}/order/${order.order_id}`, { headers });
      const statusData = pollRes.data.data;

      if (statusData.status === "completed") {
        console.log("Kode OTP Masuk:", statusData.otp);
        return statusData.otp;
      }
    }

    // 3. Batalkan jika tidak ada kode yang masuk (otomatis refund)
    console.log("Timeout, membatalkan pesanan...");
    await axios.post(`${BASE_URL}/order/${order.order_id}/cancel`, {}, { headers });
    console.log("Order dibatalkan, saldo koin telah direfund.");
  } catch (error) {
    console.error("API Error:", error.response?.data || error.message);
  }
}

getOtpFlow();
Python 3
import time
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "__BASE_URL__"
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

def main():
    # 1. Pesan nomor
    res = requests.post(
        f"{BASE_URL}/order",
        json={"service_id": "12", "server": "server_1"},
        headers=headers
    ).json()

    order = res.get("data")
    order_id = order["order_id"]
    print(f"Nomor: {order['phone']} | Order ID: {order_id}")

    # 2. Polling kode OTP setiap 5 detik (max 2 menit)
    for _ in range(24):
        time.sleep(5)
        st = requests.get(f"{BASE_URL}/order/{order_id}", headers=headers).json()
        data = st.get("data", {})
        
        if data.get("status") == "completed":
            print(f"Kode OTP Masuk: {data.get('otp')}")
            return data.get("otp")

    # 3. Timeout, batalkan pesanan
    print("Timeout, membatalkan pesanan...")
    requests.post(f"{BASE_URL}/order/{order_id}/cancel", headers=headers)
    print("Pesanan dibatalkan & saldo koin direfund.")

if __name__ == "__main__":
    main()