# Підписки через WebSocket

> Source: https://docs.blockvectra.com/uk/guides/websocket-subscriptions/

BlockVectra надає безпечні з'єднання WebSocket (`wss://`) для потокової передачі підписок на події Ethereum у реальному часі разом зі стандартними запитами JSON-RPC.

## Вибір WebSocket, Webhook або опитування

Використовуйте WebSocket для отримання `newHeads` та відфільтрованих `logs` у реальному часі, коли ваш застосунок здатний підтримувати постійне з'єднання. Використовуйте [Blockchain Webhook API](https://docs.blockvectra.com/en/guides/webhook-push/) для отримання активності відстежуваних гаманців на ендпоінт HTTPS із [перевіркою підписів сирого тіла](https://docs.blockvectra.com/en/guides/webhook-push/#verify-signatures), повторними спробами та повторним відтворенням збережених збігів. Використовуйте [опитування через HTTP](https://docs.blockvectra.com/en/guides/stablecoin-payments/) для запланованого моніторингу платежів ERC-20 та відновлення історичних логів. Посібник зі стейблкоїнів також містить приклад [отримувача вебхуків для USDT / USDC](https://docs.blockvectra.com/en/guides/stablecoin-payments/#receive-payments-with-webhooks). Архітектурне порівняння підтримки мереж, вимог до отримувача та компромісів відновлення для розробників та AI-агентів див. у [посібнику з вибору між вебхуками, WebSocket або опитуванням RPC](https://docs.blockvectra.com/en/guides/webhook-vs-websocket/).

Підтримка WebSocket визначається полями `ws` та `subscriptions` у `GET /v1/chains`; підтримка Push — автентифікованим списком `GET /v1/push/chains`. Мережа без WebSocket усе одно може використовувати вебхуки для адрес, якщо вона присутня в цьому списку.

Розриви з'єднання WebSocket вимагають повторної підписки та заповнення пропущених даних; вони не генерують керуючі події Push `subscription.gap` або `chain.reorg`. Для вебхуків виникнення прогалини потребує сканування діапазону; сповіщення про реорганізацію вимагає позначення або відкидання замінених подій перед збереженням автоматично повторно доставлених канонічних подій. [Повторне відтворення Push](https://docs.blockvectra.com/en/guides/webhook-push/#delivery-retries-and-replay) повторно надсилає збережені збіги, а не дані до додавання адреси або мережі чи під час перебування підписки офлайн. Перегляньте [правила тарифікації](https://docs.blockvectra.com/en/guides/billing-rules/) та [довідник помилок](https://docs.blockvectra.com/en/errors/) під час реалізації відновлення.

## Доступні мережі

Ви можете перевірити, чи активні підписки WebSocket у певній мережі, прочитавши значення `ws` (boolean) та `subscriptions` (масив підтримуваних типів) у `GET /v1/chains`.

У наведеній нижче таблиці відображено мережі, для яких увімкнено підтримку WebSocket:

| Мережа | Ендпоінт WebSocket (ключ у шляху) |
| --- | --- |
| Robinhood Chain | `wss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}` |
| Robinhood Chain Testnet | `wss://api.blockvectra.com/v1/robinhood_testnet/{api_key}` |

## Підключення та автентифікація

Клієнти встановлюють безпечне з'єднання TLS WebSocket (`wss://`). API key можна надати двома способами:

* **Ключ у шляху**: `wss://api.blockvectra.com/v1/{chain}/{api_key}`
* **Ключ у заголовку**: `wss://api.blockvectra.com/v1/{chain}` із заголовком `x-api-key: {api_key}` або `Authorization: Bearer {api_key}` під час рукостискання оновлення протоколу HTTP (HTTP Upgrade).

Якщо передано ключ у шляху, використовується саме він, а обидва заголовки автентифікації ігноруються. Без ключа у шляху непорожній заголовок `x-api-key` має пріоритет над `Authorization: Bearer`. Браузерні API WebSocket не дозволяють встановлювати ці заголовки; використовуйте URL з ключем у шляху.

### Перевірки доступу під час рукостискання

Рукостискання може завершитися помилкою в таких випадках:

* **Автентифікація**: відсутній API key повертає HTTP 401 ([`missing_api_key`](https://docs.blockvectra.com/en/errors/#missing_api_key)); невідомий, відключений або відкликаний API key повертає HTTP 401 ([`invalid_api_key`](https://docs.blockvectra.com/en/errors/#invalid_api_key)); якщо автентифікація тимчасово недоступна, відповіддю буде HTTP 503 ([`auth_unavailable`](https://docs.blockvectra.com/en/errors/#auth_unavailable)).
* **Баланс акаунта**: акаунт із нульовим або від'ємним передоплаченим балансом повертає HTTP 402 ([`balance_exhausted`](https://docs.blockvectra.com/en/errors/#balance_exhausted)); якщо стан тарифікації неможливо підтвердити, повертається HTTP 503 ([`billing_unavailable`](https://docs.blockvectra.com/en/errors/#billing_unavailable)).
* **Ліміти з'єднань**: перевищення ліміту на ключ (20 з'єднань) або на акаунт (50 з'єднань) повертає HTTP 429 ([`ws_connection_limit`](https://docs.blockvectra.com/en/errors/#ws_connection_limit)).
* **Доступність мережі**: запит до невідомої або непідтримуваної мережі повертає HTTP 404 ([`unknown_chain`](https://docs.blockvectra.com/en/errors/#unknown_chain)).
* **Ємність сервера**: коли сервер зайнятий або перевантажений, рукостискання повертає HTTP 503 ([`overloaded`](https://docs.blockvectra.com/en/errors/#overloaded)) із заголовком `Retry-After`.

Після підключення клієнти можуть надсилати стандартні запити JSON-RPC 2.0 (такі як `eth_blockNumber` або `eth_call`) та методи керування підписками у вигляді текстових фреймів UTF-8.

## Правила тарифікації

* Встановлення з'єднання, підтримка простою відкритого з'єднання та перевірки пульсу ping/pong не тарифікуються.
* Успішні виклики `eth_subscribe` та `eth_unsubscribe` тарифікуються, включно зі скасуванням підписки, що повертає `false`; невдалі виклики не тарифікуються. Звичайні виклики JSON-RPC підпорядковуються [правилам тарифікації JSON-RPC](https://docs.blockvectra.com/en/guides/billing-rules/).
* Сповіщення `newHeads` враховуються один раз на хеш блоку для кожного з'єднання, незалежно від того, скільки підписок `newHeads` відкрито на цьому з'єднанні.
* Сповіщення `logs` враховуються один раз на підписку для кожного хешу блоку та фази з відповідними логами; блоки без збігів не тарифікуються. Кілька відповідних логів в одному блоці та фазі не збільшують плату. Окремі підписки рахуються окремо, навіть якщо їхні фільтри перекриваються. Логи реорганізації (`removed: true`) утворюють окрему одиницю; замінений блок на тій самій висоті має інший хеш і є іншою одиницею.
* Сповіщення тарифікуються лише після їхнього успішного скидання у буфер надсилання сокета; сповіщення в черзі або відкинуті сповіщення, які не були скинуті в сокет, не тарифікуються. Сповіщення, що потрапили в чергу до відповіді на `eth_unsubscribe`, враховуються, якщо вони були скинуті в буфер. Повідомлення WebSocket не містять заголовків тарифікації HTTP; перевіряйте використання акаунта щодо нарахованих CU.

## Методи підписки

API реалізує стандартний інтерфейс публікації/підписки Ethereum: `eth_subscribe` та `eth_unsubscribe`.

### `newHeads`

Надсилає новий об'єкт заголовка блоку щоразу, коли новий блок додається до вершини ланцюга.

* **Запит на підписку**:
  ```json
  {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  ```
* **Відповідь на підписку**: повертає непрозорий шістнадцятковий ідентифікатор підписки:
  ```json
  {"jsonrpc":"2.0","id":1,"result":"0x1"}
  ```
* **Фрейм push-сповіщення**:
  ```json
  {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}
  ```

### `logs`

Надсилає події логів, що відповідають зазначеним критеріям фільтра.

* **Вимога до фільтра**: кожен фільтр підписки `logs` **повинен** визначати `address` (адресу контракту або масив адрес) або `topic0` (перша позиція теми, непорожня). Фільтр, у якому не вказано жодного з цих параметрів (наприклад, `{}` або `{"topics":[null,"0x..."]}`), відхиляється з кодом помилки `-32602` ([`logs_filter_required`](https://docs.blockvectra.com/en/errors/#logs_filter_required)).

* **Ліміти фільтра**: не більше 100 адрес; не більше 4 позицій тем із не більше ніж 16 хешами-кандидатами на позицію.

* **Ємність фільтрів**: якщо активні фільтри логів досягають ліміту ємності, підписка повертає код помилки `-32022` ([`ws_filter_capacity`](https://docs.blockvectra.com/en/errors/#ws_filter_capacity)).

* **Реорганізації мережі**: якщо блок видаляється через реорганізацію ланцюга, сповіщення для видалених логів містять `"removed": true`.

* **Запит на підписку**:
  ```json
  {"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}
  ```

### `eth_unsubscribe`

Припиняє активну підписку за її ідентифікатором підписки.

* **Запит на скасування підписки**:
  ```json
  {"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
  ```
* **Відповідь на скасування підписки**:
  ```json
  {"jsonrpc":"2.0","id":3,"result":true}
  ```

## Приклади запуску

**viem v2 (TypeScript)**

Підключайтеся за допомогою [viem](https://viem.sh) v2 через `createPublicClient` та транспорт `webSocket`. Замініть `{chain}` на ідентифікатор цільової мережі, а `{api_key}` — на ваш API key:

```ts
import { createPublicClient, webSocket } from 'viem';

const apiKey = process.env.BLOCKVECTRA_API_KEY || '{api_key}';
const url = `wss://api.blockvectra.com/v1/robinhood_mainnet/${apiKey}`;

const client = createPublicClient({
  transport: webSocket(url),
});

// 1. Subscribe to new block headers (newHeads)
const unwatchBlocks = client.watchBlocks({
  onBlock: (block) => {
    console.log('New block header received:', block.number, block.hash);
  },
  onError: (error) => {
    console.error('watchBlocks error:', error);
  },
});

// 2. Subscribe to contract event logs (filter requires address or topic0)
const unwatchEvents = client.watchEvent({
  address: '0x1234567890123456789012345678901234567890',
  onLogs: (logs) => {
    console.log('Matching logs received:', logs);
  },
  onError: (error) => {
    console.error('watchEvent error:', error);
  },
});
```


  **Command line (websocat / wscat)**

Підключайтеся за допомогою інструментів командного рядка, таких як `websocat` або `wscat`, і надсилайте необроблені фрейми JSON-RPC:

```bash
# Connect with path-based API key using websocat
websocat "wss://api.blockvectra.com/v1/{chain}/{api_key}"

# Alternatively, pass the key via request header
websocat -H="x-api-key: {api_key}" "wss://api.blockvectra.com/v1/{chain}"

# Or connect using wscat
wscat -c "wss://api.blockvectra.com/v1/{chain}/{api_key}"
```

Надсилайте команди підписки в інтерактивну сесію:

```json
{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
{"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}
{"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
```


## Коди закриття та дії клієнта

Коли сервер завершує сесію WebSocket, він надсилає фрейм Close із певним кодом закриття та коротким поясненням. У таблиці нижче наведено коди закриття, які видає сервер, та рекомендовані дії:

|             Код закриття | Рядок причини                    | Опис                                                                                                                                                           | Можливість повтору | Дія клієнта                                                                                                                                                                                                                                                        |
| -----------------------: | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [1001](https://docs.blockvectra.com/en/errors/#1001) | `idle`                           | Неактивне з'єднання без підписок або повідомлень протягом 3600 секунд (1 година)                                                                               |         Так        | Перепідключіться за потреби.                                                                                                                                                                                                                                       |
| [1003](https://docs.blockvectra.com/en/errors/#1003) | `binary frames are not accepted` | Отримано бінарний фрейм WebSocket; дозволені лише текстові фрейми UTF-8                                                                                        |         Ні         | Не перепідключайтеся автоматично. Оновіть клієнт для надсилання текстових фреймів.                                                                                                                                                                                 |
| [1009](https://docs.blockvectra.com/en/errors/#1009) | `message too large`              | Вхідне корисне навантаження перевищило 1 MiB                                                                                                                   |         Ні         | Не перепідключайтеся автоматично. Розбийте великі запити або зменшіть розмір корисного навантаження.                                                                                                                                                               |
| [1012](https://docs.blockvectra.com/en/errors/#1012) | `service restart`                | Перезапуск сервера або сесія досягла максимальної тривалості життя (24 години)                                                                                 |         Так        | Перепідключіться з використанням рандомізованої затримки, відновіть підписки та заповніть пропущені дані.                                                                                                                                                          |
| [1013](https://docs.blockvectra.com/en/errors/#1013) | `chain unavailable`              | Мережа недоступна                                                                                                                                              |         Так        | Перепідключіться з експоненціальною затримкою з повним джитером, відновіть підписки та заповніть пропущені дані.                                                                                                                                                   |
| [1013](https://docs.blockvectra.com/en/errors/#1013) | `overloaded`                     | Сервер тимчасово перевантажений                                                                                                                                |         Так        | Перепідключіться з експоненціальною затримкою з повним джитером, відновіть підписки та заповніть пропущені дані.                                                                                                                                                   |
| [4402](https://docs.blockvectra.com/en/errors/#4402) | `insufficient balance`           | Баланс акаунта вичерпано                                                                                                                                       |         Ні         | Не перепідключайтеся автоматично. [Поповніть баланс, потім перепідключіться](https://docs.blockvectra.com/en/guides/billing-rules/).                                                                                                                                                           |
| [4404](https://docs.blockvectra.com/en/errors/#4404) | `invalid api key`                | API key невідомий, відключений або відкликаний                                                                                                                 |         Ні         | Не перепідключайтеся автоматично. Перевірте або замініть API key у консолі перед повторним підключенням.                                                                                                                                                           |
| [4408](https://docs.blockvectra.com/en/errors/#4408) | `slow consumer`                  | Сервер закриває сесію, черга push якої перевищує 512 KiB, і відкидає очікувані сповіщення; клієнти можуть не отримати фрейм закриття (браузер повідомляє 1006) |         Так        | Розглядайте неочікувані розриви з'єднання (фрейм закриття не отримано, браузер повідомляє 1006) як 4408: перепідключіться із затримкою, відновіть підписки та заповніть відкинуті дані за допомогою `eth_getLogs`; зменшіть кількість підписок або читайте швидше. |
| [4429](https://docs.blockvectra.com/en/errors/#4429) | `push rate exceeded`             | Швидкість сповіщень перевищила 1,000 пушів/секунду                                                                                                             |         Так        | Зменшіть кількість підписок або звузьте фільтри; перепідключіться із затримкою, оформіть підписку знову та заповніть пропущені дані.                                                                                                                               |
| [4503](https://docs.blockvectra.com/en/errors/#4503) | `billing unavailable`            | Тарифікація тимчасово недоступна                                                                                                                               |         Так        | Тимчасовий стан; перепідключіться з використанням експоненціальної затримки з повним джитером.                                                                                                                                                                     |

## Перепідключення та експоненціальна затримка

Щоб запобігти шторму синхронних повторних підключень під час обриву з'єднання, клієнти повинні реалізувати експоненціальну затримку з повним випадковим джитером:

* **Формула затримки**: перед n-ю спробою повторного підключення (n = 0, 1, 2, ...) зачекайте інтервал часу, обраний рівномірно випадковим чином:
  ```
  delay = random(0, min(20s, 0.5s * 2^n))
  ```
* **Скидання лічильника**: скидайте лічильник спроб n на 0 лише після підтримки безперервного стабільного з'єднання протягом щонайменше `60 секунд`.
* **Код закриття 1012**: впроваджуйте рандомізовану початкову затримку перед першою спробою повторного підключення, щоб уникнути сплесків синхронних підключень.
* **Коди без можливості повтору**: не перепідключайтеся автоматично у відповідь на [4402](https://docs.blockvectra.com/en/errors/#4402), [4404](https://docs.blockvectra.com/en/errors/#4404), [1003](https://docs.blockvectra.com/en/errors/#1003) або [1009](https://docs.blockvectra.com/en/errors/#1009).

### Відновлення пропущених даних після повторного підключення

Підписки WebSocket не зберігаються між з'єднаннями; сповіщення, випущені під час розриву з'єднання, не зберігаються на сервері. Після відновлення підключення клієнтам слід виконати стратегію наздоганяння:

1. **Заповнення логів за допомогою `eth_getLogs`**:
   * Зберігайте найбільший номер блоку, успішно оброблений застосунком (`last_processed_block`).
   * Одразу викличте `eth_subscribe("logs", ...)` після перепідключення, щоб отримувати події в реальному часі.
   * Запитуйте пропущені блоки через `eth_getLogs` із `fromBlock: last_processed_block + 1` та `toBlock: "latest"` (або першим блоком, отриманим із живого потоку).
   * Якщо розрив з'єднання перевищує ліміт `max_logs_block_range` мережі (з `GET /v1/chains`), розбийте запити на частини, що не перевищують цей ліміт.
   * Дедуплікуйте записи логів на межі запитів за допомогою унікального кортежу `(blockHash, transactionHash, logIndex)`.
2. **Заповнення заголовків блоків за допомогою `eth_getBlockByNumber`**:
   * Зафіксуйте останній номер і хеш блоку, отримані перед розривом з'єднання.
   * Повторно підпишіться на `newHeads`.
   * Запитуйте `eth_getBlockByNumber("latest", false)` та послідовно вибирайте пропущені проміжні блоки. Перевіряйте неперервність ланцюжка `parentHash` для виявлення реорганізацій.

## Ліміти

| Ліміт                                           | Значення                                                            | Результат у разі перевищення                                        |
| ----------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Підписок на одне з'єднання WebSocket            | 100                                                                 | `-32022` [`subscription_limit`](https://docs.blockvectra.com/en/errors/#subscription_limit)     |
| Підписок `newHeads` на одне з'єднання WebSocket | 4                                                                   | `-32022` [`subscription_limit`](https://docs.blockvectra.com/en/errors/#subscription_limit)     |
| Вимоги до фільтра підписки `logs`               | Необхідно вказати `address` або `topic0` (перша позиція в `topics`) | `-32602` [`logs_filter_required`](https://docs.blockvectra.com/en/errors/#logs_filter_required) |

## Наступні кроки

* [Переглянути каталог наборів даних](https://blockvectra.com/en/data/), щоб ознайомитися з кожним набором даних, який індексує BlockVectra.
* [Ознайомитися з безкоштовним планом та цінами](https://blockvectra.com/en/pricing/#free), щоб дізнатися, що включено у ваш акаунт.
* [Увійти в консоль](https://console.blockvectra.com/login/?next=%2Fkeys%2F), щоб створити API key.
