Skip to content
Translated page. The English version is the source of truth.

Webhook — notifikasi pesanan ​

Daftarkan endpoint HTTPS untuk menerima webhook bertanda tangan pada saat salah satu pesanan Anda terpenuhi dan terverifikasi secara on-chain. Alih-alih melakukan polling, Anda dapat melanjutkan alur proses Anda (misalnya melepas USDT) segera setelah notifikasi tiba.

Tiga peristiwa yang dikirimkan:

PeristiwaDikirim saat
delegation.confirmedPenyewaan energy (1h / 5m) terkonfirmasi secara on-chain
bandwidth.delegatedPesanan bandwidth terpenuhi
activation.confirmedAktivasi alamat dieksekusi secara on-chain

Halaman ini mencakup API pengelolaan (buat / daftar / edit / rotasi-secret / hapus endpoint Anda) dan format webhook yang kami kirimkan kepada Anda.

ℹ️ Peran. Anda mengelola endpoint Anda di sini. Pengiriman dilakukan oleh Netts secara asinkron setelah pesanan diverifikasi — tidak ada yang perlu di-poll. Hanya peristiwa sukses yang dikirim; kegagalan dan batas waktu habis (timeout) tidak pernah dikirimkan.

🔒 Setiap hash yang kami kirim diverifikasi secara on-chain terlebih dahulu. Webhook dikirim hanya setelah setiap hash transaksi di dalamnya ditemukan dalam sebuah blok. Jika hash belum berada dalam sebuah blok, pengiriman ditahan dan diperiksa ulang setiap 30 detik hingga 5 menit; jika tidak pernah masuk ke blok, tidak ada yang dikirim untuk pesanan tersebut. Anda tidak akan pernah menerima hash yang tidak ada secara on-chain.

URL dasar endpoint ​

https://netts.io/apiv2/webhooks

Header Permintaan ​

HeaderWajibDeskripsi
Content-TypeYa (untuk POST/PATCH)application/json
X-API-KEYYaKunci API Anda dari dasbor Netts
X-Real-IPYaAlamat IP dari daftar putih (whitelist) Anda

user_id Anda diturunkan dari kunci API — Anda tidak perlu meneruskannya. Anda dapat melihat dan mengubah hanya endpoint milik Anda sendiri.


Endpoint utama dan cadangan ​

Anda mendaftarkan paling banyak dua endpoint, dan masing-masing memiliki role:

PeranTujuan
primaryAlamat tujuan pengiriman setiap webhook.
backupFallback. Hanya digunakan ketika pengiriman ke primary gagal setelah batas percobaan ulangnya habis.

Satu pesanan yang dikonfirmasi menghasilkan satu webhook. Ini bukan fan-out: peristiwa yang sama tidak pernah dikirim ke kedua alamat sekaligus. Endpoint backup hadir untuk ketahanan — jika host utama Anda tidak dapat dijangkau atau terus mengembalikan status non-2xx, pengiriman dialihkan ke cadangan alih-alih dibatalkan.

Endpoint pertama yang Anda buat menjadi primary, yang kedua menjadi backup. Anda dapat meneruskan role secara eksplisit, atau menukarnya nanti dengan PATCH.

Mengapa tidak menggunakan URL terpisah per jenis operasi? Karena jenis peristiwa berada di dalam body, pada bidang event. Satu penangan (handler), satu pemeriksaan tanda tangan, dan jenis peristiwa baru akan mulai masuk tanpa Anda perlu mendaftarkan hal baru apa pun.


Kelola endpoint ​

Buat — POST /apiv2/webhooks ​

Mendaftarkan endpoint baru dan mengembalikan secret yang hanya ditampilkan sekali (simpan ini — secret ini menandatangani setiap webhook yang Anda terima).

json
// request body — role is optional
{
    "url": "https://your-server.example/netts/delegation-hook",
    "role": "primary"
}

Jika Anda mengosongkan role, peran kosong pertama akan ditetapkan: primary, kemudian backup.

json
// 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"
        }
    }
}

Persyaratan URL (divalidasi saat pembuatan dan pada setiap pengeditan):

  • harus berupa https;
  • harus mengarah ke alamat publik — loopback, privat (RFC1918), link-local (termasuk 169.254.169.254), dan rentang non-routable lainnya akan ditolak;
  • tidak boleh ada kredensial di dalam URL (user:pass@…);
  • panjang hingga 2048 karakter.

URL yang ditolak akan mengembalikan 400.

Anda dapat memiliki dua endpoint — satu primary dan satu backup. Endpoint ketiga akan mengembalikan 409 (4090). Meminta role yang sudah digunakan akan mengembalikan 409 (4091) — tukar peran dengan PATCH atau hapus endpoint yang sudah ada terlebih dahulu.

bash
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"}'

Daftar — GET /apiv2/webhooks ​

Mengembalikan daftar endpoint Anda (secret tidak pernah dikembalikan di sini).

json
{
    "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"]
        }
    }
}

Dapatkan satu — GET /apiv2/webhooks/{id} ​

Format yang sama seperti item daftar (tanpa secret). id milik orang lain atau yang tidak ada akan mengembalikan 404.

Edit — PATCH /apiv2/webhooks/{id} ​

Ubah url, is_active dan/atau role. Kirim subset apa pun; body yang kosong akan mengembalikan 422. url yang diubah akan divalidasi ulang (https / SSRF). id milik orang lain atau yang tidak ada akan mengembalikan 404.

json
// request body (any subset)
{ "url": "https://your-server.example/netts/new-hook", "is_active": false }
json
// 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"
        }
    }
}

Mempromosikan cadangan. Mengirimkan {"role": "primary"} ke endpoint cadangan Anda akan menukar kedua peran tersebut dalam satu transaksi tunggal — primary yang lama menjadi backup. Anda tidak akan pernah dibiarkan tanpa alamat primary, dan tidak diperlukan panggilan terpisah untuk endpoint lainnya.

bash
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"}'

Atur is_active: false untuk menjeda pengiriman tanpa menghapus endpoint; true untuk melanjutkan. Menjeda primary Anda tidak mempromosikan cadangan — pengiriman tetap menargetkan primary. Tukar peran jika Anda ingin cadangan mengambil alih.

Rotasi secret — POST /apiv2/webhooks/{id}/rotate-secret ​

Menghasilkan secret baru dan mengembalikannya satu kali. Secret baru langsung berlaku untuk pengiriman berikutnya — tidak ada tindakan lebih lanjut yang diperlukan. Setiap endpoint memiliki secret-nya sendiri: merotasi secret primary tidak akan mengubah secret milik backup.

json
// response 200
{
    "detail": {
        "code": 10000,
        "status": "rotated",
        "data": {
            "id": 1,
            "secret": "whsec_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
        }
    }
}

Hapus — DELETE /apiv2/webhooks/{id} ​

Menghapus permanen (hard-delete) endpoint dan membebaskan perannya. Mengembalikan 204 (tanpa body); id milik orang lain atau yang tidak ada mengembalikan 404.

bash
curl -X DELETE https://netts.io/apiv2/webhooks/1 \
  -H "X-API-KEY: your_api_key" -H "X-Real-IP: your_whitelisted_ip"

Webhook yang kami kirimkan ​

Ketika salah satu pesanan Anda terpenuhi, Netts mengirimkan POST ke endpoint primary Anda. Setiap body berformat application/json (UTF-8); alamat dan hash selalu berupa nilai yang lengkap.

Bidang yang umum untuk semua peristiwa:

BidangTipeDeskripsi
eventstringJenis peristiwa — kunci perutean untuk penangan (handler) Anda
delivery_idintegerID Pengiriman — kunci deduplikasi di sisi Anda. Juga dikirimkan di header X-Netts-Delivery.
order_idstringID pesanan Anda
order_typestring1h, 5m, bandwidth atau activation
tx_hashesstring[]Semua hash transaksi dari operasi tersebut, masing-masing terverifikasi secara on-chain
confirmed_atstringUTC ISO-8601

delegation.confirmed — penyewaan energy ​

json
{
    "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"
}
BidangTipeDeskripsi
order_typestring1h atau 5m
receive_addressstringAlamat TRON yang menerima energy
energy_amountintegerJumlah Energy yang didelegasikan
tx_hashstringBidang legacy, dipertahankan untuk kompatibilitas: sama dengan tx_hashes[0]
delegation_timestampinteger?Opsional — hanya ada jika dikonfirmasi melalui jalur Mongo

Utamakan penggunaan tx_hashes dalam integrasi baru — sebuah pesanan pada prinsipnya dapat dipenuhi oleh lebih dari satu transaksi. tx_hash akan tetap berfungsi.

bandwidth.delegated — pesanan bandwidth ​

json
{
    "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"
}
BidangTipeDeskripsi
rental_label / rental_secondsstring / integerDurasi sewa, misalnya 1h / 3600
receive_addressstringAlamat TRON yang menerima bandwidth
bandwidth_amountintegerUnit Bandwidth (bersih)
fulfillmentstringCara pesanan dipenuhi — lihat di bawah

Nilai-nilai fulfillment:

NilaiArtitx_hashes
delegatedBandwidth didelegasikan dari pool kami1+ hash
trx_sendDipenuhi dengan mengirimkan TRX ke alamat alih-alih mendelegasikannya1+ hash
already_enoughAlamat sudah memiliki cukup bandwidth gratis — tidak ada yang dikirim secara on-chainkosong

already_enough adalah satu-satunya kasus di mana tx_hashes kosong: pesanan berhasil diselesaikan, tetapi tidak ada transaksi karena memang tidak diperlukan.

activation.confirmed — aktivasi alamat ​

json
{
    "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"
}
BidangTipeDeskripsi
order_idstringID pesanan aktivasi (string numerik)
addressstringAlamat TRON yang diaktifkan
activation_typestringACC_CREATE (AccountCreateContract) atau DIRECT (transfer TRX)
sourcestringPenanda asal. Baik berupa tag layanan, maupun ID pesanan energy yang memerlukan aktivasi tersebut

Hanya aktivasi nyata yang dikirimkan. Jika ternyata alamat tersebut sudah aktif dan tidak ada transaksi yang dilakukan, webhook tidak akan dikirim sama sekali.

Pesanan energy yang juga memerlukan aktivasi akan menghasilkan dua webhook — satu activation.confirmed dan satu delegation.confirmed. Keduanya adalah peristiwa terpisah dengan delivery_id yang berbeda; rutekan keduanya berdasarkan bidang event.

Header yang kami kirimkan:

HeaderNilai
X-Netts-EventJenis peristiwa: delegation.confirmed, bandwidth.delegated atau activation.confirmed
X-Netts-Deliverydelivery_id (deduplikasi)
X-Netts-Timestampdetik unix saat pengiriman
X-Netts-Signaturesha256=<hex>, hex = HMAC_SHA256(secret, "<timestamp>." + raw_body)
User-Agentnetts-webhook/1.0

Memverifikasi tanda tangan ​

Tanda tangan mengikuti skema Stripe (timestamp.body), dihitung dari byte mentah (raw bytes) yang kami kirimkan. Hitung ulang dengan secret Anda, bandingkan secara constant-time, dan tolak jika X-Netts-Timestamp berada di luar rentang waktu ±5 menit (perlindungan replay).

Tandatangani dengan secret dari endpoint yang menerima permintaan: primary dan backup memiliki secret yang terpisah. Jika kedua alamat Anda dilayani oleh handler yang sama, pilih secret berdasarkan URL tempat permintaan tersebut tiba.

python
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)

Semantik pengiriman (penting — at-least-once) ​

Pengiriman bersifat setidaknya-sekali (at-least-once): respons yang terputus dapat memicu percobaan ulang, sehingga Anda mungkin menerima peristiwa yang sama dua kali. Karena tindakan bisnis (melepas USDT) sensitif terhadap uang:

  1. Deduplikasi wajib dilakukan — proses setiap peristiwa secara idempoten berdasarkan delivery_id (dan/atau order_id); pengulangan tidak boleh melakukan apa pun (no-op).
  2. Verifikasi HMAC sebelum tindakan finansial apa pun — jangan percaya isi body sampai tanda tangan cocok dan X-Netts-Timestamp masih baru (fresh).
  3. Kembalikan 2xx hanya setelah Anda menyimpan peristiwa tersebut secara permanen — jika tidak, kami (secara benar) akan mencoba lagi.

Beri respons 2xx untuk mengonfirmasi penerimaan; status non-2xx / timeout apa pun akan memicu percobaan ulang.

Urutan percobaan:

  1. Percobaan ulang diarahkan ke endpoint primary Anda. Rentang waktunya tergantung pada jenis pesanan: pesanan 5m dicoba ulang selama ~1 menit, semua jenis lainnya selama ~10 menit.
  2. Jika rentang waktu habis dan Anda mendaftarkan backup, pengiriman dialihkan ke sana dan jadwal percobaan ulang dimulai kembali — ditandatangani dengan secret milik backup itu sendiri.
  3. Hanya setelah batas cadangan juga habis, pengiriman ditandai mati (dead).

delivery_id yang sama digunakan di sepanjang proses, sehingga pesan yang awalnya gagal di primary lalu berhasil di backup tetap dihitung sebagai satu peristiwa untuk logika deduplikasi Anda.


Referensi Kode Kesalahan ​

KodeDeskripsiStatus HTTP
10000Sukses (created / ok / updated / rotated)200 / 201
-Dihapus (tanpa body)204
4000URL webhook tidak valid / tidak aman (bukan https, privat/loopback, kredensial, terlalu panjang)400
-1Kunci API tidak valid / IP tidak ada di daftar putih401
-1Endpoint tidak ditemukan (atau bukan milik Anda)404
4090Batas endpoint tercapai (maksimal 2: primary, backup)409
4091Peran yang diminta sudah digunakan — tukar dengan PATCH atau hapus endpoint yang ada409
4220Tidak ada yang perlu diperbarui (PATCH dengan body kosong)422
5003Gagal membuat endpoint (coba lagi)503

Batas Laju (Rate Limits) ​

Dibatasi per kunci API (header X-API-KEY):

PeriodeBatas
1 detik5 permintaan
1 menit150 permintaan

Batas Laju Terlampaui (429) ​

json
{ "message": "API rate limit exceeded" }

Catatan ​

  • Secret hanya ditampilkan sekali — saat pembuatan dan saat rotasi. Secret tidak pernah dikembalikan oleh GET/LIST. Kehilangan secret? lakukan rotasi untuk mendapatkan yang baru.
  • Dua endpoint, bukan fan-out: satu primary dan satu backup. Setiap pesanan yang dikonfirmasi menghasilkan satu webhook, yang dikirimkan ke primary; backup hanya digunakan jika batas primary telah habis.
  • Perubahan URL tanpa downtime (zero-downtime): daftarkan alamat baru sebagai backup, verifikasi alamat tersebut, lalu lakukan PATCH menjadi primary — pertukaran berlangsung secara atomik.
  • Menjeda: PATCH … {"is_active": false} menghentikan pengiriman tanpa menghapus endpoint.
  • Hanya peristiwa sukses: delegation.confirmed, bandwidth.delegated, activation.confirmed. Tidak ada peristiwa kegagalan — pesanan yang gagal atau kehabisan waktu tidak menghasilkan webhook.
  • Jenis peristiwa baru dapat ditambahkan seiring waktu. Rutekan berdasarkan bidang event dan abaikan jenis yang belum Anda tangani — Anda tidak perlu mendaftarkan apa pun yang baru untuk mulai menerimanya.
  • Hash diverifikasi secara on-chain sebelum pengiriman (lihat catatan di bagian atas): webhook bisa berisi hash yang semuanya berada di dalam blok, atau tidak dikirim sama sekali.
  • URL divalidasi demi keamanan SSRF saat pendaftaran dan pada setiap pengeditan; sisi pengiriman memvalidasi ulang saat waktu kirim.