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
- 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. - Đưa địa chỉ vào form đăng ký của dịch vụ đích.
- Poll
GET /v1/orders/{orderId}mỗi 3–5 giây cho tới khi mảngotpcó phần tử. - 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. - 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
- Base URL:
https://otpgmail.net. Tài liệu đầy đủ tại tài liệu API. - API key riêng của mỗi tài khoản nằm ở trang Hồ sơ. Gửi qua header
Authorization: Bearer <api_key>(hoặc query?api_key=nếu môi trường không đặt được header). - Mọi phản hồi bọc trong
{ "success": true, "data": ... }; lỗi trả{ "success": false, "error": { "code", "message" } }kèm HTTP status tương ứng.
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
- NO_MAILS_AVAILABLE (HTTP 503) hoặc OUT_OF_STOCK (409): hết mail cho dịch vụ này, không bị trừ tiền. Thử
domaincòn lại, hoặc chờ vài phút rồi thử lại với backoff tăng dần. - DOMAIN_UNAVAILABLE (409): dịch vụ không có iCloud (ví dụ Apple ID) hoặc iCloud đang tạm tắt. Rơi về
gmail.comnhư ví dụ trên. - INSUFFICIENT_BALANCE (402): nạp thêm vào tài khoản; tool nên cảnh báo trước khi số dư xuống thấp.
- VALIDATION_ERROR (400): sai mã dịch vụ hoặc giá trị
domain. Lấy mã dịch vụ từGET /v1/services. - WAITING_LIMIT_REACHED (429): quá nhiều đơn đang chờ mã cùng lúc. Chờ các đơn cũ có mã hoặc hủy chúng trước khi tạo thêm.
- RATE_LIMITED: gọi quá nhanh. Giữ khoảng poll 3–5 giây và không tạo đơn dồn dập.
- Timeout phía bạn: quyết định ngưỡng chờ hợp lý theo dịch vụ (GitHub thường có mã sau ~30 giây, ChatGPT ~3–4 phút) rồi gọi cancel để hoàn tiền ngay, thay vì để đơn treo tới 30 phút.
Chọn gmail.com hay icloud.com trong tool
- iCloud rẻ hơn Gmail khoảng 10%, nên với khối lượng lớn hãy ưu tiên
icloud.comvà rơi vềgmail.comkhi gặpDOMAIN_UNAVAILABLEhoặc hết kho. - 114/115 dịch vụ có iCloud; kiểm tra trường
icloudtrongGET /v1/servicestrước khi gửi. - Kho iCloud là kho dùng chung, có lúc tạm hết rồi có lại; tool nên xử lý bằng fallback thay vì báo lỗi cứng.
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
- Lưu
orderIdvào cơ sở dữ liệu của bạn ngay khi tạo đơn, để có thể poll lại mã đăng nhập trong 24 giờ hoặc đối soát chi phí. - Ghi log mã lỗi thay vì chỉ ghi HTTP status; mã lỗi cho biết phải làm gì tiếp.
- Với nhu cầu hàng trăm mail cùng lúc, cân nhắc chế độ thuê theo lô trên web (tối đa 200 mail một lô, hiện chỉ Gmail).
- Tuân thủ điều khoản của dịch vụ đích về tài khoản tự động; tài khoản test cho developer là mục đích hợp lệ, tạo tài khoản hàng loạt để gây hại thì không. OTPGmail không chịu trách nhiệm cho việc dùng sai mục đích.
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.