POST /apiv2/withdraw
Netts bakiyenizden herhangi bir TRON adresine TRX çekin. İstek anında bir sipariş numarası döndürür; asıl zincir üstü (on-chain) ödeme arka uç tarafından asenkron olarak gerçekleştirilir (~5 dakika içinde). Sonucu durum uç noktasını sorgulayarak (polling) veya bir webhook yapılandırarak takip edin.
ℹ️ Nasıl çalışır. Çekim talebi vermek tutarı anında bakiyenizden ayırır (rezerve eder) (sipariş kabul edildiği anda bakiye düşülür). Ardından bir arka plan arka plan programı (daemon) TRX'i gönderir ve siparişi
completedveyafailedolarak işaretler. İlk yanıtta eşzamanlı zincir üstü sonuç bulunmaz — her zaman önce birpendingonayı alırsınız.
Uç Nokta URL'si
POST https://netts.io/apiv2/withdrawİstek Başlıkları
| Başlık | Gerekli | Açıklama |
|---|---|---|
| Content-Type | Evet | application/json |
| X-API-KEY | Evet | Netts kontrol panelindeki API anahtarınız |
| X-Real-IP | Evet | Beyaz listenizdeki IP adresi |
| X-Idempotency-Key | Hayır | Çift çekim olmadan güvenli bir şekilde yeniden denemek için isteğe bağlı istemci tarafından oluşturulan anahtar (base64). Atlanırsa, sunucu otomatik olarak bir tane türetir. Bu değer orderId değeriniz olur. |
İstek Gövdesi
{
"amount": 15,
"address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}Parametreler
| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| amount | number | Evet | TRX cinsinden brüt tutar (en az 3). Ücret bu tutardan düşülür — alıcıya amount − fee (net) ulaşır. |
| address | string | Evet | Hedef TRON adresi (T…, 34 karakter, base58). |
| sub_and_robot_out | boolean | Hayır | Robot/alt kullanıcı ödeme modu: 1 TRX yerine 2 TRX ücret uygular. Varsayılan false. |
Ücret. Brüt
amountüzerinden sabit bir ücret kesilir: normalde 1 TRX veyasub_and_robot_out = trueolduğunda 2 TRX.amount − fee ≤ 0ise sipariş reddedilir.
Örnek İstekler
Aşağıdaki örnekler ayrıca
X-Idempotency-Keyoluşturur ve gönderir, böylece yanlışlıkla yapılan tekrarlar ikinci bir çekim oluşturmaz. Tüm kurallar için Idempotency (Tekilleştirme) bölümüne bakın.
cURL
API_KEY="your_api_key"
ADDR="TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AMOUNT=15
NONCE=$(( $(date +%s) / 2 )) # stable for retries within a 2s window; or your own order UUID
# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) )
IDEMP=$(printf '%s' "${ADDR}:${AMOUNT}:${NONCE}" \
| openssl dgst -sha256 -hmac "$API_KEY" -binary | basenc --base64url | tr -d '=')
curl -X POST https://netts.io/apiv2/withdraw \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-H "X-Real-IP: your_whitelisted_ip" \
-H "X-Idempotency-Key: $IDEMP" \
-d "{\"amount\": $AMOUNT, \"address\": \"$ADDR\"}"Python
import time, hmac, hashlib, base64, requests
API_KEY = "your_api_key"
url = "https://netts.io/apiv2/withdraw"
payload = {"amount": 15, "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) ), padding stripped.
# Generate ONCE per order and resend the same value on every retry.
nonce = str(int(time.time() // 2)) # 2s bucket; or your own order UUID
message = f"{payload['address']}:{payload['amount']}:{nonce}"
idem_key = base64.urlsafe_b64encode(
hmac.new(API_KEY.encode(), message.encode(), hashlib.sha256).digest()
).decode().rstrip("=")
headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"X-Real-IP": "your_whitelisted_ip",
"X-Idempotency-Key": idem_key,
}
resp = requests.post(url, headers=headers, json=payload)
detail = resp.json().get("detail", {})
if resp.status_code == 202 and detail.get("status") == "pending":
d = detail["data"]
print(f"Order ID: {d['orderId']}") # use it for the status endpoint / webhook
print(f"Net to recipient: {d['net']} TRX (fee {d['fee']})")
else:
print(f"Code {detail.get('code')}: {detail.get('msg', detail)}")Yanıt
Kabul Edildi — çekim sıraya alındı (202 Accepted)
Tutar bakiyenizden rezerve edilir ve ödeme planlanır. completed / failed durumuna gelene kadar durum uç noktasını sorgulayın (veya webhook'u bekleyin).
{
"detail": {
"code": 10000,
"status": "pending",
"msg": "Withdrawal request accepted, processing within 5 minutes.",
"data": {
"orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
"amount": 15.0,
"fee": 1.0,
"net": 14.0,
"address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}Yanıt Alanları
| Alan | Tür | Açıklama |
|---|---|---|
| detail.code | integer | 10000 kabul edildi |
| detail.status | string | pending |
| detail.data.orderId | string | Sipariş numarası — 43 karakterlik URL güvenli bir dize. Durum uç noktası için kullanılır ve siparişi webhook yüklerinde tanımlar. |
| detail.data.amount | number | Talep edilen brüt tutar (TRX) |
| detail.data.fee | number | Kesilen ücret (1 veya 2 TRX) |
| detail.data.net | number | Alıcının alacağı tutar (amount − fee) |
| detail.data.address | string | Hedef adres |
Durum Uç Noktası
GET https://netts.io/apiv2/withdraw/status/{orderId}Başlıklar: X-API-KEY + X-Real-IP (sipariş, kimliği doğrulanmış kullanıcıya ait olmalıdır). orderId URL için güvenlidir — URL kodlaması (URL-encoding) gerekmeden olduğu gibi iletin.
| Sipariş durumu | HTTP | code | status |
|---|---|---|---|
| Tamamlandı (TRX gönderildi) | 200 | 10000 | completed (processed_at ile birlikte) |
| Sıraya alındı / gönderiliyor | 200 | 10001 | pending |
| Başarısız | 200 | 5003 | failed (error_message ile birlikte) |
| Bulunamadı / size ait değil | 404 | -1 | — |
{
"detail": {
"code": 10000,
"status": "completed",
"data": {
"orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
"amount": 15.0, "fee": 1.0, "net": 14.0,
"address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"processed_at": "2026-01-01 00:00:00+00:00"
}
}
}Alt kullanıcı hesapları
Alt kullanıcı çekimleri, normal kullanıcılarla tamamen aynı şekilde çalışır — yalnızca alt kullanıcının kendi API anahtarı kullanılır. Bir alt kullanıcı, kendi anahtarıyla doğrulanarak bu aynı POST /apiv2/withdraw uç noktasını çağırır; çekim ilgili alt kullanıcının kendi bakiyesinden düşülür ve isteğin belirttiği address değerine gönderilir. Aynı minimum, aynı ücret (1 TRX), aynı akış. Ayrı bir alt kullanıcı uç noktası yoktur — ister ana ister alt kullanıcı olsun her hesap, yalnızca kendi anahtarıyla kendi bakiyesini çeker.
Webhook'lar
Sürekli sorgulama (polling) yapmak yerine bir kez webhook yapılandırın; Netts, çekimlerinizin her biri nihai bir duruma (completed / failed) ulaştığında imzalı bir bildirim gönderecektir (POST). Webhook kullanıcı başına saklanır ve o hesabın çekimleri için geçerlidir. Yapılandırılmış bir webhook yoksa, yalnızca durum uç noktasını sorgulayın.
Yapılandırma / görüntüleme / kaldırma
POST https://netts.io/apiv2/withdraw/webhook # create or update
GET https://netts.io/apiv2/withdraw/webhook # view current config (secret is never returned)
DELETE https://netts.io/apiv2/withdraw/webhook # unsubscribeBaşlıklar: X-API-KEY + X-Real-IP.
// POST body
{
"callback_url": "https://your-server.example/netts/withdraw-hook",
"secret": "your_shared_secret_min_8_chars",
"enabled": true
}| Parametre | Tür | Gerekli | Açıklama |
|---|---|---|---|
| callback_url | string | Evet | POST isteğini alan http(s) URL'si (≤ 2048 karakter) |
| secret | string | Evet | Her yükü imzalamak için kullanılan paylaşılan gizli anahtar (8…256 karakter) |
| enabled | boolean | Hayır | Yapılandırmayı silmeden iletimi açıp kapatın. Varsayılan true |
GET isteği { callback_url, enabled, secret_set, updated_at } döndürür — gizli anahtarın kendisi asla geri döndürülmez.
İletim yükü
Netts, X-Netts-Signature: base64( HMAC-SHA256( secret, raw_body ) ) başlığı ve bu JSON gövdesi ile callback_url adresinize bir POST gönderir:
{
"orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
"status": "completed",
"amount": 15.0,
"fee": 1.0,
"net": 14.0,
"address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"processed_at": "2026-01-01 00:00:00+00:00",
"error_message": null
}statusdeğericompletedveyafailedolur (faileddurumundaerror_messagedoldurulur).
İmzayı doğrulama
İmza, gövdenin kanonik JSON'u üzerinden hesaplanır: anahtarlar sıralanmış, boşluksuz (separators=(",", ":")). Aynı şekilde yeniden hesaplayın ve karşılaştırın.
import hmac, hashlib, base64, json
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = base64.b64encode(
hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
).decode()
return hmac.compare_digest(expected, signature_header)
# Flask example: verify against the EXACT bytes received, then parse.
# if verify(request.get_data(), request.headers["X-Netts-Signature"], SECRET): ...Her zaman alınan ham baytlar (raw bytes) üzerinden doğrulama yapın. Ayrıştırılmış JSON'u yeniden seri hale getirirseniz, kanonik biçimi yeniden oluşturun:
json.dumps(payload, ensure_ascii=False, separators=(",",":"), sort_keys=True).
İletim garantileri
- Onaylamak için HTTP 2xx ile yanıt verin. Diğer tüm yanıtlar (veya zaman aşımı) başarısız bir deneme olarak kabul edilir.
- Siparişin oluşturulduğu andan itibaren 21 dakikalık bir zaman aralığında sipariş başına en fazla 3 deneme yapılır (yeniden deneme bekleme süresi ≈ 5 dakika). Bundan sonra iletimden vazgeçilir — durum uç noktasına geri dönün.
- İletimler tekilleştirilir: her sipariş başarıyla en fazla bir kez iletilir.
- İşleyicinizi
orderIdüzerinde idempotent (aynı işlem tekrarlandığında sonucu değişmeyen) yapın.
Hata Yanıtları
Kimlik Doğrulama Hatası (401)
{ "detail": { "code": -1, "msg": "Invalid API key or IP not in whitelist" } }Yetersiz Bakiye (403)
{ "detail": { "code": 1004, "status": "failed", "msg": "Insufficient balance: 2.0 < 15 TRX" } }Bekleyen Çekim Mevcut (409)
Kendi bakiyenizde aynı anda yalnızca bir bekleyen çekim olabilir. Mevcut olan işlenene kadar bekleyin.
{ "detail": { "code": 4090, "status": "failed", "msg": "You have a pending withdrawal. Wait until it is processed." } }Doğrulama Hatası (400)
{ "detail": { "code": 5004, "status": "failed", "msg": "Minimum withdrawal is 3 TRX" } }Hata Kodu Referansı
| Kod | Açıklama | HTTP Durumu |
|---|---|---|
10000 | Kabul edildi (çekim sıraya alındı) / Tamamlandı (durum uç noktası) | 202 / 200 |
10001 | Beklemede — sıraya alındı veya gönderiliyor (durum uç noktası) | 200 |
208 | Zaten kabul edilmiş bir isteğin kopyası — önbelleğe alınmış yanıt | 208 |
- | Aynı istek hâlâ işleniyor (henüz tekrar denemeyin) | 409 |
4090 | Zaten bekleyen bir çekiminiz var | 409 |
-1 | Geçersiz API anahtarı / IP beyaz listede değil veya sipariş bulunamadı | 401 / 404 |
1004 | Yetersiz bakiye | 403 |
5004 | Doğrulama hatası (tutar < 3, ücret ≥ tutar, hatalı adres, hatalı idempotency anahtarı) | 400 |
5003 | Çekim başarısız oldu / hizmet kullanılamıyor | 200 (durum) / 503 |
5000 | Dahili sunucu hatası | 500 |
Hız Limitleri
API anahtarı başına sınırlandırılmıştır (X-API-KEY başlığı):
| Dönem | Limit |
|---|---|
| 1 saniye | 5 istek |
| 1 dakika | 150 istek |
Hız Limiti Aşıldı (429)
{ "message": "API rate limit exceeded" }Idempotency
İsteğe bağlı X-Idempotency-Key başlığını gönderin, böylece yanlışlıkla yapılan bir tekrar ikinci bir çekim oluşturmaz — orijinal yanıt HTTP 208 ile döndürülür. Başlığı göndermezseniz, sunucu kısa bir zaman aralığında istek parametrelerinizden otomatik olarak bir anahtar türetir. Bu anahtar aynı zamanda sizin orderId değerinizdir.
Anahtar nasıl oluşturulur
Anahtar, = dolgusu kaldırılmış base64url( HMAC-SHA256( secret, message ) ) değeridir — 43 karakterlik URL güvenli bir dizedir, burada:
- secret = API anahtarınız (
X-API-KEY); - message = alanların
:ile birleştirilmiş halidir —address:amount:nonce.
nonce, aynı mantıksal siparişin yeniden denemeleri arasında sabit kalan ancak farklı siparişler arasında değişiklik gösteren herhangi bir değerdir — ör. o sipariş için tuttuğunuz bir UUID veya kaba bir zaman damgası grubu. Anahtarı sipariş başına bir kez oluşturun ve her yeniden denemede birebir aynı değeri tekrar gönderin.
import hmac, hashlib, base64, time
def make_idempotency_key(api_key, address, amount, nonce=None):
if nonce is None:
nonce = str(int(time.time() // 2)) # 2-second bucket; or your own order UUID
message = f"{address}:{amount}:{nonce}"
digest = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).digest()
return base64.urlsafe_b64encode(digest).decode().rstrip("=") # 43-char URL-safeDoğrulama. Sağlanan
X-Idempotency-Key,A–Z a–z 0–9 + / = _ -karakter kümesinden 16–64 karakter uzunluğunda olmalıdır. Hatalı biçimlendirilmiş veya fazla uzun bir anahtar HTTP 400 (code 5004) ile reddedilir.
| Durum Kodu | Anlamı |
|---|---|
| 202 | Kabul edildi (ilk istek) |
| 208 | Zaten kabul edildi — önbelleğe alınmış yanıt döndürüldü (ikinci bir çekim yapılmaz) |
| 409 | Aynı istek şu anda işleniyor — bekleyin, henüz yeniden denemeyin |
Başarısızlıktan sonra yeniden deneme. Yalnızca kabul edilen sonuçlar önbelleğe alınır. Önceki deneme başarısız olduysa (ör. yetersiz bakiye, doğrulama), güvenle aynı anahtarla yeniden deneyebilirsiniz — eski hatayı döndürmek yerine istek tekrar denenir. Bir deneme hâlâ devam ederken
409alırsınız; bekleyin ve yeniden deneyin.
Notlar
- Asenkron ödeme. Yanıt her zaman bir
pendingonayıdır; TRX, arka plan programı tarafından genellikle ~5 dakika içinde gönderilir. Sonuç için durum uç noktasını veya bir webhook'u kullanın. - Sipariş kabul edildiğinde bakiye anında rezerve edilir (TRX nihai olarak gönderildiğinde değil).
- Minimum: 3 TRX. Ücret: 1 TRX (veya
sub_and_robot_outile 2 TRX), brütamountüzerinden kesilir; alıcınet = amount − feetutarını alır. - Kendi bakiyenizde aynı anda tek bir bekleyen işlem olabilir (
code 4090). - Alt kullanıcılar tamamen normal kullanıcılar gibi çekim yapar — aynı
POST /apiv2/withdrawuç noktası, aynı kurallar, ancak alt kullanıcının kendi API anahtarı ile doğrulanır. Bir alt kullanıcı belirttiği herhangi biraddressadresine kendi bakiyesini çeker. Ayrı bir alt kullanıcı uç noktası yoktur. - orderId, 43 karakterlik URL güvenli bir dizedir; durum URL'sinde olduğu gibi iletin (kodlama gerekmez).
- Webhook'lar: kullanıcı başınadır,
X-Netts-Signatureile imzalanır; 21 dakikalık bir pencere içinde en fazla 3 deneme yapılır.POST /apiv2/withdraw/webhooküzerinden yapılandırın.