API nhận OTP qua email cho tool tự động: Python và Node.js

Nếu bạn viết tool đăng ký tài khoản test, chạy kiểm thử tự động hay xử lý đơn hàng cho nhiều khách, thao tác tay trên web sẽ không theo kịp. API của OTPGmail cho phép tool của bạn thuê email, đọc mã OTP và hủy đơn hoàn tiền bằng vài request HTTP. Bài này đi qua luồng chuẩn, kèm mã mẫu Python và Node.js ngắn gọn.

Luồng chuẩn: tạo đơn → poll lấy mã → dùng mã → hủy nếu không cần

  1. Gọi POST /v1/orders để thuê một địa chỉ cho dịch vụ đích. Tiền chỉ bị trừ khi cấp mail thành công.
  2. Đưa địa chỉ vào form đăng ký của dịch vụ đích.
  3. Poll GET /v1/orders/{orderId} mỗi 3–5 giây cho tới khi mảng otp có phần tử.
  4. Dùng mã. Trong 24 giờ, mã mới (đăng nhập, xác nhận thiết bị) tự được thêm vào cuối otp[] khi bạn tiếp tục poll.
  5. Nếu đổi ý trước khi có mã, gọi POST /v1/orders/{orderId}/cancel để hoàn tiền ngay. Không gọi gì cả thì sau 30 phút không có mã, hệ thống tự hủy và hoàn.

Xác thực và định dạng phản hồi

Bước 1: Xem dịch vụ và kho

GET /v1/services trả về danh sách dịch vụ với code, name, price, stock và trường icloud ({ price, stock } hoặc null nếu dịch vụ không có iCloud). Tool nên gọi endpoint này để kiểm tra kho trước khi tạo đơn hàng loạt, và để biết mã dịch vụ (ví dụ git cho GitHub, dr cho ChatGPT).

Bước 2: Tạo đơn thuê

POST /v1/orders
Authorization: Bearer <api_key>
Idempotency-Key: <UUID mới cho mỗi đơn>
Content-Type: application/json

{ "service": "git", "domain": "icloud.com" }

domain nhận gmail.com hoặc icloud.com; bỏ trống là gmail.com. Phản hồi là mảng đơn (vì có thể thuê nhiều đơn một lần bằng quantity), mỗi đơn gồm orderId, service, domain, email, status, price, otp: [], codeDeadlineAt, rentExpiresAt.

Luôn gửi Idempotency-Key là một UUID mới cho mỗi đơn mới. Khi request bị timeout và bạn retry, dùng lại đúng key cũ: hệ thống trả lại đơn đã tạo thay vì tạo đơn thứ hai.

Bước 3: Poll lấy mã

GET /v1/orders/{orderId} trả về đơn với trạng thái waiting_code (đang chờ), completed (đã có mã, vẫn nhận thêm trong 24 giờ) hoặc cancelled. Khi có mã, otp là mảng [{ "code": "123456", "receivedAt": ... }]. Poll mỗi 3–5 giây; nhanh hơn không giúp mã về sớm hơn mà chỉ chạm giới hạn tốc độ.

Bước 4: Hủy đơn

POST /v1/orders/{orderId}/cancel chỉ thành công khi đơn còn waiting_code và chưa có mã; khi đó tiền hoàn ngay vào số dư. Đơn đã có mã không hủy được (ORDER_NOT_CANCELLABLE).

Ví dụ Python

import time
import uuid
import requests

BASE = "https://otpgmail.net"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}


def rent(service, domain="gmail.com"):
    r = requests.post(
        f"{BASE}/v1/orders",
        json={"service": service, "domain": domain},
        headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
        timeout=30,
    )
    body = r.json()
    if not body.get("success"):
        raise RuntimeError(body["error"]["code"])
    return body["data"][0]  # data là mảng đơn


def wait_code(order_id, max_wait=600, interval=4):
    deadline = time.time() + max_wait
    while time.time() < deadline:
        body = requests.get(f"{BASE}/v1/orders/{order_id}", headers=HEADERS, timeout=30).json()
        order = body["data"]
        if order["otp"]:
            return order["otp"][-1]["code"]
        if order["status"] == "cancelled":
            return None
        time.sleep(interval)
    # Hết kiên nhẫn: hủy để hoàn tiền ngay thay vì đợi hệ thống tự hủy sau 30 phút
    requests.post(f"{BASE}/v1/orders/{order_id}/cancel", headers=HEADERS, timeout=30)
    return None


try:
    order = rent("git", domain="icloud.com")
except RuntimeError as e:
    if str(e) in ("DOMAIN_UNAVAILABLE", "NO_MAILS_AVAILABLE", "OUT_OF_STOCK"):
        order = rent("git", domain="gmail.com")  # rơi về Gmail
    else:
        raise

print("Email:", order["email"])
code = wait_code(order["orderId"])
print("OTP:", code)

Ví dụ Node.js

// Node 18+, chạy dưới dạng ES module
import { randomUUID } from "node:crypto";

const BASE = "https://otpgmail.net";
const HEADERS = { Authorization: `Bearer ${process.env.OTPGMAIL_API_KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function rent(service, domain = "gmail.com") {
  const res = await fetch(`${BASE}/v1/orders`, {
    method: "POST",
    headers: { ...HEADERS, "Content-Type": "application/json", "Idempotency-Key": randomUUID() },
    body: JSON.stringify({ service, domain }),
  });
  const body = await res.json();
  if (!body.success) throw new Error(body.error.code);
  return body.data[0]; // data là mảng đơn
}

async function waitCode(orderId, maxWaitMs = 600_000, intervalMs = 4000) {
  const deadline = Date.now() + maxWaitMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${BASE}/v1/orders/${orderId}`, { headers: HEADERS });
    const { data: order } = await res.json();
    if (order.otp.length) return order.otp.at(-1).code;
    if (order.status === "cancelled") return null;
    await sleep(intervalMs);
  }
  await fetch(`${BASE}/v1/orders/${orderId}/cancel`, { method: "POST", headers: HEADERS });
  return null;
}

let order;
try {
  order = await rent("git", "icloud.com");
} catch (e) {
  if (["DOMAIN_UNAVAILABLE", "NO_MAILS_AVAILABLE", "OUT_OF_STOCK"].includes(e.message)) {
    order = await rent("git", "gmail.com"); // rơi về Gmail
  } else throw e;
}
console.log("Email:", order.email);
console.log("OTP:", await waitCode(order.orderId));

Xử lý các tình huống thường gặp

Chọn gmail.com hay icloud.com trong tool

Chi tiết về định dạng iCloud ở bài mail iCloud nhận OTP và trang thuê iCloud.

Mẹo vận hành

Câu hỏi thường gặp

Lấy API key ở đâu?

Đăng nhập OTPGmail, vào trang Hồ sơ; mỗi tài khoản có một key riêng. Giữ key như mật khẩu: đặt trong biến môi trường, không đưa lên kho mã nguồn công khai.

Poll bao lâu một lần là hợp lý?

3–5 giây. Hệ thống có giới hạn tốc độ và việc kiểm tra hộp thư cũng có nhịp riêng, nên poll nhanh hơn không rút ngắn thời gian có mã.

Hủy đơn sau khi đã có mã có được hoàn tiền không?

Không. Chỉ đơn đang waiting_code và chưa có mã mới hủy được và hoàn 100%. Đơn đã có mã coi như hoàn thành.

Nhận mã thứ hai cho cùng đơn bằng cách nào?

Chỉ cần tiếp tục poll GET /v1/orders/{orderId} trong thời gian đơn còn hiệu lực (24 giờ, xem rentExpiresAt); mã mới tự được thêm vào cuối otp[], không tốn thêm tiền và không cần endpoint riêng.

Bắt đầu bằng cách tạo tài khoản và lấy API key tại trang thuê mail, xem bảng giá theo dịch vụ, và đọc tài liệu API đầy đủ. Các hướng dẫn khác có ở danh sách hướng dẫn; nếu cần đối chiếu với dịch vụ cụ thể, xem thuê mail GitHub.

Thuê mail nhận OTP ngay

Đăng ký miễn phí, chỉ trừ tiền khi thuê thành công. Không có mã trong 30 phút — hoàn tiền 100% tự động.

Không thấy dịch vụ bạn cần? Bấm Thêm dịch vụ trên trang thuê, admin bổ sung nếu hạ tầng hỗ trợ.