POST /apiv2/order1h
Tạo đơn thuê energy thời hạn 1 giờ thông qua nhiều nhà cung cấp energy với cơ chế tự động chuyển đổi dự phòng (failover).
URL Endpoint
POST https://netts.io/apiv2/order1hHeaders của yêu cầu
| Header | Bắt buộc | Mô tả |
|---|---|---|
| Content-Type | Có | application/json |
| X-API-KEY | Có | Khóa API của bạn từ bảng điều khiển Netts |
| X-Real-IP | Có | Địa chỉ IP thuộc danh sách trắng của bạn |
Body của yêu cầu
{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}Tham số
| Tham số | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
| amount | số nguyên | Có | Lượng Energy cần thuê (tối thiểu: 61000, tối đa: 3000000) |
| receiveAddress | chuỗi | Có | Địa chỉ TRON sẽ nhận energy (định dạng TRC-20) |
Lựa chọn nhà cung cấp
API tự động lựa chọn nhà cung cấp energy tối ưu dựa trên:
- Hiệu quả chi phí - Luôn tìm mức giá khả dụng thấp nhất
- Tính khả dụng - Đảm bảo lượng dự trữ energy đầy đủ
- Độ tin cậy - Sử dụng các nhà cung cấp có tỷ lệ thành công cao
- Tốc độ - Ưu tiên thời gian bàn giao nhanh nhất
Yêu cầu mẫu
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)}")Phản hồi
Phản hồi thành công (200 OK)
{
"detail": {
"code": 10000,
"msg": "Successful, 2.23 TRX deducted",
"data": {
"orderId": "1H123456",
"paidTRX": 2.23,
"hash": "a1b2c3d4e5f6789...",
"delegateAddress": "TDelegatePoolAddress...",
"energy": 131050
}
}
}Các trường phản hồi
| Trường | Loại | Mô tả |
|---|---|---|
| detail.code | số nguyên | Luôn là 10000 cho các đơn hàng thành công |
| detail.msg | chuỗi | Thông báo thành công kèm theo số tiền đã trừ |
| detail.data.orderId | chuỗi | Mã định danh đơn hàng hợp nhất (định dạng: 1H{request_id}) |
| detail.data.paidTRX | số | Tổng chi phí bằng TRX (bao gồm phí kích hoạt nếu địa chỉ chưa được kích hoạt) |
| detail.data.hash | chuỗi | null | Hash giao dịch. Trường này luôn tồn tại nhưng có thể rỗng - một số nhà cung cấp không trả về hash ngay lập tức. Sử dụng /apiv2/order_check sau 1 phút để lấy hash |
| detail.data.delegateAddress | chuỗi | Địa chỉ pool đã ủy quyền (delegate) energy |
| detail.data.energy | số nguyên | Lượng Energy + phần dư dự phòng (thường là +50) |
Phản hồi lỗi
Lỗi xác thực (401)
{
"detail": "Invalid API key or IP not in whitelist"
}Không đủ số dư (403)
{
"code": 1004,
"msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}Dịch vụ không khả dụng (503)
{
"code": 5003,
"msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}Lỗi nhà cung cấp (503)
{
"code": 5001,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5002,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5004,
"msg": "Energy provider requires higher minimum amount"
}Lỗi máy chủ nội bộ (500)
{
"code": 5000,
"msg": "Internal server error occurred"
}Bảng tra cứu mã lỗi
| Mã | Mô tả | Trạng thái HTTP |
|---|---|---|
10000 | Thành công | 200 |
10000 | Thành công (phản hồi từ bộ nhớ đệm) | 208 |
- | Yêu cầu trùng lặp vẫn đang được xử lý | 409 |
1004 | Không đủ số dư | 403 |
5000 | Lỗi máy chủ nội bộ | 500 |
5001 | Nhà cung cấp energy không khả dụng | 503 |
5002 | Nhà cung cấp energy không khả dụng | 503 |
5003 | Dịch vụ energy không khả dụng | 503 |
5004 | Không đáp ứng mức tối thiểu của nhà cung cấp energy | 503 |
Giới hạn tốc độ
Các giới hạn tốc độ sau áp dụng cho endpoint này (trên mỗi địa chỉ IP):
| Khoảng thời gian | Giới hạn | Mô tả |
|---|---|---|
| 1 giây | 50 yêu cầu | Tối đa 50 yêu cầu mỗi giây |
Headers giới hạn tốc độ
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49Vượt quá giới hạn tốc độ (429)
{
"message": "API rate limit exceeded"
}Tính lũy quyền (Idempotency)
API hỗ trợ tính lũy quyền để ngăn ngừa việc xử lý đơn hàng trùng lặp. Khi bạn gửi nhiều yêu cầu giống hệt nhau, hệ thống đảm bảo đơn hàng chỉ được xử lý đúng một lần.
Cơ chế hoạt động của tính lũy quyền
Tính duy nhất của yêu cầu được xác định bởi sự kết hợp của:
- Dấu thời gian của yêu cầu (khoảng thời gian 1 giây)
- Lượng Energy
- Địa chỉ nhận
- Khóa API
Mỗi yêu cầu được cấp một khoảng thời gian duy nhất 1 giây. Để bảo vệ hệ thống khỏi việc lạm dụng và đảm bảo xử lý chính xác, các yêu cầu có tham số giống hệt nhau không thể gửi thường xuyên hơn một lần mỗi giây.
Hành vi hiện tại: Hệ thống tự động bảo vệ khách hàng khỏi các lần thử lại do nhầm lẫn đối với lượng energy đã được đặt. Nếu bạn vô tình gửi cùng một yêu cầu hai lần, bạn sẽ không bị tính phí hai lần.
Cung cấp khóa riêng của bạn
Bạn có thể chủ động kiểm soát tính lũy quyền bằng cách gửi header X-Idempotency-Key. Khi header này xuất hiện, chỉ riêng giá trị đó sẽ quyết định liệu một yêu cầu có phải là lặp lại hay không, và sự kết hợp tự động ở trên sẽ không được sử dụng. Khi nó vắng mặt, không có gì thay đổi — máy chủ sẽ tự suy ra khóa cho bạn.
| Header | X-Idempotency-Key |
| Định dạng | Chính xác 64 ký tự thập lục phân viết thường — một chuỗi băm SHA-256 |
| Thời gian tồn tại | 24 giờ kể từ yêu cầu đầu tiên mang khóa đó |
| Phạm vi | Tài khoản của bạn. Cùng một giá trị được gửi bởi một tài khoản khác không bao giờ trả về kết quả của bạn |
Một khóa có bất kỳ định dạng nào khác — UUID có dấu gạch ngang, base64, chữ hoa hex — đều bị từ chối với mã 400 trước khi đơn hàng được đặt và trước khi bất kỳ khoản phí nào bị trừ:
{
"detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}Định dạng này khác với các endpoint khác.
/apiv2/withdraw,/apiv2/bandwidthvà orchestrator chấp nhận khóa base64 từ 16–64 ký tự. Endpoint này chỉ chấp nhận chuỗi băm hex 64 ký tự, do đó mã tạo khóa được sao chép từ các endpoint đó sẽ trả về lỗi 400 tại đây.
Cách tạo khóa
Hãy tạo khóa bắt nguồn từ khóa API của bạn. Điều này giúp giá trị là duy nhất cho tài khoản của bạn, có thể tái tạo khi thử lại, và người khác không thể đoán ra được:
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()
noncethuộc về đơn hàng, không thuộc về yêu cầu. Hãy chọn nó một lần duy nhất khi đơn hàng được tạo phía bạn, và truyền cùng giá trị đó trong mỗi lần gửi của đơn hàng đó — bao gồm lần thử đầu tiên cũng như mọi lần thử lại. Việc tạo một giá trị mới bên trong hàm gửi (str(uuid.uuid4())ở mỗi lệnh gọi) sẽ khiến mỗi lần thử có một khóa khác nhau, vì vậy việc thử lại sau khi hết thời gian chờ (timeout) sẽ bị coi là một đơn hàng thứ hai và bị trừ tiền lần nữa. Lựa chọn đúng đắn và đơn giản nhất chính là mã ID đơn hàng bạn đã có sẵn: nó tồn tại trước lần thử đầu tiên và vẫn giữ nguyên kể cả khi tiến trình của bạn khởi động lại.
# một lần, khi đơn hàng xuất hiện trong hệ thống của bạn
order = create_order(address="TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", amount=131000)
# ở lần thử đầu tiên và ở mọi lần thử lại — cùng ba đầu vào, cùng một khóa
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,
}Một khóa tồn tại trong 24 giờ. Sau khoảng thời gian đó, cùng một nonce sẽ được tự do trở lại và bắt đầu một đơn hàng mới.
Không sử dụng giá trị mà bất kỳ ai khác cũng có thể tạo ra — 64 số không, chuỗi băm của một từ cố định. Các khóa dùng chung một không gian giữa các tài khoản. Sự trùng lặp như vậy không bao giờ để lộ đơn hàng của tài khoản khác, nhưng yêu cầu của bạn sẽ bị từ chối với mã 409 cho đến khi khóa của họ hết hạn, đây không phải là câu trả lời bạn mong muốn khi đang thử lại.
Đặt hai đơn hàng giống hệt nhau
Đôi khi bạn thực sự muốn tạo cùng một đơn hàng hai lần — cùng một lượng energy gửi đến cùng một địa chỉ, liên tiếp nhau. Khóa tự động không thể phân biệt điều đó với một lần thử lại: hai yêu cầu giống nhau đến từng byte, và điều duy nhất phân biệt chúng là thời điểm chúng đến nơi.
Nếu không có khóa riêng của bạn, kết quả sẽ phụ thuộc vào khoảng cách thời gian giữa chúng:
| Khoảng cách giữa hai yêu cầu | Điều gì xảy ra |
|---|---|
| Trong cùng khoảng thời gian 1 giây | Yêu cầu thứ hai bị coi là lặp lại. Nó không được thực thi: bạn nhận được 208 và phản hồi của đơn hàng đầu tiên, bao gồm cả orderId. Bạn không bị tính phí cho yêu cầu này |
| Cách nhau hơn một giây | Hai khóa khác nhau — cả hai đơn hàng đều được đặt và cả hai đều bị tính phí |
Vì vậy, nếu bạn dựa vào khóa tự động, hãy để khoảng cách nhiều hơn một giây giữa hai đơn hàng giống hệt nhau, và kiểm tra mã trạng thái: 208 có nghĩa là đơn hàng bạn vừa gửi đã không được đặt.
Việc tạm dừng chỉ là một giải pháp tình thế, không phải là cách khắc phục triệt để. Nó phân tách mọi yêu cầu, bao gồm cả những yêu cầu bạn không bao giờ có ý định lặp lại — một lần thử lại sau khi hết thời gian chờ, một lần nhấp đúp chuột, một tin nhắn được gửi lại bởi hàng đợi của bạn. Những yêu cầu đó cũng đến muộn hơn khoảng thời gian 1 giây, vì vậy chúng được đặt thành các đơn hàng riêng biệt và bị tính phí riêng biệt. Thời gian chờ phản hồi của endpoint này là 10 giây, đã vượt xa khoảng thời gian quy định: khóa tự động không bảo vệ được lần thử lại diễn ra sau khi hết thời gian chờ.
Khóa riêng của bạn giúp loại bỏ việc phỏng đoán, vì quyền quyết định được chuyển về phía duy nhất biết rõ câu trả lời:
| Bạn đang làm gì | Thứ bạn gửi | Kết quả |
|---|---|---|
| Một đơn hàng thứ hai, thực sự mới | Một nonce mới | Một khóa mới — đơn hàng được đặt |
| Một lần thử lại của đơn hàng mà bạn chưa biết kết quả | nonce của lần thử đầu tiên | Cùng một khóa — 208, phản hồi ban đầu, không bị trừ tiền lần hai |
Hàng thứ hai chính là lý do header này tồn tại, và cũng là nơi các triển khai thường mắc lỗi: xem lưu ý bên dưới mục Cách tạo khóa.
Mã trạng thái HTTP cho các yêu cầu trùng lặp
| Mã trạng thái | Tên | Mô tả |
|---|---|---|
| 200 | OK | Đơn hàng đã được xử lý thành công (yêu cầu đầu tiên) |
| 208 | Already Reported | Đơn hàng đã được xử lý trước đó, trả về phản hồi từ bộ nhớ đệm |
| 409 | Conflict | Yêu cầu hiện đang được xử lý, không thử lại |
Yêu cầu trùng lặp - Đã được xử lý (208)
Khi nhận được một yêu cầu trùng lặp cho một đơn hàng đã hoàn tất:
{
"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"
}
}Nội dung phản hồi giống hệt với phản hồi thành công ban đầu, có thêm đối tượng idempotency cho biết đây là phản hồi từ bộ nhớ đệm.
Yêu cầu trùng lặp - Vẫn đang xử lý (409)
Khi một yêu cầu trùng lặp đến trong khi yêu cầu ban đầu vẫn đang được xử lý:
{
"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
}Khuyến nghị: Chờ đúng số giây được chỉ định trong retry_after_seconds trước khi kiểm tra trạng thái đơn hàng.
Các phương pháp hay nhất
- Không gửi các yêu cầu song song có cùng tham số - hãy đợi phản hồi của từng yêu cầu
- Sử dụng
noncemới cho mỗi đơn hàng mới, và dùng lạinoncecủa lần thử đầu tiên cho mỗi lần thử lại của đơn hàng đó - Không bao giờ tạo lại
noncetại thời điểm gửi — lần thử lại phải tái tạo đúng khóa của lần thử đầu tiên, không phải một khóa mới - Xử lý các phản hồi 409 bằng cách chờ đợi, không thử lại ngay lập tức
- Kiểm tra trường
idempotency.cachedđể xác định các phản hồi từ bộ nhớ đệm — mã208có nghĩa là đơn hàng bạn vừa gửi đã không được đặt
Ghi chú
- Energy được bàn giao ngay lập tức sau khi đặt hàng thành công (thường trong vòng 0.5-10 giây)
- Thời gian chờ phản hồi API: Tối đa 10 giây, thường phản hồi trong vòng tối đa 2 giây
- Kích hoạt địa chỉ: Nếu địa chỉ nhận chưa được kích hoạt, Netts sẽ kích hoạt địa chỉ đó theo giá vốn
- Độ trễ kích hoạt: Đối với các địa chỉ chưa được kích hoạt, phản hồi API có thể mất tới 6 giây do quy trình kích hoạt
- Các đơn hàng được xử lý 24/7 với cơ chế tự động chuyển đổi dự phòng nhà cung cấp
- Lượng Energy tối thiểu: 61.000 đơn vị
- Lượng Energy tối đa: 3.000.000 đơn vị mỗi đơn hàng
- Phần dư Energy dự phòng: +50 đơn vị được cộng tự động để bù trừ cho nhà cung cấp (miễn phí)
- Hash giao dịch: Trường này luôn tồn tại nhưng có thể rỗng nếu nhà cung cấp không trả về ngay lập tức. Để lấy hash, hãy gọi /apiv2/order_check không sớm hơn 1 phút sau khi đặt đơn hàng
- Lựa chọn nhà cung cấp: Tự động dựa trên chi phí và tính khả dụng
- Định dạng mã đơn hàng:
1H{request_id}để theo dõi hợp nhất - Định giá: Linh hoạt dựa trên thời gian trong ngày và lượng energy
- Thời hạn: Cố định 1 giờ (3600 giây)
- Giới hạn tốc độ: 50 yêu cầu mỗi giây trên mỗi địa chỉ IP