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

# Как использовать transactionSubscribe

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

## Что такое `transactionSubscribe`?

Метод WebSocket `transactionSubscribe` (расширение Helius для стандартного WebSocket API Solana) позволяет получать события транзакций в реальном времени.

Чтобы использовать его, укажите `TransactionSubscribeFilter` и при необходимости добавьте `TransactionSubscribeOptions` для дополнительной настройки.

`transactionSubscribe` доступен на тех же унифицированных [конечных точках](https://www.helius.dev/docs/api-reference/endpoints) `wss://mainnet.helius-rpc.com` и `wss://devnet.helius-rpc.com`, что и стандартные методы подписки Solana.

### `TransactionSubscribeFilter`

* `vote`: логический флаг для включения или исключения транзакций, связанных с голосованием
* `failed`: логический флаг для включения или исключения неуспешных транзакций
* `signature`: фильтрует обновления для конкретной транзакции по ее подписи
* `accountInclude`: список аккаунтов, для которых вы хотите получать обновления транзакций. В обновлениях транзакций должен присутствовать хотя бы один из аккаунтов (например, аккаунт 1 ИЛИ 2).
* `accountExclude`: список аккаунтов, которые вы хотите исключить из обновлений транзакций
* `accountRequired`: транзакции должны включать все указанные аккаунты, чтобы попасть в обновления (например, аккаунт 1 И 2)
* `tokenAccounts`: включаемое расширение связанного аккаунта токена (ATA) (`balanceChanged`, `all` или `none`). См. раздел [Отслеживание кошелька, включая переводы токенов](#отслеживание-кошелька-включая-переводы-токенов) ниже.

<Tip>
  В массивы `accountInclude`, `accountExclude` и `accountRequired` можно добавить до 50 000 адресов.
</Tip>

### TransactionSubscribeOptions (необязательно)

* `commitment`: уровень подтверждения для получения данных (`processed`, `confirmed` или `finalized`)
* `encoding`: формат кодирования возвращаемых данных (`base58`, `base64` или `jsonParsed`)
* `transactionDetails`: уровень детализации возвращаемых данных (`full`, `signatures`, `accounts` и `none`)
* `showRewards`: логический флаг, указывающий, следует ли включать данные о вознаграждениях в обновления
* `maxSupportedTransactionVersion`: задает максимальную версию транзакций, для которых вы хотите получать обновления. Установите значение `1`, чтобы получать транзакции устаревшего формата, v0 и v1. См. раздел [Поддержка транзакций v1](/docs/ru/rpc/transaction-v1).

<Info>
  `maxSupportedTransactionVersion` необходим для возврата аккаунтов и полной информации о заданной транзакции (то есть `transactionDetails: "accounts" | "full"`).
</Info>

## Пример подписки на транзакции

В этом примере мы подписываемся на транзакции, содержащие аккаунт Raydium `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`.

Когда происходит транзакция, содержащая аккаунт `675k...1Mp8` в `accountKeys` транзакции, мы получаем уведомление WSS.

Согласно параметрам подписки, уведомление о транзакции будет отправлено с уровнем подтверждения `processed`, кодированием `jsonParsed` и уровнем детализации транзакции `full`, а также будет содержать вознаграждения.

<CodeGroup>
  ```javascript theme={"system"}
  const WebSocket = require('ws');

  // Create a WebSocket connection
  const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');

  // Function to send a request to the WebSocket server
  function sendRequest(ws) {
      const request = {
          jsonrpc: "2.0",
          id: 420,
          method: "transactionSubscribe",
          params: [
              {
                  accountInclude: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"]
              },
              {
                  commitment: "processed",
                  encoding: "jsonParsed",
                  transactionDetails: "full",
                  showRewards: true,
                  maxSupportedTransactionVersion: 1
              }
          ]
      };
      ws.send(JSON.stringify(request));
  }

  // Function to send a ping to the WebSocket server
  function startPing(ws) {
      setInterval(() => {
          if (ws.readyState === WebSocket.OPEN) {
              ws.ping();
              console.log('Ping sent');
          }
      }, 30000); // Ping every 30 seconds
  }

  // Define WebSocket event handlers

  ws.on('open', function open() {
      console.log('WebSocket is open');
      sendRequest(ws);  // Send a request once the WebSocket is open
      startPing(ws);    // Start sending pings
  });

  ws.on('message', function incoming(data) {
      const messageStr = data.toString('utf8');
      try {
          const messageObj = JSON.parse(messageStr);
          console.log('Received:', messageObj);
      } catch (e) {
          console.error('Failed to parse JSON:', e);
      }
  });

  ws.on('error', function error(err) {
      console.error('WebSocket error:', err);
  });

  ws.on('close', function close() {
      console.log('WebSocket is closed');
  });
  ```
</CodeGroup>

### Пример уведомления

<CodeGroup>
  ```json theme={"system"}
  {
      "jsonrpc": "2.0",
      "method": "transactionNotification",
      "params": {
          "subscription": 4743323479349712,
          "result": {
              "transaction": {
                  "transaction": [
                      "Ae6zfSExLsJ/E1+q0jI+3ueAtSoW+6HnuDohmuFwagUo2BU4OpkSdUKYNI1dJfMOonWvjaumf4Vv1ghn9f3Avg0BAAEDGycH0OcYRpfnPNuu0DBQxTYPWpmwHdXPjb8y2P200JgK3hGiC2JyC9qjTd2lrug7O4cvSRUVWgwohbbefNgKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0HcpwKokfYDDAJTaF/TWRFWm0Gz5/me17PRnnywHurMBAgIAAQwCAAAAoIYBAAAAAAA=",
                      "base64"
                  ],
                  "meta": {
                      "err": null,
                      "status": {
                          "Ok": null
                      },
                      "fee": 5000,
                      "preBalances": [
                          28279852264,
                          158122684,
                          1
                      ],
                      "postBalances": [
                          28279747264,
                          158222684,
                          1
                      ],
                      "innerInstructions": [],
                      "logMessages": [
                          "Program 11111111111111111111111111111111 invoke [1]",
                          "Program 11111111111111111111111111111111 success"
                      ],
                      "preTokenBalances": [],
                      "postTokenBalances": [],
                      "rewards": null,
                      "loadedAddresses": {
                          "writable": [],
                          "readonly": []
                      },
                      "computeUnitsConsumed": 0
                  }
              },
              "signature": "5moMXe6VW7L7aQZskcAkKGQ1y19qqUT1teQKBNAAmipzdxdqVLAdG47WrsByFYNJSAGa9TByv15oygnqYvP6Hn2p",
              "slot": 224341380,
              "transactionIndex": 42
          }
      }
  }
  ```
</CodeGroup>

## Отслеживание кошелька, включая переводы токенов

При отслеживании кошелька с помощью `accountInclude` учитываются только транзакции, в которых публичный ключ кошелька непосредственно присутствует среди ключей аккаунтов. Один распространенный случай остается незамеченным: когда кто-либо отправляет на кошелек токен SPL (например, USDC), перевод затрагивает **связанный аккаунт токена (ATA)** кошелька, а не публичный ключ кошелька, поэтому обычная подписка `accountInclude: [wallet]` его не обнаруживает.

Задайте поле `tokenAccounts`, чтобы расширить условия сопоставления: отслеживаемый аккаунт также будет соответствовать транзакциям, в которых он **владеет** балансом токена:

* `balanceChanged`: сопоставлять, если кошелек владеет балансом токена, сумма которого изменилась в транзакции (или аккаунт токена был закрыт). Используйте этот вариант, чтобы узнавать, когда средства действительно перемещаются. Это наиболее узкий, распространенный вариант с наименьшим объемом данных.
* `all`: сопоставлять любую транзакцию, ссылающуюся на принадлежащий кошельку баланс токена, даже если он не изменился. Объем данных выше.
* `none`: без расширения. Аналогично отсутствию поля (значение по умолчанию).

Сопоставление выполняется по владельцу: оно охватывает все принадлежащие кошельку аккаунты токенов, включая неканонические, а не только производный адрес ATA. Недопустимое значение приводит к ошибке JSON-RPC `-32602`. Подписки без `tokenAccounts` работают точно так же, как и раньше. Полное описание расширения ATA см. в разделе [Фильтрация аккаунтов токенов (ATA) через WebSocket](/docs/ru/rpc/websocket/token-account-filtering).

```javascript theme={"system"}
const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'transactionSubscribe',
    params: [
      {
        accountInclude: ['<WALLET_PUBKEY>'],
        tokenAccounts: 'balanceChanged' // also match the wallet's ATAs
      },
      { commitment: 'confirmed', encoding: 'jsonParsed', maxSupportedTransactionVersion: 1 }
    ]
  }));
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data) => {
  const msg = JSON.parse(data.toString());
  const result = msg.params?.result;
  if (!result) return;
  // Token balances this wallet owns that changed in the tx
  const owned = (result.transaction.meta.postTokenBalances || [])
    .filter((b) => b.owner === '<WALLET_PUBKEY>');
  console.log(result.signature, owned);
});
```

## Мониторинг новых DCA Jupiter

DCA Jupiter, или усреднение долларовой стоимости, — это способ запланировать повторяющиеся сделки в Solana. Поскольку такие запланированные ордера на покупку и продажу записываются в блокчейне, трейдеры могут использовать метод `transactionSubscribe` и [`getAsset`](/docs/ru/api-reference/das/getasset), чтобы отслеживать новые ордера.

<CodeGroup>
  ```javascript theme={"system"}
  const WebSocket = require('ws');   
  const bs58      = require('bs58').default;

  /* ───────────────────── 1.  CONFIG ──────────────────────────── */
  const API_KEY   = process.env.HELIUS_API_KEY || (() => { throw new Error('Set HELIUS_API_KEY'); })();
  const HELIUS_WS  = `wss://mainnet.helius-rpc.com?api-key=${API_KEY}`;
  const HELIUS_RPC = `https://mainnet.helius-rpc.com/?api-key=${API_KEY}`;
  const DCA_PROGRAM_ID = 'DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M';

  /* ───────────────────── 2.  BINARY DECODER ──────────────────── */
  function decodeOpenDcaV2(base58Data) {
    const buf = Buffer.from(bs58.decode(base58Data));
    return {
      appIdx:    buf.readBigUInt64LE(8), // Application Index
      inAmount:  buf.readBigUInt64LE(16), // Input Amount
      perCycle:  buf.readBigUInt64LE(24), // Per Cycle
      interval:  buf.readBigUInt64LE(32) // Interval
    };
  }

  const TOKEN_META = new Map();   // mint → { symbol, decimals }
  /**
   * Fetch symbol & decimals for a mint once then cache.
   * Uses Helius getAsset DAS method: https://www.helius.dev/docs/api-reference/das/getasset
   */
  async function getMeta(mint) {
    if (TOKEN_META.has(mint)) return TOKEN_META.get(mint);

    const body = {
      jsonrpc: '2.0',
      id:      'meow',
      method:  'getAsset',
      params:  { id: mint, displayOptions: { showFungible: true } }
    };

    const { result } = await fetch(HELIUS_RPC, {
      method:  'POST',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify(body)
    }).then(r => r.json());

    const tokenInfo = result.token_info || {};
    const metadata = { symbol: tokenInfo.symbol || '?', decimals: tokenInfo.decimals ?? 0 };
    TOKEN_META.set(mint, metadata);
    return metadata;
  }

  /* ───────────────────── 4.  PRETTY HELPERS ──────────────────── */
  function formatTimestamp(unixSeconds) {
      return new Date(Number(unixSeconds) * 1_000)
               .toISOString()
               .replace('T', ' ')
               .replace('.000Z', ' UTC');
  }
  function formatInterval(seconds) {
      if (seconds % 86_400 === 0) return `every ${seconds / 86_400}d`;
      if (seconds %  3_600 === 0) return `every ${seconds /  3_600}h`;
      if (seconds %     60 === 0) return `every ${seconds /     60}m`;
      return `every ${seconds}s`;
    }

    function formatAmount(raw, decimals, symbol) {
      const ui = Number(raw) / 10 ** decimals;
      return `${ui} ${symbol}`;
    }
  /* ───────────────────── 5.  WEBSOCKET SETUP ─────────────────── */
  const ws = new WebSocket(HELIUS_WS);

  ws.on('open', () => {
    ws.send(JSON.stringify({
      jsonrpc: '2.0',
      id:      1,
      method:  'transactionSubscribe',
      params: [
        { failed: false, accountInclude: [DCA_PROGRAM_ID] },
        {
          commitment: 'confirmed',
          encoding:   'jsonParsed',
          transactionDetails: 'full',
          maxSupportedTransactionVersion: 1
        }
      ]
    }));

    setInterval(() => ws.ping(), 10_000);
  });

  /* ───────────────────── 6.  MAIN MESSAGE HANDLER ────────────── */
  ws.on('message', async raw => {
    const payload = JSON.parse(raw);
    const result  = payload.params?.result;
    if (!result) return;

    // Look for the `OpenDcaV2` log message
    const logs = result.transaction.meta.logMessages || [];
    if (!logs.some(l => l.includes('OpenDcaV2'))) return;

    // loop through all instructions in the transaction to find the DCA instruction
    for (const ix of result.transaction.transaction.message.instructions) {
      if (ix.programId !== DCA_PROGRAM_ID) continue;

      try {
        // 1) decode binary payload
        const d = decodeOpenDcaV2(ix.data);

        // 2) fetch token symbols / decimals (cached)
        const [inMeta, outMeta] = await Promise.all([
          getMeta(ix.accounts[3]),   // input mint
          getMeta(ix.accounts[4])    // output mint
        ]);

        // 3) create a nice looking table
        console.table({
          user:        ix.accounts[2],
          pair:        `${inMeta.symbol} → ${outMeta.symbol}`,
          opened:      formatTimestamp(d.appIdx),
          'total in':  formatAmount(d.inAmount,  inMeta.decimals, inMeta.symbol),
          'per cycle': formatAmount(d.perCycle,  inMeta.decimals, inMeta.symbol),
          interval:    formatInterval(Number(d.interval))
        });
      } catch (e) {}
    }
  });

  ws.on('error', console.error);

  ws.on('close', () => process.exit(1));
  ```
</CodeGroup>

### Пример уведомления

<Frame>
  <img src="https://mintcdn.com/helius/RGuN9Tphu9J_7kRM/images/enhanced-websockets-example-1.png?fit=max&auto=format&n=RGuN9Tphu9J_7kRM&q=85&s=0cbc0eb2c0eecf83b37217011cb9e3c7" alt="Terminal tables of new Jupiter DCA orders showing the user wallet, token pair, open time, total input, amount per cycle, and interval" width="566" height="622" data-path="images/enhanced-websockets-example-1.png" />
</Frame>

## Мониторинг новых токенов pump.fun

<CodeGroup>
  ```javascript theme={"system"}
  const WebSocket = require('ws');

  const KEY    = process.env.HELIUS_API_KEY ?? (() => { throw new Error('Set HELIUS_API_KEY'); })();
  const WS_URL = `wss://mainnet.helius-rpc.com?api-key=${KEY}`;
  const PUMP_FUN_PROG = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P';

  /* ────────── 2.  OPEN WEBSOCKET & SUBSCRIBE ──────────────────── */
  const ws = new WebSocket(WS_URL);

  ws.on('open', () => {
    ws.send(JSON.stringify({
      jsonrpc : '2.0',
      id      : 1,
      method  : 'transactionSubscribe',
      params  : [
        { failed:false, accountInclude:[PUMP_FUN_PROG] },
        { commitment:'confirmed', encoding:'jsonParsed',
          transactionDetails:'full', maxSupportedTransactionVersion:1 }
      ]
    }));
    // ping every 10 s so we don't get dropped
    setInterval(() => ws.ping(), 10_000);
  });

  /* ────────── 3.  MESSAGE HANDLER ─────────────────────────────── */
  ws.on('message', raw => {
    const payload = JSON.parse(raw);
    const result  = payload.params?.result;
    if (!result) return;

    const logs = result.transaction.meta.logMessages || [];
    // filter for the pump.fun "InitializeMint2" log
    if (!logs.some(l => l.includes('Instruction: InitializeMint2'))) return;

    const sig   = result.signature;    // transaction signature
    const keys  = result.transaction.transaction.message.accountKeys
                               .map(k => k.pubkey);
    //   keys[0] → creator wallet
    //   keys[1] → the new token
    console.table({
      tx:      sig,
      creator: keys[0],
      token:   keys[1]
    });
  });

  ws.on('error', console.error);
  ws.on('close', () => process.exit(1));  
  ```
</CodeGroup>

### Пример уведомления

<Frame>
  <img src="https://mintcdn.com/helius/RGuN9Tphu9J_7kRM/images/enhanced-websockets-example-2.png?fit=max&auto=format&n=RGuN9Tphu9J_7kRM&q=85&s=8febc28503381b0da3cd0f1bb40459cb" alt="Terminal tables of newly created pump.fun tokens showing the transaction signature, creator wallet, and token mint address" width="738" height="355" data-path="images/enhanced-websockets-example-2.png" />
</Frame>

## Управление подписками

### Идентификаторы подписок

При успешном вызове `transactionSubscribe` сервер возвращает идентификатор подписки в поле `result`. Это то же число, которое отображается в `params.subscription` каждого уведомления этой подписки:

<CodeGroup>
  ```json Subscribe Response theme={"system"}
  {
    "jsonrpc": "2.0",
    "result": 4743323479349712,
    "id": 420
  }
  ```

  ```json Notification theme={"system"}
  {
    "jsonrpc": "2.0",
    "method": "transactionNotification",
    "params": {
      "subscription": 4743323479349712,
      "result": {}
    }
  }
  ```
</CodeGroup>

Сохраните идентификатор подписки из ответа. Он понадобится для отмены подписки.

### Отмена подписки

Чтобы прекратить получать уведомления, вызовите `transactionUnsubscribe` с идентификатором подписки. Каждый вызов `transactionSubscribe` в рамках одного подключения создает отдельную подписку с собственным идентификатором. Поэтому перед повторной подпиской обязательно отмените предыдущую, чтобы не получать дублирующиеся уведомления.

<CodeGroup>
  ```json Request theme={"system"}
  {
    "jsonrpc": "2.0",
    "id": 421,
    "method": "transactionUnsubscribe",
    "params": [4743323479349712]
  }
  ```

  ```json Response theme={"system"}
  {
    "jsonrpc": "2.0",
    "result": true,
    "id": 421
  }
  ```
</CodeGroup>

В этом примере мы подписываемся на транзакции Raydium, получаем идентификатор подписки из ответа сервера, а затем отменяем подписку с помощью этого идентификатора. В течение короткого времени после вызова `transactionUnsubscribe` могут поступать уже отправленные сообщения. Это ожидаемое поведение.

<CodeGroup>
  ```javascript theme={"system"}
  const WebSocket = require('ws');

  const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');
  let subscriptionId = null;

  ws.on('open', () => {
      ws.send(JSON.stringify({
          jsonrpc: '2.0',
          id: 420,
          method: 'transactionSubscribe',
          params: [
              { accountInclude: ['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'] },
              {
                  commitment: 'processed',
                  encoding: 'jsonParsed',
                  transactionDetails: 'full',
                  maxSupportedTransactionVersion: 1,
              },
          ],
      }));
      setInterval(() => ws.ping(), 30000);
  });

  ws.on('message', (data) => {
      const msg = JSON.parse(data.toString());

      // Capture the subscription ID from the subscribe response
      if (msg.id === 420 && msg.result !== undefined) {
          subscriptionId = msg.result;
          console.log('Subscribed, ID:', subscriptionId);
          return;
      }

      // Handle transaction notifications
      if (msg.method === 'transactionNotification') {
          console.log('Received:', msg.params.result.signature);
      }
  });

  function unsubscribe() {
      if (subscriptionId !== null) {
          ws.send(JSON.stringify({
              jsonrpc: '2.0',
              id: 421,
              method: 'transactionUnsubscribe',
              params: [subscriptionId],
          }));
          subscriptionId = null;
      }
  }
  ```
</CodeGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.