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

Вебхуки — сповіщення про замовлення ​

Зареєструйте HTTPS-ендпоінт, щоб отримувати підписаний вебхук у той самий момент, коли одне з ваших замовлень виконано та підтверджено в блокчейні. Замість опитування (polling), ви продовжуєте свій робочий процес (наприклад, виплачуєте USDT) одразу після надходження сповіщення.

Доставляються три події:

ПодіяВідправляється, коли
delegation.confirmedОренда Energy (1h / 5m) підтверджена в блокчейні
bandwidth.delegatedЗамовлення Bandwidth виконано
activation.confirmedАктивація адреси виконана в блокчейні

Ця сторінка охоплює API керування (створення / перегляд списку / редагування / ротація секрету / видалення ваших ендпоінтів) та формат вебхуків, які ми вам надсилаємо.

ℹ️ Ролі. Тут ви керуєте своїми ендпоінтами. Доставка виконується системою Netts асинхронно після підтвердження замовлення — нічого опитувати не потрібно. Надсилаються лише успішні події; помилки та таймаути ніколи не доставляються.

🔒 Кожен хеш, який ми надсилаємо, спочатку перевіряється в блокчейні. Вебхук відправляється лише після того, як кожен хеш транзакції в ньому знайдено в блоці. Якщо хеша в блоці ще немає, доставка призупиняється та перевіряється повторно кожні 30 секунд терміном до 5 хвилин; якщо він так і не потрапить туди, для цього замовлення нічого не надсилається. Ви ніколи не отримаєте хеш, якого не існує в блокчейні.

Базовий URL ендпоінта ​

https://netts.io/apiv2/webhooks

Заголовки запиту ​

ЗаголовокОбов'язковийОпис
Content-TypeТак (для POST/PATCH)application/json
X-API-KEYТакВаш API ключ із панелі керування Netts
X-Real-IPТакIP-адреса з вашого білого списку

Ваш user_id визначається на основі API ключа — передавати його не потрібно. Ви можете бачити та змінювати лише власні ендпоінти.


Основний та резервний ендпоінт ​

Ви реєструєте щонайбільше два ендпоінти, і кожен із них має роль role:

РольПризначення
primaryАдреса, на яку доставляється кожен вебхук.
backupРезерв. Використовується лише тоді, коли доставка на primary зазнала невдачі після вичерпання спроб.

Одне підтверджене замовлення генерує один вебхук. Це не віялова розсилка: одна й та сама подія ніколи не надсилається на обидві адреси одночасно. Ендпоінт backup існує для стійкості — якщо ваш основний хост недоступний або постійно повертає код, відмінний від 2xx, доставка перемикається на резервний замість того, щоб бути скасованою.

Перший ендпоінт, який ви створюєте, стає primary, другий — backup. Ви можете вказати role явно або поміняти їх місцями пізніше за допомогою PATCH.

Чому немає окремого URL для кожного типу операцій? Тому що тип події передається всередині тіла запиту, у полі event. Один обробник, одна перевірка підпису, і нові типи подій починають надходити без реєстрації чогось нового з вашого боку.


Керування ендпоінтами ​

Створення — POST /apiv2/webhooks ​

Реєструє новий ендпоінт і повертає secret, який відображається лише один раз (збережіть його — він підписує кожен вебхук, який ви отримуєте).

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

Якщо пропустити role, призначається перша вільна: спочатку primary, потім 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"
        }
    }
}

Вимоги до URL (перевіряються під час створення та кожного редагування):

  • обов'язково https;
  • має визначатися в публічну адресу — loopback, приватні (RFC1918), link-local (включно з 169.254.169.254) та інші немаршрутизовані діапазони відхиляються;
  • без облікових даних в URL (user:pass@…);
  • довжина до 2048 символів.

Відхилений URL повертає 400.

Ви можете мати два ендпоінти — один primary та один backup. Спроба створити третій повертає 409 (4090). Запит role, яка вже зайнята, повертає 409 (4091) — поміняйте ролі місцями за допомогою PATCH або спочатку видаліть наявний.

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

Список — GET /apiv2/webhooks ​

Повертає ваші ендпоінти (secret тут ніколи не повертається).

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

Отримання одного — GET /apiv2/webhooks/{id} ​

Така сама структура, як і в елемента списку (без secret). Чужий або неіснуючий id повертає 404.

Редагування — PATCH /apiv2/webhooks/{id} ​

Зміна url, is_active та/або role. Можна надсилати будь-яку підмножину; порожнє тіло повертає 422. Змінений url повторно перевіряється (https / SSRF). Чужий або неіснуючий id повертає 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"
        }
    }
}

Підвищення резервного. Відправлення {"role": "primary"} на ваш резервний ендпоінт міняє обидві ролі місцями в одній транзакції — старий основний стає резервним. Ви ніколи не залишитеся без основної адреси, і окремий виклик для іншого ендпоінта не потрібен.

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

Встановіть is_active: false, щоб призупинити доставку без видалення ендпоінта; true — для відновлення. Призупинення вашого primary не підвищує резервний — доставка все одно спрямовується на основний. Поміняйте ролі місцями, якщо хочете, щоб резервний перехопив трафік.

Ротація секрету — POST /apiv2/webhooks/{id}/rotate-secret ​

Генерує новий secret і повертає його один раз. Новий секрет набирає чинності негайно для наступних доставок — жодних додаткових дій не потрібно. Кожен ендпоінт має свій власний секрет: ротація секрету основного ендпоінта не змінює секрет резервного.

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

Видалення — DELETE /apiv2/webhooks/{id} ​

Безповоротно видаляє ендпоінт і звільняє його роль. Повертає 204 (без тіла); чужий або неіснуючий id повертає 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"

Вебхуки, які ми доставляємо ​

Коли одне з ваших замовлень виконано, Netts надсилає POST на ваш ендпоінт primary. Кожне тіло має тип application/json (UTF-8); адреси та хеші завжди надаються повністю.

Поля, спільні для всіх подій:

ПолеТипОпис
eventstringТип події — ключ маршрутизації для вашого обробника
delivery_idintID доставки — ключ дедуплікації на вашому боці. Також надсилається в заголовку X-Netts-Delivery.
order_idstringID вашого замовлення
order_typestring1h, 5m, bandwidth або activation
tx_hashesstring[]Усі хеші транзакцій операції, кожен із яких підтверджений у блокчейні
confirmed_atstringUTC ISO-8601

delegation.confirmed — оренда 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"
}
ПолеТипОпис
order_typestring1h або 5m
receive_addressstringTRON адреса, яка отримала Energy
energy_amountintКількість делегованої Energy
tx_hashstringЗастаріле поле, збережене для сумісності: те саме, що й tx_hashes[0]
delegation_timestampint?Необов'язково — присутнє лише за умови підтвердження через шлях Mongo

У нових інтеграціях надавайте перевагу tx_hashes — замовлення в теорії може бути виконане більш ніж однією транзакцією. tx_hash продовжуватиме працювати.

bandwidth.delegated — замовлення 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"
}
ПолеТипОпис
rental_label / rental_secondsstring / intТривалість оренди, наприклад 1h / 3600
receive_addressstringTRON адреса, яка отримала Bandwidth
bandwidth_amountintОдиниці Bandwidth (нетто)
fulfillmentstringСпосіб виконання замовлення — див. нижче

Значення fulfillment:

ЗначенняЗначенняtx_hashes
delegatedBandwidth делеговано з нашого пулу1+ хешів
trx_sendВиконано шляхом надсилання TRX на адресу замість делегування1+ хешів
already_enoughАдреса вже мала достатньо вільного Bandwidth — у блокчейн нічого не надсилалосяпорожньо

already_enough — це єдиний випадок, коли tx_hashes порожній: замовлення успішно закрите, але транзакція відсутня, оскільки в ній не було потреби.

activation.confirmed — активація адреси ​

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"
}
ПолеТипОпис
order_idstringID замовлення на активацію (числовий рядок)
addressstringTRON адреса, яка була активована
activation_typestringACC_CREATE (AccountCreateContract) або DIRECT (переказ TRX)
sourcestringМаркер джерела. Або сервісний тег, або ID замовлення Energy, яке вимагало активації

Доставляються лише реальні активації. Якщо виявилося, що адреса вже активна і транзакція не здійснювалася, вебхук узагалі не надсилається.

Замовлення Energy, яке також вимагало активації, генерує два вебхуки — один activation.confirmed та один delegation.confirmed. Це окремі події з окремими delivery_id; маршрутизуйте їх за полем event.

Заголовки, які ми надсилаємо:

ЗаголовокЗначення
X-Netts-EventТип події: delegation.confirmed, bandwidth.delegated або activation.confirmed
X-Netts-Deliverydelivery_id (дедуплікація)
X-Netts-Timestampunix-час у секундах на момент відправлення
X-Netts-Signaturesha256=<hex>, hex = HMAC_SHA256(secret, "<timestamp>." + raw_body)
User-Agentnetts-webhook/1.0

Перевірка підпису ​

Підпис відповідає схемі Stripe (timestamp.body), обчислюється на основі сирих байтів (raw bytes), які ми надсилаємо. Перерахуйте його за допомогою вашого secret, порівняйте за сталий час (constant-time) і відхиліть, якщо X-Netts-Timestamp виходить за межі вікна ±5 хвилин (захист від повторного відтворення).

Підписуйте секретом того ендпоінта, який отримав запит: основний і резервний мають окремі секрети. Якщо обидві ваші адреси обслуговуються одним обробником, обирайте секрет залежно від URL, на який надійшов запит.

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)

Семантика доставки (важливо — at-least-once) ​

Доставка здійснюється за принципом щонайменше один раз (at-least-once): втрачена відповідь може спричинити повторну спробу, тому ви можете отримати одну й ту саму подію двічі. Оскільки бізнес-дія (виплата USDT) пов'язана з коштами:

  1. Дедуплікація обов'язкова — обробляйте кожну подію ідемпотентно за delivery_id (та/або order_id); повтор є порожньою операцією (no-op).
  2. Перевіряйте HMAC перед будь-якою дією з коштами — не довіряйте тілу запиту, доки підпис не зійдеться і X-Netts-Timestamp не буде актуальним.
  3. Повертайте 2xx лише після того, як надійно зберегли подію — інакше ми (цілком виправдано) повторимо спробу.

Відповідайте 2xx для підтвердження; будь-який статус, відмінний від 2xx, або таймаут викликає повторну спробу.

Порядок спроб:

  1. Повторні спроби спрямовуються на ваш ендпоінт primary. Вікно залежить від типу замовлення: для замовлень 5m повтори тривають ~1 хвилину, для всіх інших типів — ~10 хвилин.
  2. Якщо вікно вичерпано і ви зареєстрували backup, доставка перемикається туди, і графік повторів починається спочатку — з підписом власним секретом ендпоінта backup.
  3. Лише після того, як спроби для резервного також буде вичерпано, доставка позначається як невдала.

Протягом усього процесу використовується один і той самий delivery_id, тому повідомлення, яке спочатку зазнало невдачі на основному, а потім успішно пройшло на резервному, все одно залишається однією подією для вашої логіки дедуплікації.


Довідник кодів помилок ​

КодОписHTTP-статус
10000Успіх (created / ok / updated / rotated)200 / 201
-Видалено (без тіла)204
4000Некоректний / небезпечний URL вебхука (не https, приватний/loopback, облікові дані, занадто довгий)400
-1Недійсний API ключ / IP-адреси немає в білому списку401
-1Ендпоінт не знайдено (або він не ваш)404
4090Досягнуто ліміту ендпоінтів (максимум 2: primary, backup)409
4091Запитувана роль уже зайнята — поміняйте місцями через PATCH або видаліть наявний ендпоінт409
4220Немає даних для оновлення (PATCH з порожнім тілом)422
5003Не вдалося створити ендпоінт (спробуйте ще раз)503

Ліміти запитів (Rate Limits) ​

Обмежується на рівні API ключа (заголовок X-API-KEY):

ПеріодЛіміт
1 секунда5 запитів
1 хвилина150 запитів

Перевищення ліміту запитів (429) ​

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

Примітки ​

  • Секрет відображається один раз — під час створення та під час ротації. Він ніколи не повертається у відповідях GET/LIST. Втратили його? Зробіть ротацію, щоб отримати новий.
  • Два ендпоінти, а не віялова розсилка: один primary та один backup. Кожне підтверджене замовлення генерує один вебхук, який доставляється на основний; резервний використовується лише тоді, коли спроби для основного вичерпано.
  • Зміна URL без простою: зареєструйте нову адресу як backup, перевірте її, а потім виконайте PATCH, змінивши її на primary — заміна відбувається атомарно.
  • Призупинення: PATCH … {"is_active": false} зупиняє доставку без втрати ендпоінта.
  • Лише успішні події: delegation.confirmed, bandwidth.delegated, activation.confirmed. Подій про помилку немає — невдале замовлення або замовлення з вичерпаним таймаутом не створює вебхука.
  • З часом можуть додаватися нові типи подій. Маршрутизуйте за полем event та ігноруйте типи, які ви ще не обробляєте — вам не потрібно реєструвати щось нове, щоб почати їх отримувати.
  • Хеші перевіряються в блокчейні перед доставкою (див. примітку на початку): вебхук або містить хеші, які вже є в блоці, або не надсилається зовсім.
  • URL-адреси перевіряються на безпеку щодо SSRF під час реєстрації та при кожному редагуванні; сервіс доставки повторно перевіряє їх під час відправлення.