Webhook'lar — sipariş bildirimleri
Siparişlerinizden biri karşılandığı ve zincir üzerinde (on-chain) doğrulandığı anda imzalı bir webhook almak için bir HTTPS uç noktası kaydedin. Yoklama (polling) yapmak yerine, bildirim ulaşır ulaşmaz akışınıza devam edersiniz (örneğin USDT serbest bırakma).
Üç etkinlik teslim edilir:
| Etkinlik | Gönderilme zamanı |
|---|---|
delegation.confirmed | Bir energy kiralaması (1h / 5m) zincir üzerinde onaylandığında |
bandwidth.delegated | Bir bandwidth siparişi karşılandığında |
activation.confirmed | Bir adres aktivasyonu zincir üzerinde yürütüldüğünde |
Bu sayfa, yönetim API'sini (uç noktalarınızı oluşturma / listeleme / düzenleme / secret yenileme / silme) ve size ilettiğimiz webhook'ların biçimini kapsar.
ℹ️ Roller. Uç noktalarınızı buradan yönetirsiniz. Teslimat, sipariş doğrulandıktan sonra Netts tarafından asenkron olarak gerçekleştirilir — yoklama yapılacak bir şey yoktur. Yalnızca başarılı etkinlikler gönderilir; başarısızlıklar ve zaman aşımları asla iletilmez.
🔒 Gönderdiğimiz her karma (hash) önce zincir üzerinde doğrulanır. Bir webhook, yalnızca içindeki her bir işlem karması bir blokta bulunduktan sonra gönderilir. Bir karma henüz bir blokta yer almıyorsa, teslimat bekletilir ve 5 dakikaya kadar her 30 saniyede bir yeniden kontrol edilir; hiçbir zaman bloğa girmezse, o sipariş için hiçbir şey gönderilmez. Zincir üzerinde mevcut olmayan bir karmayı asla almazsınız.
Uç noktası temel URL'si
https://netts.io/apiv2/webhooksİstek Başlıkları
| Başlık | Zorunlu | Açıklama |
|---|---|---|
| Content-Type | Evet (POST/PATCH için) | application/json |
| X-API-KEY | Evet | Netts kontrol panelinizdeki API anahtarınız |
| X-Real-IP | Evet | Beyaz listenizdeki IP adresi |
user_id değeriniz API anahtarından türetilir — bunu asla siz iletmezsiniz. Yalnızca kendi uç noktalarınızı görebilir ve değiştirebilirsiniz.
Birincil ve yedek uç noktası
En fazla iki uç noktası kaydedebilirsiniz ve her birinin bir role değeri vardır:
| Rol | Amaç |
|---|---|
primary | Her webhook'un teslim edildiği adres. |
backup | Yedek (fallback). Yalnızca primary noktasına teslimat, yeniden denemeleri tükendikten sonra başarısız olduğunda kullanılır. |
Onaylanan tek bir sipariş, tek bir webhook üretir. Bu bir dağıtım (fan-out) değildir: aynı etkinlik asla her iki adrese aynı anda gönderilmez. backup uç noktası esneklik ve dayanıklılık için vardır — birincil sunucunuza ulaşılamıyorsa veya sürekli 2xx dışı yanıtlar döndürüyorsa, teslimat bırakılmak yerine yedeğe geçer.
Oluşturduğunuz ilk uç noktası primary, ikincisi backup olur. role değerini açıkça iletebilir veya daha sonra PATCH ile değiştirebilirsiniz.
Neden her işlem türü için ayrı bir URL yok? Çünkü etkinlik türü gövdenin içinde,
eventalanında iletilir. Tek bir işleyici (handler), tek bir imza kontrolü ve yeni bir şey kaydetmenize gerek kalmadan yeni etkinlik türleri gelmeye başlar.
Uç noktalarını yönetme
Oluşturma — POST /apiv2/webhooks
Yeni bir uç noktası kaydeder ve yalnızca bir kez gösterilen bir secret döndürür (bunu saklayın — aldığınız her webhook'u imzalar).
// request body — role is optional
{
"url": "https://your-server.example/netts/delegation-hook",
"role": "primary"
}Eğer role belirtmezseniz, ilk boş olan atanır: önce primary, ardından backup.
// response 201
{
"detail": {
"code": 10000,
"status": "created",
"data": {
"id": 1,
"url": "https://your-server.example/netts/delegation-hook",
"secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"role": "primary",
"is_active": true,
"created_at": "2026-01-01T00:00:00"
}
}
}URL gereksinimleri (oluşturma sırasında ve her düzenlemede doğrulanır):
httpsolmalıdır;- Genel (public) bir adrese çözümlenmelidir — geri döngü (loopback), özel (RFC1918), yerel bağlantı (
169.254.169.254dahil) ve diğer yönlendirilemeyen aralıklar reddedilir; - URL'de kimlik bilgileri bulunmamalıdır (
user:pass@…); - En fazla 2048 karakter uzunluğunda olmalıdır.
Reddedilen bir URL 400 döndürür.
İki uç noktanız olabilir — bir primary ve bir backup. Üçüncüsü 409 (4090) döndürür. Zaten alınmış bir role istemek 409 (4091) döndürür — rolleri PATCH ile değiştirin veya önce mevcut olanı silin.
curl -X POST https://netts.io/apiv2/webhooks \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip" \
-d '{"url": "https://your-server.example/netts/delegation-hook", "role": "primary"}'Listeleme — GET /apiv2/webhooks
Uç noktalarınızı döndürür (secret burada asla döndürülmez).
{
"detail": {
"code": 10000,
"status": "ok",
"data": {
"endpoints": [
{
"id": 1,
"url": "https://your-server.example/netts/delegation-hook",
"role": "primary",
"is_active": true,
"created_at": "2026-01-01T00:00:00",
"updated_at": "2026-01-01T00:00:00"
},
{
"id": 2,
"url": "https://backup.example/netts/delegation-hook",
"role": "backup",
"is_active": true,
"created_at": "2026-01-01T00:00:00",
"updated_at": "2026-01-01T00:00:00"
}
],
"count": 2,
"max_endpoints": 2,
"roles": ["primary", "backup"]
}
}
}Tek birini getirme — GET /apiv2/webhooks/{id}
Liste öğesiyle aynı yapıdadır (secret içermez). Yabancı veya var olmayan bir id 404 döndürür.
Düzenleme — PATCH /apiv2/webhooks/{id}
url, is_active ve/veya role alanlarını değiştirin. Herhangi bir alt kümeyi gönderin; boş bir gövde 422 döndürür. Değiştirilen bir url yeniden doğrulanır (https / SSRF). Yabancı veya var olmayan bir id 404 döndürür.
// request body (any subset)
{ "url": "https://your-server.example/netts/new-hook", "is_active": false }// response 200
{
"detail": {
"code": 10000,
"status": "updated",
"data": {
"id": 1,
"url": "https://your-server.example/netts/new-hook",
"role": "primary",
"is_active": false,
"created_at": "2026-01-01T00:00:00",
"updated_at": "2026-01-01T00:00:01"
}
}
}Yedeği birincil yapma (promoting). Yedek uç noktanıza {"role": "primary"} göndermek, her iki rolü tek bir işlemde değiştirir (swap) — eski birincil yeni yedek olur. Asla birincil bir adres olmadan kalmazsınız ve diğer uç nokta için ayrı bir çağrı yapılması gerekmez.
curl -X PATCH https://netts.io/apiv2/webhooks/2 \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip" \
-d '{"role": "primary"}'Uç noktasını silmeden teslimatı duraklatmak için
is_active: false; devam ettirmek içintrueolarak ayarlayın.primaryuç noktanızı duraklatmak yedeği birincil yapmaz — teslimat yine de birincili hedefler. Yedeğin devralmasını istiyorsanız rolleri değiştirin.
Secret yenileme — POST /apiv2/webhooks/{id}/rotate-secret
Yeni bir secret oluşturur ve bunu bir kez döndürür. Yeni secret, sonraki teslimatlar için derhal yürürlüğe girer — başka bir işlem gerekmez. Her uç noktanın kendi secret değeri vardır: birincilin secret'ını yenilemek yedeğinkini değiştirmez.
// response 200
{
"detail": {
"code": 10000,
"status": "rotated",
"data": {
"id": 1,
"secret": "whsec_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
}
}
}Silme — DELETE /apiv2/webhooks/{id}
Uç noktasını kalıcı olarak siler ve rolünü serbest bırakır. 204 döndürür (gövde yok); yabancı veya var olmayan bir id 404 döndürür.
curl -X DELETE https://netts.io/apiv2/webhooks/1 \
-H "X-API-KEY: your_api_key" -H "X-Real-IP: your_whitelisted_ip"Teslim ettiğimiz webhook'lar
Siparişlerinizden biri karşılandığında Netts, primary uç noktanıza bir POST gönderir. Her gövde application/json (UTF-8) biçimindedir; adresler ve karmalar her zaman tam değerlerdir.
Tüm etkinliklerde ortak olan alanlar:
| Alan | Tür | Açıklama |
|---|---|---|
event | string | Etkinlik türü — işleyiciniz için yönlendirme anahtarı |
delivery_id | int | Teslimat Kimliği — tarafınızdaki tekilleştirme anahtarı (dedup key). Ayrıca X-Netts-Delivery başlığında da gönderilir. |
order_id | string | Sipariş Kimliğiniz |
order_type | string | 1h, 5m, bandwidth veya activation |
tx_hashes | string[] | İşlemin her biri zincir üzerinde doğrulanmış tüm işlem karmaları |
confirmed_at | string | UTC ISO-8601 |
delegation.confirmed — energy kiralaması
{
"event": "delegation.confirmed",
"delivery_id": 1,
"order_id": "1Hxxxxxxxxxx",
"order_type": "1h",
"receive_address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"energy_amount": 65000,
"tx_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"tx_hashes": ["0000000000000000000000000000000000000000000000000000000000000000"],
"delegation_timestamp": 1700000000000,
"confirmed_at": "2026-01-01T00:00:00Z"
}| Alan | Tür | Açıklama |
|---|---|---|
order_type | string | 1h veya 5m |
receive_address | string | Energy'yi alan TRON adresi |
energy_amount | int | Delege edilen Energy miktarı |
tx_hash | string | Eski alan, uyumluluk için korunmuştur: tx_hashes[0] ile aynıdır |
delegation_timestamp | int? | İsteğe bağlı — yalnızca Mongo yolu üzerinden onaylandığında mevcuttur |
Yeni entegrasyonlarda
tx_hashesalanını tercih edin — bir sipariş prensipte birden fazla işlemle karşılanabilir.tx_hashçalışmaya devam edecektir.
bandwidth.delegated — bandwidth siparişi
{
"event": "bandwidth.delegated",
"delivery_id": 2,
"order_id": "B1Hxxxxxxxxxxxxx",
"order_type": "bandwidth",
"rental_label": "1h",
"rental_seconds": 3600,
"receive_address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"bandwidth_amount": 400,
"fulfillment": "delegated",
"tx_hashes": ["0000000000000000000000000000000000000000000000000000000000000000"],
"confirmed_at": "2026-01-01T00:00:00Z"
}| Alan | Tür | Açıklama |
|---|---|---|
rental_label / rental_seconds | string / int | Kiralama süresi, örneğin 1h / 3600 |
receive_address | string | Bandwidth alan TRON adresi |
bandwidth_amount | int | Bandwidth birimleri (net) |
fulfillment | string | Siparişin nasıl karşılandığı — aşağıya bakın |
fulfillment değerleri:
| Değer | Anlamı | tx_hashes |
|---|---|---|
delegated | Havuzumuzdan delege edilen Bandwidth | 1+ karma |
trx_send | Delege etmek yerine adrese TRX gönderilerek karşılandı | 1+ karma |
already_enough | Adreste zaten yeterli ücretsiz bant genişliği vardı — zincir üzerinde hiçbir şey gönderilmedi | boş |
already_enough, tx_hashes alanının boş olduğu tek durumdur: sipariş başarıyla kapatılmıştır, ancak gerekmediği için hiçbir işlem yapılmamıştır.
activation.confirmed — adres aktivasyonu
{
"event": "activation.confirmed",
"delivery_id": 3,
"order_id": "123456",
"order_type": "activation",
"address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"activation_type": "ACC_CREATE",
"source": "telegram_bot",
"tx_hashes": ["0000000000000000000000000000000000000000000000000000000000000000"],
"confirmed_at": "2026-01-01T00:00:00Z"
}| Alan | Tür | Açıklama |
|---|---|---|
order_id | string | Aktivasyon sipariş Kimliği (sayısal dize) |
address | string | Aktive edilen TRON adresi |
activation_type | string | ACC_CREATE (AccountCreateContract) veya DIRECT (TRX transferi) |
source | string | Kaynak belirteci. Bir servis etiketi veya aktivasyonu gerektiren enerji siparişinin Kimliği |
Yalnızca gerçek aktivasyonlar teslim edilir. Adresin zaten aktif olduğu ortaya çıkarsa ve hiçbir işlem yapılmadıysa, hiçbir webhook gönderilmez.
Aynı zamanda bir aktivasyon gerektiren bir enerji siparişi iki webhook üretir — bir
activation.confirmedve birdelegation.confirmed. Bunlar ayrıdelivery_iddeğerlerine sahip ayrı etkinliklerdir; bunlarıeventalanına göre yönlendirin.
Gönderdiğimiz başlıklar:
| Başlık | Değer |
|---|---|
X-Netts-Event | Etkinlik türü: delegation.confirmed, bandwidth.delegated veya activation.confirmed |
X-Netts-Delivery | delivery_id (tekilleştirme) |
X-Netts-Timestamp | Gönderim anındaki unix saniyesi |
X-Netts-Signature | sha256=<hex>, hex = HMAC_SHA256(secret, "<timestamp>." + raw_body) |
User-Agent | netts-webhook/1.0 |
İmzayı doğrulama
İmza, gönderdiğimiz ham baytlar (raw bytes) üzerinden hesaplanan Stripe şemasını (timestamp.body) takip eder. secret değerinizle yeniden hesaplayın, sabit zamanda (constant-time) karşılaştırın ve X-Netts-Timestamp ±5 dakikalık bir pencerenin dışındaysa reddedin (yeniden oynatma koruması).
İsteği alan uç noktasının secret değeriyle imzalayın: birincil ve yedek ayrı secret değerlerine sahiptir. Her iki adresinize de aynı işleyici hizmet veriyorsa, secret değerini isteğin ulaştığı URL'ye göre seçin.
import hmac, hashlib, time
def verify(raw_body: bytes, sig_header: str, ts_header: str, secret: str) -> bool:
# freshness (anti-replay)
if abs(time.time() - int(ts_header)) > 300:
return False
signed = f"{ts_header}.".encode() + raw_body
expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig_header)
# Flask example:
# ok = verify(request.get_data(),
# request.headers["X-Netts-Signature"],
# request.headers["X-Netts-Timestamp"], SECRET)Teslimat semantiği (önemli — en-az-bir-kez / at-least-once)
Teslimat en-az-bir-kez (at-least-once) prensibiyle çalışır: düşen bir yanıt yeniden denemeye neden olabilir, bu nedenle aynı etkinliği iki kez alabilirsiniz. İş eylemi (USDT serbest bırakma) paraya duyarlı olduğundan:
- Tekilleştirme (dedup) zorunludur — her etkinliği
delivery_id(ve/veyaorder_id) ile etkisiz eleman (idempotent) olarak işleyin; bir tekrar hiçbir işlem yapmamalıdır (no-op). - Herhangi bir para eyleminden önce HMAC'i doğrulayın — imza eşleşene ve
X-Netts-Timestampgüncel olana kadar gövdeye güvenmeyin. - Yalnızca etkinliği kalıcı olarak sakladıktan sonra 2xx döndürün — aksi takdirde biz (haklı olarak) yeniden deneriz.
Onaylamak için 2xx yanıtı verin; 2xx dışındaki herhangi bir yanıt / zaman aşımı bir yeniden denemeyi tetikler.
Deneme sırası:
- Yeniden denemeler
primaryuç noktanıza gider. Zaman aralığı sipariş türüne bağlıdır:5msiparişleri yaklaşık 1 dakika, diğer tüm türler yaklaşık 10 dakika boyunca yeniden denenir. - Zaman aralığı tükenirse ve bir
backupkaydettiyseniz, teslimat oraya geçer ve yeniden deneme programı baştan başlar — yedeğin kendi secret'ı ile imzalanır. - Teslimat ancak yedek de tükendikten sonra kapalı (dead) olarak işaretlenir.
Baştan sona aynı delivery_id kullanılır, bu nedenle önce birincilde başarısız olan ve ardından yedekte başarılı olan bir mesaj, tekilleştirme mantığınız için hala tek bir etkinliktir.
Hata Kodu Referansı
| Kod | Açıklama | HTTP Durumu |
|---|---|---|
10000 | Başarılı (created / ok / updated / rotated) | 200 / 201 |
- | Silindi (gövde yok) | 204 |
4000 | Geçersiz / güvensiz webhook URL'si (https değil, özel/loopback, kimlik bilgileri, çok uzun) | 400 |
-1 | Geçersiz API anahtarı / IP beyaz listede değil | 401 |
-1 | Uç noktası bulunamadı (veya size ait değil) | 404 |
4090 | Uç noktası sınırına ulaşıldı (maks 2: primary, backup) | 409 |
4091 | İstenen rol zaten alınmış — PATCH ile değiştirin veya mevcut uç noktasını silin | 409 |
4220 | Güncellenecek bir şey yok (boş gövdeli PATCH) | 422 |
5003 | Uç noktası oluşturulamadı (tekrar deneyin) | 503 |
İstek Limitleri (Rate Limits)
API anahtarı başına sınırlandırılmıştır (X-API-KEY başlığı):
| Dönem | Sınır |
|---|---|
| 1 saniye | 5 istek |
| 1 dakika | 150 istek |
İstek Limiti Aşıldı (429)
{ "message": "API rate limit exceeded" }Notlar
- Secret yalnızca bir kez gösterilir — oluşturma ve yenileme sırasında.
GET/LISTtarafından asla döndürülmez. Kaybettiniz mi? Yeni bir tane almak için yenileyin (rotate). - İki uç noktası, dağıtım (fan-out) yok: bir
primaryve birbackup. Onaylanan her sipariş, birincile teslim edilen bir webhook üretir; yedek yalnızca birincil tükendiğinde kullanılır. - Kesintisiz (zero-downtime) URL değişikliği: yeni adresi
backupolarak kaydedin, doğrulayın, ardındanPATCHileprimaryyapın — takas atomiktir. - Duraklatma:
PATCH … {"is_active": false}, uç noktasını kaybetmeden teslimatı durdurur. - Yalnızca başarılı etkinlikler:
delegation.confirmed,bandwidth.delegated,activation.confirmed. Başarısızlık etkinliği yoktur — başarısız olan veya zaman aşımına uğrayan bir sipariş webhook üretmez. - Zamanla yeni etkinlik türleri eklenebilir.
eventalanına göre yönlendirin ve henüz işlemediğiniz türleri yoksayın — bunları almaya başlamak için asla yeni bir şey kaydetmeniz gerekmez. - Karmalar teslimattan önce zincir üzerinde doğrulanır (üstteki nota bakın): bir webhook ya tamamı bir blokta yer alan karmaları taşır ya da hiç gönderilmez.
- Kayıt sırasında ve her düzenlemede URL'ler SSRF güvenliği açısından doğrulanır; teslimat tarafı gönderim anında yeniden doğrular.