> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket API

> Подписки Solana в реальном времени для аккаунтов, слотов, логов и многого другого

## Обзор

OrbitFlare поддерживает постоянные WebSocket-соединения для получения данных Solana в реальном времени. WebSocket-подписки отправляют обновления вашему клиенту по мере их появления в блокчейне — без необходимости опроса.

WebSocket-эндпоинты используют схему `wss://` с теми же кодами регионов, что и HTTP API:

```
wss://{region}.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY
```

Эндпоинт основной сети с автоматической маршрутизацией:

```
wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY
```

<Tip>
  Ваш лицензионный ключ находится в разделе **Лицензии** вашего [OrbitFlare Dashboard](https://orbitflare.com/dashboard). Передайте его как параметр запроса `api_key` — тот же ключ, что используется для HTTP RPC.
</Tip>

## Подключение

```javascript theme={null}
const WebSocket = require("ws");

const ws = new WebSocket(
  "wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY"
);

ws.on("open", () => {
  console.log("Connected");
});

ws.on("message", (data) => {
  const msg = JSON.parse(data);
  console.log("Received:", msg);
});

ws.on("error", (err) => {
  console.error("WebSocket error:", err);
});

ws.on("close", (code, reason) => {
  console.log(`Connection closed: ${code} ${reason}`);
});
```

<Note>
  WebSocket-соединения, простаивающие более **60 секунд** без обмена сообщениями, закрываются сервером. Отправляйте ping или поддерживайте активные подписки для сохранения соединения.
</Note>

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

### accountSubscribe

Получайте обновления при изменении баланса lamport или данных конкретного аккаунта.

```javascript theme={null}
ws.on("open", () => {
  ws.send(JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "accountSubscribe",
    params: [
      "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",
      { encoding: "base64", commitment: "confirmed" }
    ],
  }));
});
```

**Поля обновления:**

| Поле         | Описание                                                       |
| ------------ | -------------------------------------------------------------- |
| `lamports`   | Текущий баланс в lamport                                       |
| `data`       | Данные аккаунта (кодировка определяется параметром `encoding`) |
| `owner`      | Публичный ключ программы-владельца                             |
| `executable` | Является ли аккаунт исполняемой программой                     |
| `rentEpoch`  | Эпоха, в которую следующий раз будет начислена аренда          |

***

### logsSubscribe

Получайте сообщения журнала транзакций в реальном времени. Опционально фильтруйте по конкретной программе.

```javascript theme={null}
// All transactions
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 2,
  method: "logsSubscribe",
  params: ["all"],
}));

// Filter to a specific program
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 3,
  method: "logsSubscribe",
  params: [
    { mentions: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"] }, // Raydium AMM
    { commitment: "confirmed" }
  ],
}));
```

**Поля обновления:**

| Поле        | Описание                                  |
| ----------- | ----------------------------------------- |
| `signature` | Подпись транзакции (base-58)              |
| `err`       | `null` при успехе, объект ошибки при сбое |
| `logs`      | Массив строк с сообщениями журнала        |

***

### slotSubscribe

Получайте уведомление каждый раз при обработке слота.

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 4,
  method: "slotSubscribe",
  params: [],
}));
```

**Поля обновления:**

| Поле     | Описание                               |
| -------- | -------------------------------------- |
| `slot`   | Номер текущего слота                   |
| `parent` | Номер родительского слота              |
| `root`   | Наивысший подтверждённый корневой слот |

***

### signatureSubscribe

Получайте одноразовое уведомление, когда конкретная подпись транзакции достигает заданного уровня подтверждения.

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 5,
  method: "signatureSubscribe",
  params: [
    "TRANSACTION_SIGNATURE_HERE",
    { commitment: "finalized" }
  ],
}));
```

Подписка автоматически закрывается после отправки первого уведомления.

***

### programSubscribe

Получайте обновления для всех аккаунтов, принадлежащих конкретной программе.

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 6,
  method: "programSubscribe",
  params: [
    "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // SPL Token
    {
      encoding: "jsonParsed",
      commitment: "confirmed",
      filters: [{ dataSize: 165 }], // Standard token account size
    }
  ],
}));
```

***

### blockSubscribe

Получайте полные данные блока при его подтверждении. **Требует дополнения — обратитесь в поддержку для активации.**

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 7,
  method: "blockSubscribe",
  params: ["all", { commitment: "confirmed", encoding: "base64" }],
}));
```

***

### rootSubscribe

Получайте наивысший подтверждённый корневой слот каждый раз при его продвижении.

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 8,
  method: "rootSubscribe",
  params: [],
}));
```

***

### voteSubscribe

Получайте необработанные транзакции голосования по мере их появления в сети gossip. **Высокий объём — фильтруйте тщательно.**

```javascript theme={null}
ws.send(JSON.stringify({
  jsonrpc: "2.0",
  id: 9,
  method: "voteSubscribe",
  params: [],
}));
```

## Отписка

Каждый метод подписки имеет соответствующий метод `Unsubscribe`. Передайте ID подписки, возвращённый в ответе на первоначальную подписку.

```javascript theme={null}
// Subscribe and capture the subscription ID
ws.on("message", (data) => {
  const msg = JSON.parse(data);

  // Subscription confirmation contains the subscription ID
  if (msg.id === 1 && msg.result !== undefined) {
    const subscriptionId = msg.result;
    console.log("Subscribed, ID:", subscriptionId);

    // Unsubscribe later
    ws.send(JSON.stringify({
      jsonrpc: "2.0",
      id: 10,
      method: "accountUnsubscribe",
      params: [subscriptionId],
    }));
  }
});
```

Доступные методы отписки: `accountUnsubscribe`, `logsUnsubscribe`, `slotUnsubscribe`, `signatureUnsubscribe`, `programUnsubscribe`, `blockUnsubscribe`, `rootUnsubscribe`, `voteUnsubscribe`.

## Поддержание соединения

WebSocket-соединения закрываются после 60 секунд бездействия. Периодически отправляйте JSON-RPC ping для поддержания соединения:

```javascript theme={null}
const pingInterval = setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ jsonrpc: "2.0", id: 0, method: "ping" }));
  }
}, 30_000);

ws.on("close", () => clearInterval(pingInterval));
```

## Переподключение

Реализуйте автоматическое переподключение с экспоненциальной задержкой для production-приложений:

```javascript theme={null}
function connect(url, onMessage) {
  let ws;
  let delay = 1000;
  let attempt = 0;

  function createConnection() {
    ws = new WebSocket(url);

    ws.on("open", () => {
      console.log("Connected (attempt", attempt + 1, ")");
      delay = 1000; // reset backoff on successful connection
      attempt = 0;
      // re-subscribe to all channels here
    });

    ws.on("message", onMessage);

    ws.on("close", () => {
      attempt++;
      const nextDelay = Math.min(delay * 2, 30_000);
      console.log(`Reconnecting in ${delay}ms...`);
      setTimeout(createConnection, delay);
      delay = nextDelay;
    });

    ws.on("error", (err) => console.error("WebSocket error:", err));
  }

  createConnection();
  return () => ws?.close();
}

const disconnect = connect(
  "wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY",
  (data) => {
    const msg = JSON.parse(data);
    console.log("Update:", msg);
  }
);
```

## Лимиты соединений

WebSocket-соединения разделяют тот же лимит на IP, что и gRPC-соединения. Подробности см. в разделе [Аутентификация и лимиты](/authentication#websocket).

## Смотрите также

<CardGroup cols={2}>
  <Card title="HTTP RPC API" icon="server" href="/rpc/http">
    Формат запросов JSON-RPC 2.0, пакетные запросы и все доступные методы.
  </Card>

  <Card title="Коды ошибок" icon="triangle-exclamation" href="/rpc/error-codes">
    HTTP-статусы, ошибки JSON-RPC и способы их обработки.
  </Card>
</CardGroup>
