เอกสาร API
การเข้าถึงแบบโปรแกรมสำหรับเบอร์เสมือน คำสั่งซื้อ และยอดเงินในบัญชี
ภาพรวม
ฟิลด์เงินทั้งหมดบน API /v1 เป็น IDR (รูเปียห์อินโดนีเซีย) ในรูปแบบจำนวนเต็ม — ตัวอย่างเช่น "price": 15000 และ "balance": 500000 หมายถึง Rp 15,000 และ Rp 500,000 สำหรับการฉายภาพแบบ USD-native ของบัญชีแยกประเภทเดียวกัน ให้สลับไปใช้ API v2 ด้วยปุ่มสลับเวอร์ชันด้านบน
⟩การยืนยันตัวตน
คำขอ API ทั้งหมดต้องใช้ Bearer token สร้าง token จากตั้งค่าบัญชีในแดชบอร์ด แล้วใส่ในทุกคำขอ:
คำขอที่ไม่มี token ที่ถูกต้องจะได้รับการตอบกลับ 401 UNAUTHORIZED
⟩Base URL
เส้นทาง endpoint ทั้งหมดด้านล่างเป็น relative กับ:
⟩รูปแบบการตอบกลับ
ทุกการตอบกลับเป็น JSON ในรูปแบบ envelope ที่สอดคล้องกัน ทุกการตอบกลับมี header x-request-id สำหรับการดีบัก
{
"success": true,
"data": { ... }
} {
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message"
}
} ฟิลด์เงินทั้งหมดบน API /v1 เป็น IDR (รูเปียห์อินโดนีเซีย) ในรูปแบบจำนวนเต็ม — ตัวอย่างเช่น "price": 15000 และ "balance": 500000 หมายถึง Rp 15,000 และ Rp 500,000 สำหรับการฉายภาพแบบ USD-native ของบัญชีแยกประเภทเดียวกัน ให้สลับไปใช้ API v2 ด้วยปุ่มสลับเวอร์ชันด้านบน
/catalog/countries ส่งคืนรายการประเทศที่มีทั้งหมด
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v1/catalog/countries \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/catalog/countries", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/catalog/countries",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 6,
"code": "ID",
"name": "Indonesia",
"dial_code": "+62",
"emoji": "🇮🇩",
"active": true
}
]
} /catalog/services ส่งคืนรายการบริการ (แพลตฟอร์ม) ที่มี สามารถกรองตามประเทศได้
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
country_id | integer | ไม่ | กรองบริการที่มีสำหรับประเทศนี้ |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v1/catalog/services?country_id=6" \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/catalog/services?country_id=6", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/catalog/services",
params={"country_id": 6},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 3,
"code": "wa",
"name": "WhatsApp",
"active": true
}
]
} /catalog/products ส่งคืนรายการผลิตภัณฑ์ที่มีแบบแบ่งหน้า กรองตามประเทศและ/หรือแพลตฟอร์มได้
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
country_id | integer | ไม่ | กรองตามรหัสประเทศ |
platform_id | integer | ไม่ | กรองตามรหัสแพลตฟอร์ม/บริการ |
sort | string | ไม่ | การเรียงลำดับ: price_asc (ค่าเริ่มต้น), price_desc, available_asc, available_desc, name_asc, name_desc |
limit | integer | ไม่ | จำนวนผลลัพธ์ต่อหน้า (1-10,000 ค่าเริ่มต้น 1,000) |
page | integer | ไม่ | หมายเลขหน้า (ขั้นต่ำ 1 ค่าเริ่มต้น 1) |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v1/catalog/products?country_id=6&platform_id=3&limit=10&page=1" \
-H "Authorization: Bearer YOUR_API_TOKEN"const params = new URLSearchParams({
country_id: "6", platform_id: "3", limit: "10", page: "1",
});
const res = await fetch(`https://api.smscode.gg/v1/catalog/products?${params}`, {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/catalog/products",
params={"country_id": 6, "platform_id": 3, "limit": 10, "page": 1},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 142,
"name": "WhatsApp Indonesia",
"country_id": 6,
"platform_id": 3,
"catalog_product_id": 87,
"available": 42,
"price": 15000,
"active": true
}
],
"meta": { "page": 1, "limit": 10, "count": 1 }
} /catalog/exchange-rate ส่งคืนอัตราแลกเปลี่ยน USD/IDR ปัจจุบันที่ใช้สำหรับการแปลงสกุลเงิน
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
pair | string | ไม่ | คู่สกุลเงิน (ค่าเริ่มต้น: USD/IDR) |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR" \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/catalog/exchange-rate",
params={"pair": "USD/IDR"},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"pair": "USD/IDR",
"base_currency": "USD",
"quote_currency": "IDR",
"rate": 16250
}
} /balance ส่งคืนยอดเงินในบัญชีของผู้ใช้ที่ผ่านการยืนยันตัวตน
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v1/balance \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/balance", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/balance",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"currency": "IDR",
"balance": 500000
}
} /orders ส่งคืนรายการคำสั่งซื้อของผู้ใช้ที่ผ่านการยืนยันตัวตน เรียงตามล่าสุด รองรับการกรองตามสถานะและแบ่งหน้าด้วย offset
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
limit | integer | ไม่ | จำนวนผลลัพธ์สูงสุด (1-100 ค่าเริ่มต้น 20) |
offset | integer | ไม่ | จำนวนผลลัพธ์ที่ข้าม (ค่าเริ่มต้น 0) |
status | string | ไม่ | กรองตามสถานะ: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (ไม่คำนึงตัวพิมพ์เล็ก-ใหญ่) |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v1/orders?limit=5&status=ACTIVE" \
-H "Authorization: Bearer YOUR_API_TOKEN"const params = new URLSearchParams({
limit: "5", status: "ACTIVE", offset: "0",
});
const res = await fetch(`https://api.smscode.gg/v1/orders?${params}`, {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/orders",
params={"limit": 5, "status": "ACTIVE", "offset": 0},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 1001,
"status": "ACTIVE",
"created_at": "2026-02-25T10:00:00+00:00",
"product_id": 142,
"phone_number": "+6281234567890",
"amount": 15000,
"otp_code": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:20:00+00:00",
"canceled_at": null,
"failed_reason": null
}
]
} /orders/{id} ส่งคืนคำสั่งซื้อเดี่ยวตามรหัส ส่งคืนเฉพาะคำสั่งซื้อที่เป็นของผู้ใช้ที่ผ่านการยืนยันตัวตน
Path Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อ (path parameter) |
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v1/orders/1001 \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/orders/1001", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/orders/1001",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"id": 1001,
"status": "OTP_RECEIVED",
"created_at": "2026-02-25T10:00:00+00:00",
"product_id": 142,
"phone_number": "+6281234567890",
"amount": 15000,
"otp_code": "123456",
"otp_received_at": "2026-02-25T10:05:00+00:00",
"expires_at": "2026-02-25T10:20:00+00:00",
"canceled_at": null,
"failed_reason": null
}
} /orders/active แสดงคำสั่งซื้อที่กำลังดำเนินการทั้งหมด (ACTIVE + OTP_RECEIVED) ใช้เพื่อตรวจสอบการอัปเดตสถานะ OTP
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v1/orders/active \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/orders/active", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/orders/active",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 1001,
"status": "OTP_RECEIVED",
"otp_code": "123456",
"otp_message": "Your verification code is 123456",
"otp_received_at": "2026-02-25T10:05:00+00:00",
"expires_at": "2026-02-25T10:20:00+00:00",
"failed_reason": null
},
{
"id": 1002,
"status": "ACTIVE",
"otp_code": null,
"otp_message": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:50:00+00:00",
"failed_reason": null
}
]
} /orders/create สร้างคำสั่งซื้อเบอร์เสมือนใหม่ หักยอดเงินอัตโนมัติ รองรับ header Idempotency-Key เพื่อป้องกันคำสั่งซื้อซ้ำเมื่อลองส่งคำขอใหม่
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
product_id | integer | ไม่ | รหัสของผลิตภัณฑ์ที่จะสั่ง ระบุได้เพียงอย่างใดอย่างหนึ่ง: product_id หรือ catalog_product_id ไม่ใช่ทั้งสองอย่าง |
catalog_product_id | integer | ไม่ | รหัสผลิตภัณฑ์ที่คงที่ — เซิร์ฟเวอร์จะเลือกข้อเสนอที่ดีที่สุดในขณะนั้น (ถูกที่สุด โดยคำนึงถึงความน่าเชื่อถือ) ระบุรายการนี้หรือ product_id อย่างใดอย่างหนึ่ง |
max_price | integer · string | ไม่ | เพดานราคาแบบไม่บังคับ v1: จำนวนเต็ม IDR v2: สตริงทศนิยม USD (เช่น "0.50") |
prefer_provider | string | ไม่ | รหัสผู้ให้บริการแบบไม่บังคับ ใช้เป็นตัวตัดสินเมื่อข้อเสนอเท่ากัน |
policy | string | ไม่ | นโยบายการจัดเส้นทางแบบไม่บังคับ ใช้ได้เฉพาะกับ catalog_product_id เท่านั้น ค่าที่ใช้ได้: cheapest (ค่าเริ่มต้น) เลือกข้อเสนอที่พร้อมใช้งานและราคาต่ำสุด; best_success จัดอันดับข้อเสนอโดยให้ความสำเร็จในการส่งล่าสุดมาก่อน โดย best_success ให้คะแนนผู้ให้บริการแต่ละรายจากสัดส่วนคำสั่งซื้อที่ได้รับ OTP ในช่วง 30 วันเต็มล่าสุด แบ่งเป็นช่วงละ 10% และจะนับผู้ให้บริการรายนั้นก็ต่อเมื่อมีคำสั่งซื้ออย่างน้อย 20 รายการในช่วงเวลาดังกล่าว — ผู้ให้บริการที่ต่ำกว่าเกณฑ์นี้หรือยังไม่มีประวัติจะถือว่าเป็นกลาง จึงทำให้ข้อเสนอใหม่ไม่ถูกมองข้าม (ต้องเลือกใช้เอง; สัญญาณเริ่มต้นที่ค่ากลาง) หากตั้งค่า prefer_provider ไว้ด้วย ผู้ให้บริการที่เลือกไว้ก็ยังคงอยู่อันดับแรก |
quantity | integer | ไม่ | จำนวน (1-100 ค่าเริ่มต้น 1) |
ส่ง header Idempotency-Key เพื่อส่งคำขอซ้ำได้อย่างปลอดภัยโดยไม่สร้างคำสั่งซื้อซ้ำ key ประกอบด้วยตัวอักษร ตัวเลข ขีดกลาง และขีดล่าง (A-Z a-z 0-9 _ -) ได้ ยาวไม่เกิน 128 อักขระ key ที่ไม่ถูกต้องจะถูกปฏิเสธด้วย 422 VALIDATION_ERROR การส่งซ้ำด้วย key เดิมและ body เดิมจะเล่นผลลัพธ์เดิมซ้ำ (รวมถึง failed_count ของกรณีสำเร็จบางส่วน) การส่งซ้ำที่ไปถึงผู้ให้บริการแล้วแต่ล้มเหลวจะถูกบันทึกไว้และเล่นข้อผิดพลาดเดิมซ้ำ — ให้ใช้ key ใหม่เพื่อลองอีกครั้ง ความล้มเหลวที่ไม่มีผลข้างเคียง (ยอดเงินไม่พอ ไม่มีข้อเสนอที่ใช้ได้) จะปล่อย key คืน คุณจึงสามารถเติมเงินแล้วลองซ้ำด้วย key เดิมได้ การใช้ key เดิมซ้ำกับ body ที่ต่างออกไปจะคืนค่า 422 IDEMPOTENCY_KEY_REUSED และคำขอที่ยังทำงานอยู่ด้วย key นั้นจะคืนค่า 409 REQUEST_IN_PROGRESS ฟิลด์ failed_reason ในการตอบกลับของ create จะเป็น null เสมอ — จะมีค่าก็ต่อเมื่อ poll/list คำสั่งซื้อเท่านั้น
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v1/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-123" \
-d '{"product_id":142,"quantity":1}'
# Or order by stable catalog_product_id — the server picks the best current offer
# (cheapest, reliability-aware). Optional max_price caps the price; on v1 it is an
# IDR integer, on v2 it is a USD decimal string (e.g. "0.50"). prefer_provider
# (provider code) is a soft tie-breaker. Pass EITHER product_id OR catalog_product_id.
curl -s -X POST https://api.smscode.gg/v1/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-124" \
-d '{"catalog_product_id":87,"max_price":20000}'const res = await fetch("https://api.smscode.gg/v1/orders/create", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
"Idempotency-Key": "unique-request-id-123",
},
body: JSON.stringify({ product_id: 142, quantity: 1 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v1/orders/create",
json={"product_id": 142, "quantity": 1},
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"Idempotency-Key": "unique-request-id-123",
})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"orders": [
{
"id": 1002,
"status": "ACTIVE",
"product_id": 142,
"catalog_product_id": 87,
"amount": 15000,
"phone_number": "+6281234567891",
"otp_code": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:50:00+00:00",
"failed_reason": null
}
],
"failed_count": 0
}
} /orders/cancel ยกเลิกคำสั่งซื้อที่กำลังดำเนินการ ค่าเช่าจะถูกคืนเข้ายอดบัญชีของคุณ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะยกเลิก |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v1/orders/cancel \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v1/orders/cancel", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v1/orders/cancel",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "CANCELED",
"refund_amount": 15000,
"new_balance": 515000
}
} /orders/finish ทำเครื่องหมายคำสั่งซื้อว่าเสร็จสิ้นหลังจากได้รับ OTP การดำเนินการนี้จะปล่อยเบอร์ทันทีแทนที่จะรอให้หมดอายุ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะเสร็จสิ้น |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v1/orders/finish \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v1/orders/finish", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v1/orders/finish",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "COMPLETED"
}
} /orders/resend ขอให้แพลตฟอร์มส่ง SMS ซ้ำไปยังเบอร์ที่เช่า แพลตฟอร์มบางแห่งไม่รองรับการส่งซ้ำ — ตรวจสอบฟิลด์ resent ในการตอบกลับ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะส่ง SMS ซ้ำ |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v1/orders/resend \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v1/orders/resend", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v1/orders/resend",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "ACTIVE",
"resent": true
}
} /webhook ส่งคืนการตั้งค่า webhook notification ปัจจุบันของคุณ
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v1/webhook \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/webhook", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v1/webhook",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} /webhook อัปเดต URL และ/หรือ secret ของ webhook secret จะถูกสร้างอัตโนมัติเมื่อคุณตั้ง URL ครั้งแรก ส่งสตริงว่างเพื่อล้าง URL ต้องใช้ HTTPS
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
webhook_url | string | ไม่ | HTTPS URL สำหรับรับเหตุการณ์ webhook (สตริงว่างเพื่อล้าง) |
webhook_secret | string | ไม่ | Shared secret สำหรับ HMAC-SHA256 signature (สร้างอัตโนมัติหากไม่ระบุในครั้งแรก) |
ต้องระบุอย่างน้อยหนึ่งฟิลด์
ตัวอย่างคำขอ
curl -s -X PATCH https://api.smscode.gg/v1/webhook \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"webhook_url":"https://example.com/webhook"}'const res = await fetch("https://api.smscode.gg/v1/webhook", {
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ webhook_url: "https://example.com/webhook" }),
});
const data = await res.json();import requests
res = requests.patch("https://api.smscode.gg/v1/webhook",
json={"webhook_url": "https://example.com/webhook"},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} /webhook/test ส่งเหตุการณ์ทดสอบไปยัง URL webhook ที่ตั้งค่าไว้ ส่งคืนรหัสสถานะ HTTP จากเซิร์ฟเวอร์ของคุณ มีประโยชน์สำหรับตรวจสอบว่า endpoint ทำงานก่อนเริ่มใช้งานจริง
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v1/webhook/test \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v1/webhook/test", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v1/webhook/test",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"status_code": 200
}
} ⟩Webhook Notifications
ตั้งค่า URL webhook เพื่อรับการแจ้งเตือนแบบ push แบบเรียลไทม์สำหรับเหตุการณ์คำสั่งซื้อแทนการ polling นี่คือวิธีที่แนะนำสำหรับ bot script
เหตุการณ์
| เหตุการณ์ | ทริกเกอร์ |
|---|---|
order.otp_received | ส่ง OTP ไปยังเบอร์ที่เช่าแล้ว |
order.completed | คำสั่งซื้อถูกทำเครื่องหมายว่าเสร็จสิ้น (ด้วยตนเองหรือเมื่อหมดอายุ) |
order.expired | คำสั่งซื้อหมดอายุโดยไม่ได้ OTP (คืนเงินแล้ว) |
order.canceled | คำสั่งซื้อถูกยกเลิกโดยผู้ใช้ (คืนเงินแล้ว) |
Payload
{
"event": "order.otp_received",
"timestamp": "2026-02-25T12:00:00+00:00",
"data": {
"order_id": 1001,
"phone_number": "+628123456789",
"otp_code": "1234",
"otp_message": "Your verification code is 1234",
"product_id": 42,
"catalog_product_id": 87,
"country": "Indonesia",
"platform": "WhatsApp"
}
} การตรวจสอบ Signature
ทุกคำขอ webhook มี header X-Webhook-Signature พร้อม HMAC-SHA256 signature ของ request body โดยใช้ webhook_secret ของคุณเป็น key:
ตรวจสอบ signature นี้บนเซิร์ฟเวอร์ของคุณเพื่อยืนยันว่าคำขอเป็นของจริง การส่งเป็นแบบ fire-and-forget พร้อม timeout 3 วินาทีและไม่มีการลองใหม่
⟩Rate Limits
คำขอ API ถูกจำกัดอัตราตามกลุ่ม endpoint การเกินขีดจำกัดจะได้รับ 429 Too Many Requests พร้อม header Retry-After ที่ระบุจำนวนวินาทีที่ต้องรอ
| กลุ่ม Endpoint | ขีดจำกัด | ช่วงเวลา |
|---|---|---|
| Catalog (countries, services, products, exchange-rate) | 5,000 คำขอ | 60 วินาที |
| Balance | 600 คำขอ | 60 วินาที |
| Order reads (list, get, active) | 5,000 คำขอ | 60 วินาที |
| Order create | 3,000 คำขอ | 60 วินาที |
| Order cancel | 1,000 คำขอ | 60 วินาที |
| Order actions (finish, resend) | 1,000 คำขอ | 60 วินาที |
| Webhook config (get, update) | 600 คำขอ | 60 วินาที |
| Webhook test | 10 คำขอ | 60 วินาที |
⟩รหัสข้อผิดพลาด
การตอบกลับข้อผิดพลาดจะมีรหัสเหล่านี้ใน error.code:
| รหัส | HTTP | รายละเอียด |
|---|---|---|
UNAUTHORIZED | 401 | ไม่มีหรือ API token ไม่ถูกต้อง |
FORBIDDEN | 403 | การเข้าถึงถูกปฏิเสธ |
NOT_FOUND | 404 | ไม่พบทรัพยากร (คำสั่งซื้อ อัตราแลกเปลี่ยน ฯลฯ) |
CONFLICT | 409 | คำขอซ้ำหรือทรัพยากรขัดแย้ง |
INSUFFICIENT_BALANCE | 409 | ยอดเงินไม่เพียงพอสำหรับสร้างคำสั่งซื้อ |
VALIDATION_ERROR | 422 | พารามิเตอร์คำขอไม่ผ่านการตรวจสอบ |
RATE_LIMIT_EXCEEDED | 429 | คำขอมากเกินไป (ตรวจสอบ header Retry-After) |
INTERNAL_ERROR | 500 | ข้อผิดพลาดภายในเซิร์ฟเวอร์ |
PROVIDER_ERROR | 422 | ผู้ให้บริการ SMS ต้นทางปฏิเสธคำขอ เมื่อการสร้างคำสั่งซื้อล้มเหลว error อาจมี <code>details</code>: <code>cause_counts</code> (คำสั่งซื้อแบบ <code>product_id</code> เดิม — การนับจัดกลุ่มตามสาเหตุ) หรือ <code>attempts</code> (คำสั่งซื้อแบบ <code>catalog_product_id</code> — ผลลัพธ์ต่อความพยายามแต่ละครั้ง) โดยใช้ค่า <code>ok</code>, <code>no_numbers</code>, <code>insufficient_balance</code>, <code>price_rejected</code>, <code>provider_unavailable</code>, <code>provider_account_balance</code>, <code>provider_error</code> |
NO_OFFER_AVAILABLE | 422 | ไม่มีข้อเสนอที่ใช้งานอยู่ตรงกับผลิตภัณฑ์และนโยบายที่ร้องขอ (เพดานราคา ความพร้อมจำหน่าย) |
CANCEL_TOO_EARLY | 409 | คำสั่งซื้อใหม่เกินไปที่จะยกเลิก — รอ 2 นาที |
REQUEST_IN_PROGRESS | 409 | คำขอสร้างคำสั่งซื้อด้วย idempotency key นี้ยังทำงานอยู่ |
IDEMPOTENCY_KEY_REUSED | 422 | idempotency key นี้ถูกใช้กับ body คำขอที่ต่างออกไปแล้ว |
SERVICE_UNAVAILABLE | 503 | บริการไม่พร้อมให้บริการชั่วคราว (บำรุงรักษา) |
ภาพรวม
ฟิลด์เงินทั้งหมดบน API /v2 เป็น USD ส่งคืนเป็นออบเจ็กต์เงิน — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" } amount เป็นสตริงทศนิยม ส่วน canonical_amount คือค่าบัญชีแยกประเภท IDR ที่แม่นยำ (ใช้สำหรับการกระทบยอด) อัตรา rate USD/IDR ที่ใช้จะถูกเปิดเผยหนึ่งครั้งต่อการตอบกลับใน meta.fx v2 คือการฉายภาพ USD ขณะเรนเดอร์บนบัญชีแยกประเภท IDR เดียวกันกับ v1 — ไม่เคยจัดเก็บหรือทำธุรกรรมเป็น USD
⟩การยืนยันตัวตน
คำขอ API ทั้งหมดต้องใช้ Bearer token สร้าง token จากตั้งค่าบัญชีในแดชบอร์ด แล้วใส่ในทุกคำขอ:
คำขอที่ไม่มี token ที่ถูกต้องจะได้รับการตอบกลับ 401 UNAUTHORIZED
⟩Base URL
เส้นทาง endpoint ทั้งหมดด้านล่างเป็น relative กับ:
⟩รูปแบบการตอบกลับ
ทุกการตอบกลับเป็น JSON ในรูปแบบ envelope ที่สอดคล้องกัน ทุกการตอบกลับมี header x-request-id สำหรับการดีบัก
{
"success": true,
"data": { ... }
} {
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message"
}
} ข้อผิดพลาด v2: ไม่มีอัตราแลกเปลี่ยนที่ใช้ได้ (503)
{
"success": false,
"error": { "code": "FX_RATE_UNAVAILABLE", "message": "USD/IDR exchange rate is unavailable" }
} ฟิลด์เงินทั้งหมดบน API /v2 เป็น USD ส่งคืนเป็นออบเจ็กต์เงิน — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" } amount เป็นสตริงทศนิยม ส่วน canonical_amount คือค่าบัญชีแยกประเภท IDR ที่แม่นยำ (ใช้สำหรับการกระทบยอด) อัตรา rate USD/IDR ที่ใช้จะถูกเปิดเผยหนึ่งครั้งต่อการตอบกลับใน meta.fx v2 คือการฉายภาพ USD ขณะเรนเดอร์บนบัญชีแยกประเภท IDR เดียวกันกับ v1 — ไม่เคยจัดเก็บหรือทำธุรกรรมเป็น USD
/catalog/countries ส่งคืนรายการประเทศที่มีทั้งหมด
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v2/catalog/countries \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/catalog/countries", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/catalog/countries",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 6,
"code": "ID",
"name": "Indonesia",
"dial_code": "+62",
"emoji": "🇮🇩",
"active": true
}
]
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/catalog/services ส่งคืนรายการบริการ (แพลตฟอร์ม) ที่มี สามารถกรองตามประเทศได้
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
country_id | integer | ไม่ | กรองบริการที่มีสำหรับประเทศนี้ |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v2/catalog/services?country_id=6" \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/catalog/services?country_id=6", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/catalog/services",
params={"country_id": 6},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 3,
"code": "wa",
"name": "WhatsApp",
"active": true
}
]
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/catalog/products ส่งคืนรายการผลิตภัณฑ์ที่มีแบบแบ่งหน้า กรองตามประเทศและ/หรือแพลตฟอร์มได้
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
country_id | integer | ไม่ | กรองตามรหัสประเทศ |
platform_id | integer | ไม่ | กรองตามรหัสแพลตฟอร์ม/บริการ |
sort | string | ไม่ | การเรียงลำดับ: price_asc (ค่าเริ่มต้น), price_desc, available_asc, available_desc, name_asc, name_desc |
limit | integer | ไม่ | จำนวนผลลัพธ์ต่อหน้า (1-10,000 ค่าเริ่มต้น 1,000) |
page | integer | ไม่ | หมายเลขหน้า (ขั้นต่ำ 1 ค่าเริ่มต้น 1) |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v2/catalog/products?country_id=6&platform_id=3&limit=10&page=1" \
-H "Authorization: Bearer YOUR_API_TOKEN"const params = new URLSearchParams({
country_id: "6", platform_id: "3", limit: "10", page: "1",
});
const res = await fetch(`https://api.smscode.gg/v2/catalog/products?${params}`, {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/catalog/products",
params={"country_id": 6, "platform_id": 3, "limit": 10, "page": 1},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 142,
"name": "WhatsApp Indonesia",
"country_id": 6,
"platform_id": 3,
"catalog_product_id": 87,
"available": 42,
"price": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"active": true
}
],
"meta": { "page": 1, "limit": 10, "count": 1, "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/catalog/exchange-rate ส่งคืนอัตราแลกเปลี่ยน USD/IDR ปัจจุบันที่ใช้สำหรับการแปลงสกุลเงิน
พารามิเตอร์
ไม่มี — v2 ส่งคืน USD/IDR เสมอ; พารามิเตอร์ ?pair ของ v1 จะถูกละเว้น
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v2/catalog/exchange-rate?pair=USD/IDR" \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/catalog/exchange-rate?pair=USD/IDR", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/catalog/exchange-rate",
params={"pair": "USD/IDR"},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" }
} v2: ส่งคืน { pair, rate, rate_as_of } (ไม่มี base_currency/quote_currency ไม่มีตัวห่อ meta — อัตราคือข้อมูล) ?pair จะถูกละเว้น — v2 ส่งคืน USD/IDR เสมอ (v1 จะเคารพ ?pair) ส่งคืน 503 FX_RATE_UNAVAILABLE หากไม่มีอัตราที่ใช้ได้
/balance ส่งคืนยอดเงินในบัญชีของผู้ใช้ที่ผ่านการยืนยันตัวตน
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v2/balance \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/balance", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/balance",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"balance": { "amount": "30.77", "currency": "USD", "canonical_amount": 500000, "canonical_currency": "IDR" }
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/orders ส่งคืนรายการคำสั่งซื้อของผู้ใช้ที่ผ่านการยืนยันตัวตน เรียงตามล่าสุด รองรับการกรองตามสถานะและแบ่งหน้าด้วย offset
Query Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
limit | integer | ไม่ | จำนวนผลลัพธ์สูงสุด (1-100 ค่าเริ่มต้น 20) |
offset | integer | ไม่ | จำนวนผลลัพธ์ที่ข้าม (ค่าเริ่มต้น 0) |
status | string | ไม่ | กรองตามสถานะ: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (ไม่คำนึงตัวพิมพ์เล็ก-ใหญ่) |
ตัวอย่างคำขอ
curl -s "https://api.smscode.gg/v2/orders?limit=5&status=ACTIVE" \
-H "Authorization: Bearer YOUR_API_TOKEN"const params = new URLSearchParams({
limit: "5", status: "ACTIVE", offset: "0",
});
const res = await fetch(`https://api.smscode.gg/v2/orders?${params}`, {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/orders",
params={"limit": 5, "status": "ACTIVE", "offset": 0},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 1001,
"status": "ACTIVE",
"created_at": "2026-02-25T10:00:00+00:00",
"product_id": 142,
"phone_number": "+6281234567890",
"amount": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"otp_code": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:20:00+00:00",
"canceled_at": null,
"failed_reason": null
}
],
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/orders/{id} ส่งคืนคำสั่งซื้อเดี่ยวตามรหัส ส่งคืนเฉพาะคำสั่งซื้อที่เป็นของผู้ใช้ที่ผ่านการยืนยันตัวตน
Path Parameters
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อ (path parameter) |
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v2/orders/1001 \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/orders/1001", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/orders/1001",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"id": 1001,
"status": "OTP_RECEIVED",
"created_at": "2026-02-25T10:00:00+00:00",
"product_id": 142,
"phone_number": "+6281234567890",
"amount": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"otp_code": "123456",
"otp_received_at": "2026-02-25T10:05:00+00:00",
"expires_at": "2026-02-25T10:20:00+00:00",
"canceled_at": null,
"failed_reason": null
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/orders/active แสดงคำสั่งซื้อที่กำลังดำเนินการทั้งหมด (ACTIVE + OTP_RECEIVED) ใช้เพื่อตรวจสอบการอัปเดตสถานะ OTP
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v2/orders/active \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/orders/active", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/orders/active",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": [
{
"id": 1001,
"status": "OTP_RECEIVED",
"otp_code": "123456",
"otp_message": "Your verification code is 123456",
"otp_received_at": "2026-02-25T10:05:00+00:00",
"expires_at": "2026-02-25T10:20:00+00:00",
"failed_reason": null
},
{
"id": 1002,
"status": "ACTIVE",
"otp_code": null,
"otp_message": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:50:00+00:00",
"failed_reason": null
}
]
} v2: เอนด์พอยต์นี้ไม่เกี่ยวข้องกับเงิน — ไม่ส่งคืน amount และไม่ส่งคืน meta.fx (โครงสร้างเดียวกับ v1 ภายใต้ /v2)
/orders/create สร้างคำสั่งซื้อเบอร์เสมือนใหม่ หักยอดเงินอัตโนมัติ รองรับ header Idempotency-Key เพื่อป้องกันคำสั่งซื้อซ้ำเมื่อลองส่งคำขอใหม่
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
product_id | integer | ไม่ | รหัสของผลิตภัณฑ์ที่จะสั่ง ระบุได้เพียงอย่างใดอย่างหนึ่ง: product_id หรือ catalog_product_id ไม่ใช่ทั้งสองอย่าง |
catalog_product_id | integer | ไม่ | รหัสผลิตภัณฑ์ที่คงที่ — เซิร์ฟเวอร์จะเลือกข้อเสนอที่ดีที่สุดในขณะนั้น (ถูกที่สุด โดยคำนึงถึงความน่าเชื่อถือ) ระบุรายการนี้หรือ product_id อย่างใดอย่างหนึ่ง |
max_price | integer · string | ไม่ | เพดานราคาแบบไม่บังคับ v1: จำนวนเต็ม IDR v2: สตริงทศนิยม USD (เช่น "0.50") |
prefer_provider | string | ไม่ | รหัสผู้ให้บริการแบบไม่บังคับ ใช้เป็นตัวตัดสินเมื่อข้อเสนอเท่ากัน |
policy | string | ไม่ | นโยบายการจัดเส้นทางแบบไม่บังคับ ใช้ได้เฉพาะกับ catalog_product_id เท่านั้น ค่าที่ใช้ได้: cheapest (ค่าเริ่มต้น) เลือกข้อเสนอที่พร้อมใช้งานและราคาต่ำสุด; best_success จัดอันดับข้อเสนอโดยให้ความสำเร็จในการส่งล่าสุดมาก่อน โดย best_success ให้คะแนนผู้ให้บริการแต่ละรายจากสัดส่วนคำสั่งซื้อที่ได้รับ OTP ในช่วง 30 วันเต็มล่าสุด แบ่งเป็นช่วงละ 10% และจะนับผู้ให้บริการรายนั้นก็ต่อเมื่อมีคำสั่งซื้ออย่างน้อย 20 รายการในช่วงเวลาดังกล่าว — ผู้ให้บริการที่ต่ำกว่าเกณฑ์นี้หรือยังไม่มีประวัติจะถือว่าเป็นกลาง จึงทำให้ข้อเสนอใหม่ไม่ถูกมองข้าม (ต้องเลือกใช้เอง; สัญญาณเริ่มต้นที่ค่ากลาง) หากตั้งค่า prefer_provider ไว้ด้วย ผู้ให้บริการที่เลือกไว้ก็ยังคงอยู่อันดับแรก |
quantity | integer | ไม่ | จำนวน (1-100 ค่าเริ่มต้น 1) |
ส่ง header Idempotency-Key เพื่อส่งคำขอซ้ำได้อย่างปลอดภัยโดยไม่สร้างคำสั่งซื้อซ้ำ key ประกอบด้วยตัวอักษร ตัวเลข ขีดกลาง และขีดล่าง (A-Z a-z 0-9 _ -) ได้ ยาวไม่เกิน 128 อักขระ key ที่ไม่ถูกต้องจะถูกปฏิเสธด้วย 422 VALIDATION_ERROR การส่งซ้ำด้วย key เดิมและ body เดิมจะเล่นผลลัพธ์เดิมซ้ำ (รวมถึง failed_count ของกรณีสำเร็จบางส่วน) การส่งซ้ำที่ไปถึงผู้ให้บริการแล้วแต่ล้มเหลวจะถูกบันทึกไว้และเล่นข้อผิดพลาดเดิมซ้ำ — ให้ใช้ key ใหม่เพื่อลองอีกครั้ง ความล้มเหลวที่ไม่มีผลข้างเคียง (ยอดเงินไม่พอ ไม่มีข้อเสนอที่ใช้ได้) จะปล่อย key คืน คุณจึงสามารถเติมเงินแล้วลองซ้ำด้วย key เดิมได้ การใช้ key เดิมซ้ำกับ body ที่ต่างออกไปจะคืนค่า 422 IDEMPOTENCY_KEY_REUSED และคำขอที่ยังทำงานอยู่ด้วย key นั้นจะคืนค่า 409 REQUEST_IN_PROGRESS ฟิลด์ failed_reason ในการตอบกลับของ create จะเป็น null เสมอ — จะมีค่าก็ต่อเมื่อ poll/list คำสั่งซื้อเท่านั้น
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v2/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-123" \
-d '{"product_id":142,"quantity":1}'
# Or order by stable catalog_product_id — the server picks the best current offer
# (cheapest, reliability-aware). Optional max_price caps the price; on v1 it is an
# IDR integer, on v2 it is a USD decimal string (e.g. "0.50"). prefer_provider
# (provider code) is a soft tie-breaker. Pass EITHER product_id OR catalog_product_id.
curl -s -X POST https://api.smscode.gg/v2/orders/create \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-124" \
-d '{"catalog_product_id":87,"max_price":20000}'const res = await fetch("https://api.smscode.gg/v2/orders/create", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
"Idempotency-Key": "unique-request-id-123",
},
body: JSON.stringify({ product_id: 142, quantity: 1 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v2/orders/create",
json={"product_id": 142, "quantity": 1},
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"Idempotency-Key": "unique-request-id-123",
})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"orders": [
{
"id": 1002,
"status": "ACTIVE",
"product_id": 142,
"catalog_product_id": 87,
"amount": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"phone_number": "+6281234567891",
"otp_code": null,
"otp_received_at": null,
"expires_at": "2026-02-25T10:50:00+00:00",
"failed_reason": null
}
],
"failed_count": 0
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/orders/cancel ยกเลิกคำสั่งซื้อที่กำลังดำเนินการ ค่าเช่าจะถูกคืนเข้ายอดบัญชีของคุณ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะยกเลิก |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v2/orders/cancel \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v2/orders/cancel", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v2/orders/cancel",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "CANCELED",
"refund_amount": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"new_balance": { "amount": "31.69", "currency": "USD", "canonical_amount": 515000, "canonical_currency": "IDR" }
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
} v2: ฟิลด์เงินเป็นออบเจ็กต์เงิน USD และการตอบกลับมี meta.fx { pair, rate, rate_as_of } เพียงรายการเดียว rate คือ IDR จำนวนเต็มต่อ 1 USD ดังนั้น USD = canonical_amount / rate ยอดรวมใช้ทศนิยม 2 ตำแหน่ง ราคา/การคืนเงินต่อรายการใช้ 4 ตำแหน่ง จำนวนเงินที่เป็นบวกอย่างแท้จริงจะไม่ถูกปัดเป็น 0.00 rate_as_of คือเวลาประทับ RFC3339 ของอัตรา (รูปแบบ +00:00) หรือ null เมื่อไม่มีการบันทึกเวลาประทับ
เฉพาะ v2: หากไม่มีอัตรา USD/IDR ที่ใช้ได้ เอนด์พอยต์เงินจะส่งคืน 503 FX_RATE_UNAVAILABLE พร้อมเฮดเดอร์ Retry-After แทนที่จะเป็นเนื้อหาเงิน v1 ไม่เคยส่งคืนค่านี้
/orders/finish ทำเครื่องหมายคำสั่งซื้อว่าเสร็จสิ้นหลังจากได้รับ OTP การดำเนินการนี้จะปล่อยเบอร์ทันทีแทนที่จะรอให้หมดอายุ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะเสร็จสิ้น |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v2/orders/finish \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v2/orders/finish", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v2/orders/finish",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "COMPLETED"
}
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/orders/resend ขอให้แพลตฟอร์มส่ง SMS ซ้ำไปยังเบอร์ที่เช่า แพลตฟอร์มบางแห่งไม่รองรับการส่งซ้ำ — ตรวจสอบฟิลด์ resent ในการตอบกลับ
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
id | integer | ใช่ | รหัสคำสั่งซื้อที่จะส่ง SMS ซ้ำ |
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v2/orders/resend \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1001}'const res = await fetch("https://api.smscode.gg/v2/orders/resend", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v2/orders/resend",
json={"id": 1001},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"order_id": 1001,
"status": "ACTIVE",
"resent": true
}
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/webhook ส่งคืนการตั้งค่า webhook notification ปัจจุบันของคุณ
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s https://api.smscode.gg/v2/webhook \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/webhook", {
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.get("https://api.smscode.gg/v2/webhook",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/webhook อัปเดต URL และ/หรือ secret ของ webhook secret จะถูกสร้างอัตโนมัติเมื่อคุณตั้ง URL ครั้งแรก ส่งสตริงว่างเพื่อล้าง URL ต้องใช้ HTTPS
Request Body
| ชื่อ | ประเภท | จำเป็น | รายละเอียด |
|---|---|---|---|
webhook_url | string | ไม่ | HTTPS URL สำหรับรับเหตุการณ์ webhook (สตริงว่างเพื่อล้าง) |
webhook_secret | string | ไม่ | Shared secret สำหรับ HMAC-SHA256 signature (สร้างอัตโนมัติหากไม่ระบุในครั้งแรก) |
ต้องระบุอย่างน้อยหนึ่งฟิลด์
ตัวอย่างคำขอ
curl -s -X PATCH https://api.smscode.gg/v2/webhook \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"webhook_url":"https://example.com/webhook"}'const res = await fetch("https://api.smscode.gg/v2/webhook", {
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ webhook_url: "https://example.com/webhook" }),
});
const data = await res.json();import requests
res = requests.patch("https://api.smscode.gg/v2/webhook",
json={"webhook_url": "https://example.com/webhook"},
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
/webhook/test ส่งเหตุการณ์ทดสอบไปยัง URL webhook ที่ตั้งค่าไว้ ส่งคืนรหัสสถานะ HTTP จากเซิร์ฟเวอร์ของคุณ มีประโยชน์สำหรับตรวจสอบว่า endpoint ทำงานก่อนเริ่มใช้งานจริง
พารามิเตอร์
ไม่มี
ตัวอย่างคำขอ
curl -s -X POST https://api.smscode.gg/v2/webhook/test \
-H "Authorization: Bearer YOUR_API_TOKEN"const res = await fetch("https://api.smscode.gg/v2/webhook/test", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();import requests
res = requests.post("https://api.smscode.gg/v2/webhook/test",
headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()ตัวอย่างการตอบกลับ
{
"success": true,
"data": {
"status_code": 200
}
} เหมือนกับ v1 — เปลี่ยนเฉพาะเส้นทางฐาน (/v1 → /v2)
⟩Webhook Notifications
ตั้งค่า URL webhook เพื่อรับการแจ้งเตือนแบบ push แบบเรียลไทม์สำหรับเหตุการณ์คำสั่งซื้อแทนการ polling นี่คือวิธีที่แนะนำสำหรับ bot script
เหตุการณ์
| เหตุการณ์ | ทริกเกอร์ |
|---|---|
order.otp_received | ส่ง OTP ไปยังเบอร์ที่เช่าแล้ว |
order.completed | คำสั่งซื้อถูกทำเครื่องหมายว่าเสร็จสิ้น (ด้วยตนเองหรือเมื่อหมดอายุ) |
order.expired | คำสั่งซื้อหมดอายุโดยไม่ได้ OTP (คืนเงินแล้ว) |
order.canceled | คำสั่งซื้อถูกยกเลิกโดยผู้ใช้ (คืนเงินแล้ว) |
Payload
{
"event": "order.otp_received",
"timestamp": "2026-02-25T12:00:00+00:00",
"data": {
"order_id": 1001,
"phone_number": "+628123456789",
"otp_code": "1234",
"otp_message": "Your verification code is 1234",
"product_id": 42,
"catalog_product_id": 87,
"country": "Indonesia",
"platform": "WhatsApp"
}
} การตรวจสอบ Signature
ทุกคำขอ webhook มี header X-Webhook-Signature พร้อม HMAC-SHA256 signature ของ request body โดยใช้ webhook_secret ของคุณเป็น key:
ตรวจสอบ signature นี้บนเซิร์ฟเวอร์ของคุณเพื่อยืนยันว่าคำขอเป็นของจริง การส่งเป็นแบบ fire-and-forget พร้อม timeout 3 วินาทีและไม่มีการลองใหม่
⟩Rate Limits
คำขอ API ถูกจำกัดอัตราตามกลุ่ม endpoint การเกินขีดจำกัดจะได้รับ 429 Too Many Requests พร้อม header Retry-After ที่ระบุจำนวนวินาทีที่ต้องรอ
| กลุ่ม Endpoint | ขีดจำกัด | ช่วงเวลา |
|---|---|---|
| Catalog (countries, services, products, exchange-rate) | 5,000 คำขอ | 60 วินาที |
| Balance | 600 คำขอ | 60 วินาที |
| Order reads (list, get, active) | 5,000 คำขอ | 60 วินาที |
| Order create | 3,000 คำขอ | 60 วินาที |
| Order cancel | 1,000 คำขอ | 60 วินาที |
| Order actions (finish, resend) | 1,000 คำขอ | 60 วินาที |
| Webhook config (get, update) | 600 คำขอ | 60 วินาที |
| Webhook test | 10 คำขอ | 60 วินาที |
⟩รหัสข้อผิดพลาด
การตอบกลับข้อผิดพลาดจะมีรหัสเหล่านี้ใน error.code:
| รหัส | HTTP | รายละเอียด |
|---|---|---|
UNAUTHORIZED | 401 | ไม่มีหรือ API token ไม่ถูกต้อง |
FORBIDDEN | 403 | การเข้าถึงถูกปฏิเสธ |
NOT_FOUND | 404 | ไม่พบทรัพยากร (คำสั่งซื้อ อัตราแลกเปลี่ยน ฯลฯ) |
CONFLICT | 409 | คำขอซ้ำหรือทรัพยากรขัดแย้ง |
INSUFFICIENT_BALANCE | 409 | ยอดเงินไม่เพียงพอสำหรับสร้างคำสั่งซื้อ |
VALIDATION_ERROR | 422 | พารามิเตอร์คำขอไม่ผ่านการตรวจสอบ |
RATE_LIMIT_EXCEEDED | 429 | คำขอมากเกินไป (ตรวจสอบ header Retry-After) |
INTERNAL_ERROR | 500 | ข้อผิดพลาดภายในเซิร์ฟเวอร์ |
PROVIDER_ERROR | 422 | ผู้ให้บริการ SMS ต้นทางปฏิเสธคำขอ เมื่อการสร้างคำสั่งซื้อล้มเหลว error อาจมี <code>details</code>: <code>cause_counts</code> (คำสั่งซื้อแบบ <code>product_id</code> เดิม — การนับจัดกลุ่มตามสาเหตุ) หรือ <code>attempts</code> (คำสั่งซื้อแบบ <code>catalog_product_id</code> — ผลลัพธ์ต่อความพยายามแต่ละครั้ง) โดยใช้ค่า <code>ok</code>, <code>no_numbers</code>, <code>insufficient_balance</code>, <code>price_rejected</code>, <code>provider_unavailable</code>, <code>provider_account_balance</code>, <code>provider_error</code> |
NO_OFFER_AVAILABLE | 422 | ไม่มีข้อเสนอที่ใช้งานอยู่ตรงกับผลิตภัณฑ์และนโยบายที่ร้องขอ (เพดานราคา ความพร้อมจำหน่าย) |
CANCEL_TOO_EARLY | 409 | คำสั่งซื้อใหม่เกินไปที่จะยกเลิก — รอ 2 นาที |
REQUEST_IN_PROGRESS | 409 | คำขอสร้างคำสั่งซื้อด้วย idempotency key นี้ยังทำงานอยู่ |
IDEMPOTENCY_KEY_REUSED | 422 | idempotency key นี้ถูกใช้กับ body คำขอที่ต่างออกไปแล้ว |
SERVICE_UNAVAILABLE | 503 | บริการไม่พร้อมให้บริการชั่วคราว (บำรุงรักษา) |
FX_RATE_UNAVAILABLE | 503 | อัตราแลกเปลี่ยน USD/IDR ไม่พร้อมใช้งาน (เอนด์พอยต์เงิน v2) — ส่งคืน 503 พร้อมเฮดเดอร์ Retry-After |
⟩การย้ายจาก v1 ไป v2
v1 ให้บริการ IDR; v2 ให้บริการ USD ทั้งสองเวอร์ชันอยู่ร่วมกันถาวร — ไม่มีการยกเลิก เลือกหนึ่งเวอร์ชันต่อหนึ่งการเชื่อมต่อ อย่าปนเส้นทางฐาน v2 เหมือนกับ v1 ทุกประการ ยกเว้นวิธีการแสดงค่าเงิน
| ด้าน | v1 · IDR | v2 · USD |
|---|---|---|
| ฟิลด์เงิน | IDR จำนวนเต็ม เช่น 15000 | ออบเจ็กต์เงิน { amount, currency, canonical_amount, canonical_currency } |
meta.fx | ไม่มี | จำเป็นในทุกการตอบกลับที่เกี่ยวข้องกับเงิน |
| สกุลเงิน | IDR | USD (ฮาร์ดโค้ด) |
FX_RATE_UNAVAILABLE | — | 503 + Retry-After ใหม่ เมื่อไม่มีอัตราที่ใช้ได้ |
| ความแม่นยำ | — | ยอดรวม 2 ตำแหน่ง ราคา/คืนเงิน 4 ตำแหน่ง ปัดขึ้นสำหรับค่าบวก |
GET /catalog/exchange-rate | {pair, base_currency, quote_currency, rate}; เคารพ ?pair | {pair, rate, rate_as_of}; ละเว้น ?pair (USD/IDR เท่านั้น) |
ตัวอย่างเทียบเคียง
{
"success": true,
"data": {
"currency": "IDR",
"balance": 500000
}
}{
"success": true,
"data": {
"balance": { "amount": "30.77", "currency": "USD", "canonical_amount": 500000, "canonical_currency": "IDR" }
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
}{
"success": true,
"data": [
{
"id": 142,
"name": "WhatsApp Indonesia",
"country_id": 6,
"platform_id": 3,
"catalog_product_id": 87,
"available": 42,
"price": 15000,
"active": true
}
],
"meta": { "page": 1, "limit": 10, "count": 1 }
}{
"success": true,
"data": [
{
"id": 142,
"name": "WhatsApp Indonesia",
"country_id": 6,
"platform_id": 3,
"catalog_product_id": 87,
"available": 42,
"price": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"active": true
}
],
"meta": { "page": 1, "limit": 10, "count": 1, "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
}catalog_product_id คือรหัสระบุสินค้าที่คงที่ (หนึ่งรายการต่อประเทศ + แพลตฟอร์ม) — ปลอดภัยที่จะเก็บไว้ในระบบของคุณ และยังใช้สั่งซื้อได้โดยตรง: สั่งซื้อด้วย catalog_product_id (พร้อม max_price และ prefer_provider แบบไม่บังคับ) แล้วเซิร์ฟเวอร์จะเลือกข้อเสนอที่ใช้งานได้ให้คุณ ส่วนเส้นทางที่ใช้ product_id ของแต่ละข้อเสนอยังรองรับอยู่และเข้ากันได้แบบย้อนหลัง — id นั้นเปลี่ยนแปลงได้และจะเปลี่ยนทุกครั้งที่ระดับราคาของผู้ให้บริการขยับ ดังนั้นคำแนะนำให้ดึงแคตตาล็อกใหม่ก่อนสั่งซื้อจึงใช้กับเส้นทางนั้นเท่านั้น
{
"success": true,
"data": {
"order_id": 1001,
"status": "CANCELED",
"refund_amount": 15000,
"new_balance": 515000
}
}{
"success": true,
"data": {
"order_id": 1001,
"status": "CANCELED",
"refund_amount": { "amount": "0.9231", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" },
"new_balance": { "amount": "31.69", "currency": "USD", "canonical_amount": 515000, "canonical_currency": "IDR" }
},
"meta": { "fx": { "pair": "USD/IDR", "rate": 16250, "rate_as_of": "2026-05-27T08:00:00+00:00" } }
}เช็กลิสต์การย้าย
- เปลี่ยนเส้นทางฐาน
/v1→/v2 - แยกวิเคราะห์ฟิลด์เงินเป็นออบเจ็กต์ — อ่าน
amountเป็นสตริงทศนิยม;currencyคือ"USD" - สำหรับการกระทบยอดบัญชีแยกประเภท ให้ใช้
canonical_amount(IDR ที่แม่นยำ) ส่วนamountUSD เป็นการฉายภาพขณะเรนเดอร์ และrateจะถูกเปิดเผยหนึ่งครั้งในmeta.fx - จัดการ
FX_RATE_UNAVAILABLE(503) ใหม่ — ลองใหม่หลังRetry-Afterv1 ไม่เคยส่งคืนค่านี้