POST /apiv2/order1h
สร้างคำสั่งเช่า Energy ระยะเวลา 1 ชั่วโมงผ่านผู้ให้บริการ Energy หลายรายพร้อมระบบสลับการทำงานอัตโนมัติเมื่อเกิดข้อผิดพลาด (automatic failover)
URL ของ Endpoint
POST https://netts.io/apiv2/order1hHeaders ของคำขอ
| ส่วนหัว | จำเป็น | คำอธิบาย |
|---|---|---|
| Content-Type | ใช่ | application/json |
| X-API-KEY | ใช่ | คีย์ API ของคุณจากแดชบอร์ด Netts |
| X-Real-IP | ใช่ | ที่อยู่ IP จากรายการที่อนุญาต (whitelist) ของคุณ |
เนื้อหาของคำขอ
{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}พารามิเตอร์ของคำขอ
| พารามิเตอร์ | ชนิด | จำเป็น | คำอธิบาย |
|---|---|---|---|
| amount | integer | ใช่ | จำนวน Energy ที่ต้องการเช่า (ขั้นต่ำ: 61000, สูงสุด: 3000000) |
| receiveAddress | string | ใช่ | ที่อยู่ TRON ที่จะรับ Energy (รูปแบบ TRC-20) |
การเลือกผู้ให้บริการ
API จะเลือกผู้ให้บริการ Energy ที่เหมาะสมที่สุดโดยอัตโนมัติตามเกณฑ์ต่อไปนี้:
- ความคุ้มค่าด้านต้นทุน - ค้นหาราคาที่ต่ำที่สุดที่มีอยู่เสมอ
- ความพร้อมใช้งาน - มั่นใจได้ว่ามี Energy สำรองเพียงพอ
- ความน่าเชื่อถือ - ใช้ผู้ให้บริการที่มีอัตราความสำเร็จสูง
- ความเร็ว - ให้ความสำคัญกับเวลาในการจัดส่งที่เร็วที่สุดก่อน
ตัวอย่าง
cURL
curl -X POST https://netts.io/apiv2/order1h \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip" \
-d '{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}'Python
import requests
url = "https://netts.io/apiv2/order1h"
headers = {
"Content-Type": "application/json",
"X-API-KEY": "your_api_key",
"X-Real-IP": "your_whitelisted_ip"
}
payload = {
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
if response.status_code == 200:
detail = data.get('detail', {})
order_data = detail.get('data', {})
print(f"Order ID: {order_data.get('orderId')}")
print(f"Transaction Hash: {order_data.get('hash')}")
print(f"Energy Delivered: {order_data.get('energy')}")
print(f"Cost: {order_data.get('paidTRX')} TRX")
print(f"Delegate Address: {order_data.get('delegateAddress')}")
else:
error_detail = data.get('detail', data)
print(f"Error Code: {error_detail.get('code', 'N/A')}")
print(f"Error Message: {error_detail.get('msg', error_detail)}")การตอบกลับ
การตอบกลับสำเร็จ (200 OK)
{
"detail": {
"code": 10000,
"msg": "Successful, 2.23 TRX deducted",
"data": {
"orderId": "1H123456",
"paidTRX": 2.23,
"hash": "a1b2c3d4e5f6789...",
"delegateAddress": "TDelegatePoolAddress...",
"energy": 131050
}
}
}ฟิลด์การตอบกลับ
| ฟิลด์ | ชนิด | คำอธิบาย |
|---|---|---|
| detail.code | integer | เป็น 10000 เสมอสำหรับคำสั่งซื้อที่สำเร็จ |
| detail.msg | string | ข้อความแจ้งความสำเร็จพร้อมจำนวนเงินที่หัก |
| detail.data.orderId | string | ID คำสั่งซื้อแบบรวมศูนย์ (รูปแบบ: 1H{request_id}) |
| detail.data.paidTRX | number | ค่าใช้จ่ายทั้งหมดในหน่วย TRX (รวมค่าธรรมเนียมการเปิดใช้งานหากที่อยู่ยังไม่ได้เปิดใช้งาน) |
| detail.data.hash | string | null | แฮชธุรกรรม ฟิลด์นี้จะปรากฏเสมอแต่อาจว่างเปล่า - ผู้ให้บริการบางรายไม่ได้ส่งคืนแฮชในทันที ใช้ /apiv2/order_check หลังจากผ่านไป 1 นาทีเพื่อรับแฮช |
| detail.data.delegateAddress | string | ที่อยู่พูลที่ทำการมอบหมาย Energy |
| detail.data.energy | integer | จำนวน Energy + บัฟเฟอร์ (โดยทั่วไปคือ +50) |
การตอบกลับเมื่อเกิดข้อผิดพลาด
ข้อผิดพลาดในการตรวจสอบสิทธิ์ (401)
{
"detail": "Invalid API key or IP not in whitelist"
}ยอดคงเหลือไม่เพียงพอ (403)
{
"code": 1004,
"msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}บริการไม่พร้อมใช้งาน (503)
{
"code": 5003,
"msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}ข้อผิดพลาดจากผู้ให้บริการ (503)
{
"code": 5001,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5002,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5004,
"msg": "Energy provider requires higher minimum amount"
}ข้อผิดพลาดภายในเซิร์ฟเวอร์ (500)
{
"code": 5000,
"msg": "Internal server error occurred"
}การอ้างอิงรหัสข้อผิดพลาด
| รหัส | คำอธิบาย | สถานะ HTTP |
|---|---|---|
10000 | สำเร็จ | 200 |
10000 | สำเร็จ (การตอบกลับที่แคชไว้) | 208 |
- | คำขอที่ซ้ำกันกำลังอยู่ระหว่างการประมวลผล | 409 |
1004 | ยอดคงเหลือไม่เพียงพอ | 403 |
5000 | ข้อผิดพลาดภายในเซิร์ฟเวอร์ | 500 |
5001 | ผู้ให้บริการ Energy ไม่พร้อมใช้งาน | 503 |
5002 | ผู้ให้บริการ Energy ไม่พร้อมใช้งาน | 503 |
5003 | บริการ Energy ไม่พร้อมใช้งาน | 503 |
5004 | จำนวนไม่ถึงเกณฑ์ขั้นต่ำของผู้ให้บริการ Energy | 503 |
ขีดจำกัดอัตราการเรียกใช้
ขีดจำกัดอัตราคำขอต่อไปนี้ใช้กับ Endpoint นี้ (ต่อที่อยู่ IP):
| ช่วงเวลา | ขีดจำกัด | คำอธิบาย |
|---|---|---|
| 1 วินาที | 50 คำขอ | สูงสุด 50 คำขอต่อวินาที |
ส่วนหัวของ Rate Limit
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49เกินขีดจำกัดอัตราคำขอ (429)
{
"message": "API rate limit exceeded"
}การดำเนินการแบบ Idempotency
API รองรับ Idempotency เพื่อป้องกันไม่ให้เกิดการประมวลผลคำสั่งซื้อซ้ำซ้อน เมื่อคุณส่งคำขอที่เหมือนกันหลายรายการ ระบบจะทำให้มั่นใจได้ว่าคำสั่งซื้อนั้นจะได้รับการประมวลผลเพียงครั้งเดียวเท่านั้น
การทำงานของ Idempotency
ความเป็นเอกลักษณ์ของคำขอจะพิจารณาจากชุดค่าผสมของ:
- การประทับเวลาของคำขอ (หน้าต่างเวลา 1 วินาที)
- จำนวน Energy
- ที่อยู่ผู้รับ
- คีย์ API
คำขอแต่ละรายการจะได้รับหน้าต่างความเป็นเอกลักษณ์ 1 วินาที เพื่อปกป้องระบบจากการใช้งานในทางที่ผิดและรับประกันการประมวลผลที่ถูกต้อง คำขอที่มีพารามิเตอร์เหมือนกันจะไม่สามารถส่งได้บ่อยเกินกว่าหนึ่งครั้งต่อวินาที
พฤติกรรมปัจจุบัน: ระบบจะปกป้องไคลเอนต์โดยอัตโนมัติจากการลองส่งคำขอซ้ำโดยไม่ได้ตั้งใจสำหรับ Energy ที่ได้สั่งซื้อไปแล้ว หากคุณส่งคำขอเดิมซ้ำสองครั้งโดยไม่ได้ตั้งใจ คุณจะไม่ถูกเรียกเก็บเงินสองครั้ง
การระบุคีย์ของคุณเอง
คุณสามารถควบคุมการทำงานของ Idempotency ได้ด้วยตนเองโดยการส่งส่วนหัว X-Idempotency-Key เมื่อระบุส่วนหัวนี้ ค่าดังกล่าวเพียงอย่างเดียวจะเป็นตัวตัดสินว่าคำขอนั้นเป็นคำขอซ้ำหรือไม่ และจะไม่มีการใช้ชุดค่าผสมอัตโนมัติด้านบน เมื่อไม่ได้ระบุส่วนหัวนี้ จะไม่มีอะไรเปลี่ยนแปลง — เซิร์ฟเวอร์จะสร้างคีย์ให้คุณโดยอัตโนมัติ
| ส่วนหัว | X-Idempotency-Key |
| รูปแบบ | อักขระเลขฐานสิบหกตัวพิมพ์เล็ก 64 ตัวพอดี — ไดเจสต์ SHA-256 |
| อายุการใช้งาน | 24 ชั่วโมงนับจากคำขอแรกที่มีคีย์ดังกล่าว |
| ขอบเขต | บัญชีของคุณ ค่าเดียวกันที่ส่งโดยบัญชีอื่นจะไม่ส่งคืนผลลัพธ์ของคุณ |
คีย์ในรูปแบบอื่นใด — UUID ที่มีเครื่องหมายขีดคั่น, base64, เลขฐานสิบหกตัวพิมพ์ใหญ่ — จะถูกปฏิเสธด้วยสถานะ 400 ก่อนที่จะมีการสร้างคำสั่งซื้อและก่อนที่จะมีการคิดค่าบริการใดๆ:
{
"detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}รูปแบบนี้แตกต่างจาก Endpoint อื่นๆ
/apiv2/withdraw,/apiv2/bandwidthและ orchestrator ยอมรับคีย์ base64 ความยาว 16–64 อักขระ ส่วน Endpoint นี้ยอมรับเฉพาะไดเจสต์ฐานสิบหกความยาว 64 อักขระเท่านั้น ดังนั้นโค้ดสร้างคีย์ที่คัดลอกมาจาก Endpoint เหล่านั้นจะส่งคืนค่า 400 ที่นี่
วิธีการสร้างคีย์
สร้างคีย์ขึ้นมาจากคีย์ API ของคุณ ซึ่งจะทำให้ค่านั้นมีเอกลักษณ์เฉพาะสำหรับบัญชีของคุณ สามารถทำซ้ำได้ในการลองใหม่อีกครั้ง และเป็นไปไม่ได้ที่ผู้อื่นจะสร้างขึ้นมาให้ตรงกัน:
import hashlib
import hmac
def make_idempotency_key(api_key: str, address: str, amount: int, nonce: str) -> str:
message = f"{address}:{amount}:{nonce}"
return hmac.new(api_key.encode(), message.encode(), hashlib.sha256).hexdigest()
nonceเป็นของคำสั่งซื้อ ไม่ใช่ของคำขอ ให้เลือกค่านั้นเพียงครั้งเดียวเมื่อมีการสร้างคำสั่งซื้อในฝั่งของคุณ และส่งค่าเดิมนั้นไปในทุกการส่งคำสั่งซื้อดังกล่าว — ทั้งการพยายามครั้งแรกและทุกครั้งที่ลองส่งใหม่ การสร้างค่าใหม่ภายในฟังก์ชันการส่ง (str(uuid.uuid4())ในแต่ละการเรียกใช้) จะทำให้การพยายามแต่ละครั้งได้คีย์ที่แตกต่างกัน ดังนั้นการลองใหม่หลังจากหมดเวลาเชื่อมต่อจะถูกยอมรับเป็นคำสั่งซื้อที่สองและถูกเรียกเก็บเงินอีกครั้ง ทางเลือกที่ถูกต้องและง่ายที่สุดคือใช้ ID คำสั่งซื้อที่คุณมีอยู่แล้ว: มีอยู่ก่อนการพยายามครั้งแรกและคงอยู่แม้ว่าจะมีการรีสตาร์ตโปรเซสของคุณก็ตาม
# ทำเพียงครั้งเดียวเมื่อคำสั่งซื้อปรากฏขึ้นในระบบของคุณ
order = create_order(address="TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", amount=131000)
# ในการพยายามครั้งแรกและในทุกครั้งที่ลองใหม่ — ค่าอินพุตทั้งสามเหมือนเดิม คีย์เดิม
key = make_idempotency_key(API_KEY, order.address, order.amount, order.id)
headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"X-Idempotency-Key": key,
}คีย์มีอายุการใช้งาน 24 ชั่วโมง หลังจากนั้น nonce เดิมจะว่างอีกครั้งและสามารถเริ่มคำสั่งซื้อใหม่ได้
อย่าใช้ค่าที่ใครอื่นก็สามารถสร้างขึ้นมาได้ — เลขศูนย์ 64 ตัว, ไดเจสต์ของคำที่กำหนดไว้คงที่ คีย์จะแชร์พื้นที่ร่วมกันในทุกบัญชี การชนกันของคีย์ดังกล่าวจะไม่ทำให้คำสั่งซื้อของบัญชีอื่นถูกเปิดเผย แต่คำขอของคุณจะถูกปฏิเสธด้วยสถานะ 409 จนกว่าคีย์ของพวกเขาจะหมดอายุ ซึ่งไม่ใช่คำตอบที่คุณต้องการในระหว่างที่กำลังลองส่งคำขอใหม่
การสร้างคำสั่งซื้อที่เหมือนกันสองรายการ
ในบางครั้งคุณอาจต้องการสร้างคำสั่งซื้อเดิมซ้ำสองครั้งจริงๆ — จำนวน Energy เท่ากันไปยังที่อยู่เดียวกัน ต่อเนื่องกัน คีย์อัตโนมัติจะไม่สามารถแยกแยะความแตกต่างระหว่างกรณีนี้กับการลองส่งใหม่ได้: คำขอทั้งสองรายการเหมือนกันทุกไบต์ และสิ่งเดียวที่แยกพวกมันออกจากกันคือเวลาที่คำขอมาถึง
หากไม่มีคีย์ที่คุณกำหนดขึ้นเอง ผลลัพธ์จะขึ้นอยู่กับช่วงเวลาระหว่างคำขอทั้งสอง:
| ช่วงเวลาระหว่างคำขอทั้งสอง | สิ่งที่เกิดขึ้น |
|---|---|
| ภายในหน้าต่างเวลา 1 วินาทีเดียวกัน | คำขอที่สองจะถือเป็นคำขอซ้ำ คำขอนั้นจะไม่ถูกดำเนินการ: คุณจะได้รับ 208 และการตอบกลับของคำสั่งซื้อแรก ซึ่งรวมถึง orderId และจะไม่มีการเรียกเก็บเงินสำหรับคำขอนั้น |
| ห่างกันมากกว่าหนึ่งวินาที | ได้คีย์ที่แตกต่างกันสองคีย์ — คำสั่งซื้อทั้งสองจะถูกสร้างขึ้นและถูกคิดค่าบริการทั้งคู่ |
ดังนั้นหากคุณพึ่งพาคีย์อัตโนมัติ ให้เว้นช่วงเวลามากกว่าหนึ่งวินาทีระหว่างคำสั่งซื้อที่เหมือนกันสองรายการ และอ่านรหัสสถานะ: 208 หมายความว่าคำสั่งซื้อที่คุณเพิ่งส่งไปนั้นไม่ได้ถูกสร้างขึ้น
การหยุดพักเป็นเพียงการแก้ปัญหาชั่วคราว ไม่ใช่การแก้ปัญหาที่แท้จริง มันจะแยกทุกคำขอออกจากกัน รวมถึงคำขอที่คุณไม่เคยตั้งใจจะส่งซ้ำ — การลองใหม่หลังจากหมดเวลาเชื่อมต่อ, การดับเบิลคลิก, ข้อความที่ถูกส่งซ้ำโดยคิวของคุณ สิ่งเหล่านั้นก็มาถึงช้ากว่าหน้าต่างเวลาเช่นกัน ดังนั้นพวกมันจึงถูกสร้างเป็นคำสั่งซื้อแยกต่างหากและถูกคิดค่าบริการแยกกัน การหมดเวลาตอบกลับของ Endpoint นี้คือ 10 วินาที ซึ่งอยู่นอกหน้าต่างเวลาไปมากแล้ว: คีย์อัตโนมัติไม่สามารถปกป้องการลองใหม่ที่เกิดขึ้นหลังจากหมดเวลาเชื่อมต่อได้
คีย์ของคุณเองจะขจัดปัญหาการคาดเดาออกไป เนื่องจากการตัดสินใจจะย้ายไปยังฝั่งเดียวที่รู้คำตอบ:
| สิ่งที่คุณกำลังทำ | สิ่งที่คุณส่ง | ผลลัพธ์ |
|---|---|---|
| คำสั่งซื้อที่สองที่เป็นคำสั่งซื้อใหม่จริงๆ | nonce ใหม่ | ได้คีย์ใหม่ — คำสั่งซื้อถูกสร้างขึ้น |
| การลองใหม่ของคำสั่งซื้อที่คุณไม่ทราบผลลัพธ์ | nonce ของการพยายามครั้งแรก | ได้คีย์เดิม — 208, ได้รับการตอบกลับเดิม, ไม่มีการคิดค่าบริการซ้ำ |
แถวที่สองคือเหตุผลว่าทำไมส่วนหัวนี้จึงมีอยู่ และมักเป็นจุดที่การนำไปใช้งานเกิดข้อผิดพลาด: โปรดดูหมายเหตุใต้ วิธีการสร้างคีย์
รหัสสถานะ HTTP สำหรับคำขอซ้ำ
| รหัสสถานะ | ชื่อ | คำอธิบาย |
|---|---|---|
| 200 | OK | ประมวลผลคำสั่งซื้อสำเร็จ (คำขอแรก) |
| 208 | Already Reported | คำสั่งซื้อได้รับการประมวลผลแล้ว ส่งคืนการตอบกลับที่แคชไว้ |
| 409 | Conflict | คำขอกำลังอยู่ระหว่างการประมวลผล ห้ามลองส่งใหม่ |
คำขอซ้ำ - ประมวลผลแล้ว (208)
เมื่อได้รับคำขอซ้ำสำหรับคำสั่งซื้อที่เสร็จสมบูรณ์ไปแล้ว:
{
"detail": {
"code": 10000,
"msg": "Successful, 2.54 TRX deducted",
"data": {
"hash": "9e4c20e21e01e4c39b21b670d1ea1fc1e4b0de94d8fbd4c190d5378ba911dfae",
"energy": 65050,
"orderId": "1H70bcc7962a",
"paidTRX": 2.535,
"delegateAddress": "TNp5gsJhBmZFXgCdgjMgr8pEZ8fHgXUHDq"
}
},
"idempotency": {
"status": "completed",
"cached": true,
"original_created_at": "2025-12-03T10:34:49.104896"
}
}เนื้อหาการตอบกลับจะเหมือนกับการตอบกลับที่สำเร็จดั้งเดิมทุกประการ โดยมีออบเจกต์ idempotency เพิ่มเติมที่ระบุว่านี่คือการตอบกลับที่แคชไว้
คำขอซ้ำ - กำลังประมวลผล (409)
เมื่อคำขอซ้ำมาถึงในขณะที่คำขอดั้งเดิมยังคงอยู่ระหว่างการประมวลผล:
{
"success": false,
"error": "duplicate_request_processing",
"message": "This request is currently being processed. Please wait and do not retry.",
"idempotency_key": "b9e67b2412d33c92...",
"retry_after_seconds": 3
}คำแนะนำ: ให้รอตามเวลา retry_after_seconds ที่ระบุก่อนที่จะตรวจสอบสถานะคำสั่งซื้อ
แนวทางปฏิบัติที่ดีที่สุด
- อย่าส่งคำขอแบบขนานด้วยพารามิเตอร์เดียวกัน - ให้รอการตอบกลับของแต่ละคำขอ
- ใช้
nonceใหม่สำหรับทุกคำสั่งซื้อใหม่ และใช้nonceของการพยายามครั้งแรกสำหรับทุกการลองใหม่ของคำสั่งซื้อนั้น - อย่าสร้าง
nonceขึ้นใหม่ ณ เวลาส่ง — การลองใหม่จะต้องสร้างคีย์เดิมของการพยายามครั้งแรกขึ้นมาซ้ำ ไม่ใช่คีย์ใหม่ - จัดการกับการตอบกลับ 409 โดยการรอ ไม่ใช่การลองใหม่ทันที
- ตรวจสอบฟิลด์
idempotency.cachedเพื่อระบุการตอบกลับที่แคชไว้ — รหัส208หมายความว่าคำสั่งซื้อที่คุณเพิ่งส่งไปนั้นไม่ได้ถูกสร้างขึ้น
หมายเหตุ
- จัดส่ง Energy ทันทีเมื่อสร้างคำสั่งซื้อสำเร็จ (โดยทั่วไปภายใน 0.5-10 วินาที)
- การหมดเวลาตอบกลับของ API: สูงสุด 10 วินาที โดยทั่วไปจะตอบกลับภายในไม่เกิน 2 วินาที
- การเปิดใช้งานที่อยู่: หากที่อยู่ผู้รับยังไม่ได้เปิดใช้งาน Netts จะทำการเปิดใช้งานให้ในราคาต้นทุน
- ความล่าช้าในการเปิดใช้งาน: สำหรับที่อยู่ที่ยังไม่ได้เปิดใช้งาน การตอบกลับของ API อาจใช้เวลาสูงสุด 6 วินาทีเนื่องจากกระบวนการเปิดใช้งาน
- คำสั่งซื้อจะได้รับการประมวลผลตลอด 24 ชั่วโมงทุกวัน พร้อมระบบสลับผู้ให้บริการอัตโนมัติเมื่อเกิดข้อผิดพลาด
- จำนวน Energy ขั้นต่ำ: 61,000 หน่วย
- จำนวน Energy สูงสุด: 3,000,000 หน่วยต่อคำสั่งซื้อ
- Energy บัฟเฟอร์: เพิ่ม +50 หน่วยโดยอัตโนมัติเพื่อชดเชยจากผู้ให้บริการ (ไม่มีค่าใช้จ่าย)
- แฮชธุรกรรม: ฟิลด์นี้จะปรากฏเสมอแต่อาจว่างเปล่าหากผู้ให้บริการไม่ได้ส่งคืนในทันที หากต้องการรับแฮช ให้เรียกใช้ /apiv2/order_check ไม่เร็วกว่า 1 นาที หลังจากสร้างคำสั่งซื้อ
- การเลือกผู้ให้บริการ: เป็นไปโดยอัตโนมัติตามต้นทุนและความพร้อมใช้งาน
- รูปแบบ ID คำสั่งซื้อ:
1H{request_id}เพื่อการติดตามแบบรวมศูนย์ - ราคา: ปรับเปลี่ยนตามช่วงเวลาของวันและจำนวน Energy
- ระยะเวลา: คงที่ 1 ชั่วโมง (3600 วินาที)
- Rate Limiting: 50 คำขอต่อวินาทีต่อที่อยู่ IP