Hướng Dẫn API SMSCode: Tích Hợp Số Ảo Vào Ứng Dụng Của Bạn

Hướng Dẫn API SMSCode: Tích Hợp Số Ảo Vào Ứng Dụng Của Bạn

TL;DR: API SMSCode cho phép tự động hóa toàn bộ quy trình mua số ảo và nhận OTP — đặt mua số, polling OTP, hủy đơn, kiểm tra số dư. Tích hợp trong dưới 50 dòng code, hỗ trợ mọi ngôn ngữ lập trình qua REST/HTTP. Giá từ $0.005/số với hoàn tiền tự động.

Nếu bạn là developer hoặc đang xây dựng hệ thống cần xác minh số điện thoại tự động ở quy mô lớn, API SMSCode là giải pháp cho phép tích hợp đầy đủ mà không cần thao tác thủ công.

Bài viết này hướng dẫn toàn diện cách sử dụng API — từ xác thực đến xử lý OTP hoàn chỉnh — với ví dụ code thực tế bằng Python, JavaScript, và cURL.

Tại Sao Cần API Số Ảo?

Khi bạn cần xác minh hàng chục hoặc hàng trăm tài khoản, làm thủ công qua dashboard web là không thực tế về mặt thời gian và chi phí nhân lực. API giải quyết vấn đề này bằng cách cho phép:

Tự động hóa hoàn toàn: Không cần con người can thiệp vào từng bước. Hệ thống tự mua số, chờ OTP, nhập OTP, và xử lý kết quả.

Tích hợp vào quy trình CI/CD: Automation testing với số điện thoại thực sự — test đăng ký người dùng, test luồng xác minh OTP, test toàn bộ onboarding flow.

Scale theo nhu cầu: Xử lý hàng chục đến hàng trăm đơn hàng song song (trong phạm vi rate limit). Hệ thống tự điều chỉnh, không cần thêm nhân lực.

Xây dựng sản phẩm trên nền tảng số ảo: Dùng số ảo như một infrastructure layer trong ứng dụng của bạn — cung cấp dịch vụ xác minh cho người dùng của bạn.

Quản lý chi phí programmatically: Theo dõi chi tiêu, phân tích tỷ lệ thành công theo dịch vụ/quốc gia, tối ưu ngân sách dựa trên dữ liệu thực.

Bắt Đầu — Lấy API Key

  1. Đăng ký tài khoản SMSCode nếu chưa có — miễn phí, chỉ cần email
  2. Đăng nhập vào dashboard
  3. Vào Account > API để xem và copy API key
  4. Nạp tiền vào tài khoản trước khi bắt đầu test thực tế

Bảo mật API key:

  • Lưu vào biến môi trường (environment variable), không hardcode trong source code
  • Không commit vào git repository — thêm vào .gitignore
  • Không chia sẻ key trên Slack, email, hoặc bất kỳ kênh nào
  • Nếu key bị lộ, tạo key mới ngay trong phần Account

Base URL Và Xác Thực

Base URL: https://api.smscode.gg/v1

Tất cả requests cần header xác thực:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Ví dụ cURL kiểm tra kết nối:

curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://api.smscode.gg/v1/balance

Các Endpoint Chính

Endpoint 1: Kiểm Tra Số Dư

GET /v1/balance

Response thành công:

{
  "success": true,
  "data": {
    "balance": 5.42,
    "currency": "USD"
  }
}

Dùng endpoint này để:

  • Kiểm tra trước khi đặt order để tránh lỗi insufficient balance
  • Monitoring số dư trong hệ thống tự động
  • Alert khi số dư xuống thấp

Endpoint 2: Xem Catalog — Số Khả Dụng

GET /v1/catalog?service=telegram&country=vn

Parameters:

  • service — tên dịch vụ (telegram, whatsapp, facebook, gmail…)
  • country — mã quốc gia ISO 2 chữ (vn, us, uk, ru, in…)

Response:

{
  "success": true,
  "data": {
    "products": [
      {
        "id": "vn_telegram_s1",
        "country": "VN",
        "service": "telegram",
        "price": 0.05,
        "available": 142
      },
      {
        "id": "vn_telegram_s2",
        "country": "VN",
        "service": "telegram",
        "price": 0.07,
        "available": 58
      }
    ]
  }
}

Kiểm tra available trước khi đặt order. Nếu available về 0, chuyển sang product khác hoặc quốc gia khác.


Endpoint 3: Tạo Đơn Hàng — Mua Số

POST /v1/orders
Content-Type: application/json

{
  "product_id": "vn_telegram_s1"
}

Response thành công:

{
  "success": true,
  "data": {
    "order_id": "ord_abc123xyz",
    "phone": "+84987654321",
    "status": "pending",
    "expires_at": "2026-03-16T10:30:00Z"
  }
}

Sau khi nhận được response này:

  1. Lưu order_id để poll sau
  2. Dùng phone để nhập vào ứng dụng đích
  3. Gọi API ứng dụng đích để yêu cầu gửi OTP đến số đó
  4. Bắt đầu polling endpoint tiếp theo

Endpoint 4: Polling OTP — Chờ Mã

GET /v1/orders/{order_id}

Response khi đang chờ:

{
  "success": true,
  "data": {
    "order_id": "ord_abc123xyz",
    "phone": "+84987654321",
    "status": "pending",
    "sms_code": null,
    "expires_at": "2026-03-16T10:30:00Z"
  }
}

Response khi OTP đến:

{
  "success": true,
  "data": {
    "order_id": "ord_abc123xyz",
    "phone": "+84987654321",
    "status": "completed",
    "sms_code": "847291",
    "received_at": "2026-03-16T10:25:43Z"
  }
}

Response khi hết hạn:

{
  "success": true,
  "data": {
    "order_id": "ord_abc123xyz",
    "status": "expired",
    "sms_code": null
  }
}

Khi status = expired, tiền tự động hoàn về tài khoản. Không cần gọi thêm endpoint nào.


Endpoint 5: Hủy Đơn Hàng

DELETE /v1/orders/{order_id}

Response:

{
  "success": true,
  "data": {
    "order_id": "ord_abc123xyz",
    "status": "cancelled",
    "refunded": 0.05
  }
}

Dùng endpoint này khi:

  • Bạn quyết định không dùng số nữa trước khi phiên hết hạn
  • Số bị từ chối bởi ứng dụng đích và không cần chờ thêm
  • Muốn hoàn tiền ngay thay vì chờ hết hạn tự nhiên

Ví Dụ Code Hoàn Chỉnh — Python

import requests
import time
import os

API_KEY = os.environ.get("SMSCODE_API_KEY")  # Lấy từ env, không hardcode
BASE_URL = "https://api.smscode.gg/v1"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}


def check_balance():
    """Kiểm tra số dư tài khoản"""
    response = requests.get(f"{BASE_URL}/balance", headers=HEADERS)
    data = response.json()
    if data["success"]:
        return data["data"]["balance"]
    raise Exception(f"Lỗi kiểm tra số dư: {data['error']['message']}")


def get_available_products(service, country="us"):
    """Lấy danh sách số khả dụng"""
    response = requests.get(
        f"{BASE_URL}/catalog",
        headers=HEADERS,
        params={"service": service, "country": country}
    )
    data = response.json()
    if data["success"]:
        products = [p for p in data["data"]["products"] if p["available"] > 0]
        return sorted(products, key=lambda x: x["price"])  # Sắp xếp theo giá
    return []


def buy_number(product_id):
    """Mua số ảo và trả về thông tin đơn hàng"""
    response = requests.post(
        f"{BASE_URL}/orders",
        headers=HEADERS,
        json={"product_id": product_id}
    )
    data = response.json()
    if data["success"]:
        return data["data"]
    raise Exception(f"Không thể mua số: {data['error']['code']}")


def wait_for_otp(order_id, timeout_seconds=120, poll_interval=5):
    """
    Poll OTP cho đến khi nhận được hoặc hết thời gian chờ.
    Returns: OTP string nếu thành công, None nếu thất bại/hết hạn
    """
    start = time.time()
    while time.time() - start < timeout_seconds:
        response = requests.get(
            f"{BASE_URL}/orders/{order_id}",
            headers=HEADERS
        )
        data = response.json()["data"]

        if data["status"] == "completed":
            return data["sms_code"]
        elif data["status"] in ("expired", "cancelled"):
            print(f"Phiên {order_id} đã kết thúc với status: {data['status']}")
            return None

        print(f"  Đang chờ OTP... ({int(time.time() - start)}s)")
        time.sleep(poll_interval)

    print(f"Timeout sau {timeout_seconds}s")
    return None


def cancel_order(order_id):
    """Hủy đơn hàng và hoàn tiền"""
    response = requests.delete(
        f"{BASE_URL}/orders/{order_id}",
        headers=HEADERS
    )
    return response.json()


def get_sms_for_service(service, country="us", max_retries=3):
    """
    Workflow hoàn chỉnh: mua số → chờ OTP.
    Tự động retry với số mới nếu thất bại.
    Returns: (phone_number, otp) hoặc (None, None)
    """
    products = get_available_products(service, country)
    if not products:
        print(f"Không có số khả dụng cho {service}/{country}")
        return None, None

    product = products[0]  # Chọn giá thấp nhất có sẵn
    print(f"Mua số {country.upper()} cho {service}, giá ${product['price']}")

    for attempt in range(max_retries):
        try:
            order = buy_number(product["id"])
            phone = order["phone"]
            order_id = order["order_id"]

            print(f"Đã mua số: {phone}")
            print("  Nhập số này vào ứng dụng và yêu cầu OTP...")

            # *** Đây là nơi bạn tích hợp với ứng dụng đích ***
            # Ví dụ: requests.post("https://target-app.com/api/send-sms", json={"phone": phone})

            otp = wait_for_otp(order_id)
            if otp:
                print(f"  OTP nhận được: {otp}")
                return phone, otp
            else:
                print(f"  Thất bại lần {attempt + 1}/{max_retries}")
        except Exception as e:
            print(f"  Lỗi lần {attempt + 1}: {e}")

    return None, None


# Sử dụng
if __name__ == "__main__":
    balance = check_balance()
    print(f"Số dư hiện tại: ${balance:.2f}")

    phone, otp = get_sms_for_service("telegram", country="vn")
    if phone and otp:
        print(f"\nThành công!\nSố: {phone}\nOTP: {otp}")
    else:
        print("\nThất bại — xem log ở trên để debug")

Ví Dụ Code — JavaScript (Node.js)

const API_KEY = process.env.SMSCODE_API_KEY;
const BASE_URL = 'https://api.smscode.gg/v1';
const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json'
};

async function checkBalance() {
  const res = await fetch(`${BASE_URL}/balance`, { headers });
  const { data } = await res.json();
  return data.balance;
}

async function getProducts(service, country = 'us') {
  const res = await fetch(`${BASE_URL}/catalog?service=${service}&country=${country}`, { headers });
  const { data } = await res.json();
  return data.products.filter(p => p.available > 0);
}

async function buyNumber(productId) {
  const res = await fetch(`${BASE_URL}/orders`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ product_id: productId })
  });
  const { data } = await res.json();
  return data;
}

async function waitForOtp(orderId, timeoutMs = 120000, pollMs = 5000) {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const res = await fetch(`${BASE_URL}/orders/${orderId}`, { headers });
    const { data } = await res.json();

    if (data.status === 'completed') return data.sms_code;
    if (data.status === 'expired' || data.status === 'cancelled') return null;

    await new Promise(r => setTimeout(r, pollMs));
  }
  return null;
}

async function cancelOrder(orderId) {
  const res = await fetch(`${BASE_URL}/orders/${orderId}`, {
    method: 'DELETE',
    headers
  });
  return res.json();
}

// Workflow hoàn chỉnh với retry logic
async function getSmsForService(service, country = 'us', maxRetries = 3) {
  const products = await getProducts(service, country);
  if (!products.length) {
    console.log(`Không có số khả dụng cho ${service}/${country}`);
    return null;
  }

  const product = products.sort((a, b) => a.price - b.price)[0];
  console.log(`Mua số ${country.toUpperCase()} cho ${service}, giá $${product.price}`);

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const order = await buyNumber(product.id);
      console.log(`Đã mua số: ${order.phone}`);

      // *** Nhập order.phone vào ứng dụng đích của bạn ở đây ***

      const otp = await waitForOtp(order.order_id);
      if (otp) {
        console.log(`OTP nhận được: ${otp}`);
        return { phone: order.phone, otp };
      }
      console.log(`Thất bại lần ${attempt}/${maxRetries}`);
    } catch (err) {
      console.error(`Lỗi lần ${attempt}: ${err.message}`);
    }
  }
  return null;
}

// Sử dụng
(async () => {
  const balance = await checkBalance();
  console.log(`Số dư: $${balance}`);

  const result = await getSmsForService('chatgpt', 'us');
  if (result) {
    console.log(`\nThành công!\nSố: ${result.phone}\nOTP: ${result.otp}`);
  }
})();

Xử Lý Lỗi

API trả về lỗi theo format nhất quán:

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Số dư không đủ để thực hiện đơn hàng này"
  }
}

Bảng mã lỗi và cách xử lý:

CodeÝ nghĩaCách xử lý
INSUFFICIENT_BALANCESố dư không đủNạp thêm tiền, hoặc check balance trước
PRODUCT_NOT_FOUNDProduct ID không tồn tạiKiểm tra product ID từ catalog
NO_NUMBERS_AVAILABLEHết số từ quốc gia đóThử quốc gia khác hoặc chờ
ORDER_EXPIREDPhiên đã hết hạnMua số mới
ORDER_NOT_FOUNDOrder ID không tồn tạiKiểm tra lại order ID
RATE_LIMITEDQuá nhiều requestsGiảm tần suất poll, thêm delay
INVALID_API_KEYAPI key không hợp lệKiểm tra API key trong Account
SERVICE_UNAVAILABLEDịch vụ tạm thời không khả dụngRetry sau 30-60 giây

Best Practices Cho Production

Polling thông minh — không poll quá dày: Poll mỗi 5 giây là hợp lý. Poll dày hơn không giúp OTP đến nhanh hơn mà chỉ lãng phí rate limit. Dùng exponential backoff nếu gặp lỗi liên tiếp: 5s → 10s → 20s → 40s.

Retry logic với số mới: Khi phiên expired mà không có OTP, mua số mới và thử lại thay vì từ bỏ. Tiền đã hoàn tự động. Logic retry tốt: 3 lần thử, sau đó log lỗi và alert.

Kiểm tra số dư trước khi batch: Trước khi bắt đầu batch lớn (10+ orders), check balance để đảm bảo đủ tiền. Dừng sớm khi số dư thấp hơn threshold.

MIN_BALANCE = 1.0  # $1 minimum
if check_balance() < MIN_BALANCE:
    raise Exception("Số dư quá thấp, hãy nạp thêm tiền")

Logging đầy đủ: Log tất cả: order_id, phone, service, country, kết quả, thời gian. Dữ liệu này giúp debug và tối ưu tỷ lệ thành công.

Không hardcode product_id: Product ID có thể thay đổi. Luôn gọi catalog API để lấy product ID hiện tại thay vì hardcode.

Xử lý concurrent orders: Nếu cần nhiều số cùng lúc, dùng async/await hoặc threading. Tuy nhiên không quá số lượng rate limit (60 orders/phút).

Health check định kỳ: Trong production, chạy health check mỗi giờ: kiểm tra balance, kiểm tra catalog có số khả dụng không, alert nếu có vấn đề.


Use Cases Thực Tế

Automation Testing: Tích hợp với Selenium, Playwright, hoặc Cypress để test toàn bộ luồng đăng ký người dùng bao gồm OTP verification. Môi trường staging cần tài khoản thật, API SMSCode cho phép điều này một cách programmatic.

# Ví dụ với Playwright
from playwright.sync_api import sync_playwright
from smscode_client import get_sms_for_service  # Hàm bạn viết ở trên

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://app-to-test.com/register")

    # Lấy số ảo
    result = get_sms_for_service("yourapp", "us")

    # Điền vào form
    page.fill("#phone-input", result["phone"])
    page.click("#send-otp-btn")

    # OTP đã có sẵn
    page.fill("#otp-input", result["otp"])
    page.click("#verify-btn")

    assert page.url.endswith("/dashboard")

Bulk Account Verification: Doanh nghiệp cần verify hàng trăm tài khoản mới (CRM seed data, test environment population, migration). API cho phép xử lý song song với quản lý rate limit tự động.

SaaS Product — Cung Cấp Xác Minh Cho Khách Hàng: Nếu bạn xây dựng sản phẩm yêu cầu xác minh số điện thoại, API SMSCode cho phép bạn cung cấp dịch vụ này mà không cần đầu tư vào hạ tầng SMS. Bạn là khách hàng của SMSCode, khách hàng của bạn là người dùng cuối.


FAQ

API có hỗ trợ webhook không?

Hiện tại API dùng polling model — bạn chủ động kiểm tra trạng thái order. Webhook (nhận thông báo chủ động khi OTP đến) đang trong roadmap phát triển. Polling với interval 5 giây hoạt động tốt trong hầu hết use case.

Có thể dùng API cho automation testing không?

Có — đây là một trong những use case phổ biến và được hỗ trợ tốt nhất. Tích hợp tốt với Selenium, Playwright, Puppeteer, Cypress. API response time thấp phù hợp với test runner có timeout chặt.

Giới hạn số lượng đơn hàng đồng thời là bao nhiêu?

Rate limit: 60 orders/phút và 300 status checks/phút. Với nhu cầu vượt quá giới hạn này, liên hệ hỗ trợ để thảo luận về plan phù hợp.

Làm thế nào để test API mà không tốn nhiều tiền?

Dùng quốc gia có giá thấp nhất ($0.005-0.01) để test logic code trước. Chọn dịch vụ có tỷ lệ thành công cao để giảm số lần thử thất bại. Sau khi logic ổn định, mới chuyển sang số premium cho production.

API có tài liệu Swagger/OpenAPI không?

Có — truy cập https://api.smscode.gg/docs sau khi đăng ký tài khoản. Tài liệu interactive cho phép test endpoint trực tiếp từ browser mà không cần viết code.

Có SDK chính thức không?

Hiện tại chưa có SDK chính thức — API REST đơn giản đủ để tích hợp trong dưới 50 dòng code với bất kỳ ngôn ngữ nào. Các ví dụ code trong bài này có thể dùng làm foundation.


Sẵn sàng tích hợp? Đăng ký SMSCode và lấy API key miễn phí ngay hôm nay. Tham khảo thêm số ảo cho kinh doanh và developer để khám phá toàn bộ capabilities, hoặc xem hướng dẫn nạp tiền để cấu hình tài khoản cho production.

Sẵn sàng thử SMSCode?

Tạo tài khoản và nhận số ảo đầu tiên trong chưa đầy hai phút.

Bắt đầu →