> ## 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.

# Comment utiliser transactionSubscribe

> Diffusez les mises à jour des transactions Solana en temps réel avec `transactionSubscribe`. Surveillez l'activité de la blockchain, filtrez par comptes et recevez des notifications instantanées.

## Qu'est-ce que `transactionSubscribe`?

La méthode WebSocket `transactionSubscribe` (une extension Helius de l'API WebSocket standard Solana) permet des événements de transaction en temps réel.

Pour l'utiliser, fournissez un `TransactionSubscribeFilter` et incluez éventuellement `TransactionSubscribeOptions` pour une personnalisation supplémentaire.

`transactionSubscribe` réside sur le même `wss://mainnet.helius-rpc.com` et `wss://devnet.helius-rpc.com` unifiés [endpoints](https://www.helius.dev/docs/api-reference/endpoints) que les méthodes d'abonnement standard de Solana.

### INLINE\_CODE\_PLACEHOLDER\_90586faa3b753\_END

* `vote` : indicateur booléen pour inclure/exclure les transactions liées au vote
* `failed` : indicateur booléen pour inclure/exclure les transactions qui ont échoué
* `signature` : filtre les mises à jour vers une transaction spécifique basée sur sa signature
* `accountInclude` : liste de comptes pour lesquels vous souhaitez recevoir des mises à jour de transaction. Un seul des comptes doit être inclus dans les mises à jour de transaction (par exemple, Compte 1 OU 2).
* `accountExclude` : liste de comptes que vous souhaitez exclure des mises à jour de transaction
* `accountRequired` : les transactions doivent inclure tous les comptes spécifiés pour être incluses dans les mises à jour (par exemple, Compte 1 ET 2)
* `tokenAccounts` : expansion optionnelle des comptes de jetons associés (ATA) (`balanceChanged`, `all`, ou `none`). Voir [Surveiller un portefeuille, y compris les transferts de jetons](#surveiller-un-portefeuille-y-compris-les-transferts-de-jetons) ci-dessous.

<Tip>
  Vous pouvez inclure jusqu'à 50 000 adresses dans les tableaux `accountInclude`, `accountExclude` et `accountRequired`.
</Tip>

### TransactionSubscribeOptions (optionnel)

* `commitment` : niveau d'engagement pour récupérer les données (`processed`, `confirmed`, ou `finalized`)
* `encoding` : format d'encodage des données retournées (`base58`, `base64`, ou `jsonParsed`)
* `transactionDetails` : niveau de détail pour les données retournées (`full`, `signatures`, `accounts` et `none`)
* `showRewards` : indicateur booléen indiquant si les données de récompense doivent être incluses dans les mises à jour
* `maxSupportedTransactionVersion` : spécifie la version la plus élevée des transactions dont vous souhaitez recevoir les mises à jour. Définissez la valeur sur `1` pour recevoir les transactions legacy, v0 et v1. Voir [Transaction v1 support](/docs/fr/rpc/transaction-v1).

<Info>
  `maxSupportedTransactionVersion` est requis pour retourner les comptes et les détails de niveau complet d'une transaction donnée (c'est-à-dire, `transactionDetails: "accounts" | "full"`).
</Info>

## Exemple d'abonnement à une transaction

Dans cet exemple, nous nous abonnons aux transactions contenant le compte Raydium `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`.

Lorsqu'une transaction contenant le compte `675k...1Mp8` dans le `accountKeys` de la transaction se produit, nous recevrons une notification WSS.

Sur la base des options d'abonnement, la notification de transaction sera envoyée au niveau d'engagement `processed`, encodage `jsonParsed`, détails de la transaction `full`, et affichera les récompenses.

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

### Exemple de notification

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

## Surveiller un portefeuille, y compris les transferts de jetons

Lorsque vous surveillez un portefeuille avec `accountInclude`, vous ne correspondez qu'aux transactions où la clé publique du portefeuille apparaît directement dans les clés de compte. Un cas commun passe inaperçu : lorsque quelqu'un envoie au portefeuille un jeton SPL (USDC, par exemple), le transfert touche le **compte de jetons associé (ATA)** du portefeuille, et non la clé publique du portefeuille — donc un abonnement en ligne `accountInclude: [wallet]` ne le voit jamais.

Définissez le champ `tokenAccounts` pour élargir la correspondance de sorte que le compte surveillé corresponde également aux transactions où il **détient** un solde de jeton :

* `balanceChanged` : correspondance lorsque le portefeuille détient un solde de jeton dont le montant a changé (ou dont le compte de jeton a été fermé) dans la transaction. Utilisez ceci pour "me dire quand l'argent a réellement bougé." C'est le choix le plus étroit, à faible volume et le plus courant.
* `all` : correspond à toute transaction référencée à un solde de jeton que le portefeuille détient, même si invariable. Volume plus élevé.
* `none` : pas d'expansion. Identique à l'omission du champ (par défaut).

La correspondance est basée sur le propriétaire : elle capture tout compte de jeton détenu par le portefeuille, y compris les non-canoniques, pas seulement l'adresse ATA dérivée. Une valeur invalide renvoie une erreur JSON-RPC `-32602`. Les abonnements qui omettent `tokenAccounts` se comportent exactement comme avant. Pour un aperçu complet du fonctionnement de l'expansion ATA, voir [Filtrage des comptes de jetons (ATA) sur WebSocket](/docs/fr/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);
});
```

## Surveiller les nouveaux Jupiter DCAs

Jupiter DCA, ou Dollar Cost Averaging, est un moyen de programmer des transactions récurrentes sur Solana. Étant donné que ces ordres d'achat/vente programmés sont enregistrés sur la chaîne, les traders peuvent utiliser la méthode `transactionSubscribe` et [`getAsset`](/docs/fr/api-reference/das/getasset) pour écouter les nouveaux ordres.

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

### Exemple de notification

<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="Tableaux du terminal des nouveaux ordres Jupiter DCA montrant le portefeuille utilisateur, la paire de jetons, le temps d'ouverture, l'entrée totale, le montant par cycle, et l'intervalle" width="566" height="622" data-path="images/enhanced-websockets-example-1.png" />
</Frame>

## Surveiller les nouveaux tokens 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>

### Exemple de notification

<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="Tableaux du terminal des nouveaux tokens pump.fun créés montrant la signature de la transaction, le portefeuille du créateur et l'adresse de frappe du jeton" width="738" height="355" data-path="images/enhanced-websockets-example-2.png" />
</Frame>

## Gestion des abonnements

### Identifiants d'abonnement

Lorsque `transactionSubscribe` réussit, le serveur renvoie un identifiant d'abonnement dans le champ `result`. C'est le même numéro qui apparaît dans `params.subscription` à chaque notification de cet abonnement :

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

Stockez l'identifiant d'abonnement de la réponse. Vous en avez besoin pour vous désabonner.

### Désabonnement

Pour arrêter de recevoir des notifications, appelez `transactionUnsubscribe` avec l'identifiant d'abonnement. Chaque appel `transactionSubscribe` sur la même connexion crée un abonnement distinct avec son propre identifiant, alors assurez-vous de vous désabonner avant de vous réabonner pour éviter de recevoir des notifications en double.

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

Dans cet exemple, nous nous abonnons aux transactions Raydium, capturons l'identifiant d'abonnement de la réponse du serveur, puis nous nous désabonnons en utilisant cet identifiant. Quelques messages en cours peuvent encore arriver brièvement après l'appel à `transactionUnsubscribe`. C'est un comportement attendu.

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