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

# parsedTransactionSubscribe

> Subscribe to decoded Solana transactions matching a filter by program, account, and instruction name. Receive whole transactions with named arguments and accounts.

Start a subscription. Every confirmed transaction that matches your filter arrives as a `parsedTransactionNotification`, already decoded: every instruction with named arguments and named accounts, plus the fee, the full account key list, a transaction-level `summary`, and the SOL and token transfers.

## Endpoints

Parsed Streams is in closed beta. The Helius team whitelists your project id and shares the connection endpoint with you:

* `wss://<ENDPOINT>/?api-key=<API_KEY>`

## Authorizations

<ParamField query="api-key" type="string" required>
  Your Helius API key, passed as the `api-key` query parameter or the `x-api-key` header. A missing, invalid, or non-whitelisted key is rejected with HTTP 401.
</ParamField>

## Body

<ParamField body="params" type="array" required>
  <Expandable title="Filter" defaultOpen>
    At least one of `programs` or `accounts.include` is required. The fields you set combine with **AND**: an instruction must satisfy all of them to match.

    <ParamField body="programs" type="string[]">
      Program IDs to match (base58 addresses, not names). An instruction matches if its program is in this list. OR within the list.
    </ParamField>

    <ParamField body="instructionNames" type="string[]">
      Decoded instruction names, such as `route`. Matched exactly first, then with a case and separator insensitive fallback, so `sharedAccountsRoute` also matches the wire name `shared_accounts_route`. OR within the list. Only instructions whose name the catalog could identify can match, so take names from [describeProgram](/docs/api-reference/parsed-streams/describeprogram).
    </ParamField>

    <ParamField body="accounts.include" type="string[]">
      Account addresses. An instruction matches if any of these appears in its account list. OR within the list. Works for every instruction, decoded or not. The program id itself does not count as an account here.
    </ParamField>

    <ParamField body="accounts.roles" type="object">
      A map of decoded account role name to address, such as `{ "user_transfer_authority": "<pubkey>" }`. Every entry must hold (AND across entries), and the instruction must be decoded for this to apply. Role names match **exactly**, with no case folding, so copy them from [describeProgram](/docs/api-reference/parsed-streams/describeprogram) rather than guessing.
    </ParamField>

    <ParamField body="includeFailed" type="boolean" default="false">
      Include instructions from failed transactions.
    </ParamField>

    <ParamField body="includeCpi" type="boolean" default="true">
      Inner (CPI) instructions are eligible to match. Set `false` to match top-level instructions only.
    </ParamField>
  </Expandable>

  <Expandable title="Options">
    The second param is optional.

    <ParamField body="commitment" type="string" default="confirmed">
      Only `confirmed` is supported.
    </ParamField>

    <ParamField body="details" type="string" default="full">
      What each notification carries. `full`: the whole transaction, every instruction, plus `matchedIndexes` pointing at the filter hits. `matched`: only the instructions that matched, no index list. `raw`: matched instructions only, each reduced to its position, `programId`, and base58 `data` blob, with no decoded fields and no `accountKeys` array. Use `matched` when bandwidth matters more than context (full payloads average roughly three times the size), and `raw` when you decode instruction data yourself and only need the bytes.
    </ParamField>
  </Expandable>
</ParamField>

Unknown fields anywhere in the filter or options are rejected with `-32602` rather than silently ignored, so typos fail loudly instead of matching nothing.

## Response

<ResponseField name="result" type="integer">
  Subscription id (needed to unsubscribe)
</ResponseField>

<RequestExample>
  ```json Request theme={"system"}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "parsedTransactionSubscribe",
    "params": [
      {
        "programs": ["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"],
        "instructionNames": ["route", "shared_accounts_route"],
        "accounts": {
          "include": ["So11111111111111111111111111111111111111112"],
          "roles": { "user_transfer_authority": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" }
        },
        "includeFailed": false,
        "includeCpi": true
      },
      { "commitment": "confirmed", "details": "full" }
    ]
  }
  ```

  ```typescript TypeScript theme={"system"}
  import WebSocket from "ws";

  const ws = new WebSocket("wss://<ENDPOINT>/?api-key=<API_KEY>");

  ws.on("open", () => {
    ws.send(JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "parsedTransactionSubscribe",
      params: [{ programs: ["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"] }],
    }));
  });

  ws.on("message", (data) => {
    const msg = JSON.parse(data.toString());
    if (msg.method === "parsedTransactionNotification") {
      const { transaction, instructions, matchedIndexes } = msg.params.result.value;
      for (const i of matchedIndexes ?? instructions.keys()) {
        const ix = instructions[i];
        console.log(transaction.signature, ix.programName, ix.instructionName, ix.decoded?.args);
      }
    }
  });
  ```

  ```python Python theme={"system"}
  import asyncio, json, websockets

  URL = "wss://<ENDPOINT>/?api-key=<API_KEY>"

  async def main():
      async with websockets.connect(URL) as ws:
          await ws.send(json.dumps({
              "jsonrpc": "2.0", "id": 1, "method": "parsedTransactionSubscribe",
              "params": [{"programs": ["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"]}],
          }))
          async for raw in ws:
              msg = json.loads(raw)
              if msg.get("method") == "parsedTransactionNotification":
                  value = msg["params"]["result"]["value"]
                  for i in value.get("matchedIndexes") or range(len(value["instructions"])):
                      ix = value["instructions"][i]
                      print(ix.get("programName"), ix.get("instructionName"), (ix.get("decoded") or {}).get("args"))

  asyncio.run(main())
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={"system"}
  { "jsonrpc": "2.0", "id": 1, "result": 23 }
  ```

  ```json Notification theme={"system"}
  {
    "jsonrpc": "2.0",
    "method": "parsedTransactionNotification",
    "params": {
      "subscription": 23,
      "result": {
        "context": { "slot": 430172053 },
        "value": {
          "transaction": {
            "signature": "3riSYL4HTRxgQjLayt6L2JPaDR3oaEQg1H4v3fnjUxNU...",
            "slot": 430172053,
            "blockTime": null,
            "feePayer": "6jduWNCTQzG91JGBchfGGxd55Vi5FxJCCJEV18RkXzJX",
            "fee": 5000,
            "accountKeys": ["6jduWNCT...", "..."],
            "status": "ok",
            "error": null,
            "summary": {
              "type": "swap",
              "description": "6jduWNCTQzG91JGBchfGGxd55Vi5FxJCCJEV18RkXzJX swapped 0.001 SOL for 0.183985 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v via Jupiter",
              "parsedData": {
                "type": "swap",
                "protocol": "jupiter",
                "kind": "swap",
                "in_amount": "1000000",
                "actual_out_amount": "183985",
                "input_mint": "So11111111111111111111111111111111111111112",
                "output_mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
              }
            },
            "nativeTransfers": [
              { "fromUserAccount": "6jduWNCT...", "toUserAccount": "DfXygSm4...", "amount": 1000000 }
            ],
            "tokenTransfers": [
              {
                "fromUserAccount": "6jduWNCT...",
                "toUserAccount": "AeUfFU6L...",
                "fromTokenAccount": "HLaEoW1s...",
                "toTokenAccount": "G13P9kSY...",
                "rawTokenAmount": 183985,
                "decimals": 6,
                "tokenStandard": "Fungible",
                "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
              }
            ]
          },
          "instructions": [
            {
              "topIndex": 4,
              "innerIndex": null,
              "stackHeight": 1,
              "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
              "programName": "jupiter",
              "instructionName": "route",
              "summary": {
                "type": "swap",
                "description": "6jduWNCTQzG91JGBchfGGxd55Vi5FxJCCJEV18RkXzJX swapped 0.001 SOL for 0.183985 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v via Jupiter",
                "parsedData": {
                  "type": "swap",
                  "protocol": "jupiter",
                  "kind": "swap",
                  "in_amount": "1000000",
                  "actual_out_amount": "183985",
                  "input_mint": "So11111111111111111111111111111111111111112",
                  "output_mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
                }
              },
              "decoded": {
                "args": { "in_amount": "1000000", "slippage_bps": 50 },
                "accounts": [
                  { "name": "user_transfer_authority", "pubkey": "9xQe...", "isSigner": true, "isWritable": false }
                ]
              }
            }
          ],
          "matchedIndexes": [8, 13]
        }
      }
    }
  }
  ```
</ResponseExample>

## Notifications

One notification per matching transaction per subscription. Inside `params.result.value`:

* **`transaction`** — the full context: signature, slot, fee (lamports), the complete `accountKeys` list, `status`/`error`, a transaction-level `summary`, and the extracted `nativeTransfers` and `tokenTransfers`.
* **`instructions`** — every instruction in execution order, positioned by `topIndex`, `innerIndex`, and `stackHeight`. Decoded instructions carry named `decoded.args` and `decoded.accounts` (snake\_case, u64 values as strings); undecoded ones carry `rawData` and `rawAccounts` instead.
* **`matchedIndexes`** — indices into `instructions` telling you which ones your filter actually hit. With `details: "matched"` the array contains only the hits and `matchedIndexes` is absent; with `details: "raw"` each matched instruction shrinks to its position, `programId`, and base58 `data` blob.

For a field-by-field reading of the notification payload, see the [quickstart protocol reference](/docs/parsed-streams/quickstart#notifications).

## Managing Subscriptions

The `result` from the subscribe response is the same number that appears in `params.subscription` on every notification from that subscription. Store it — you need it to [unsubscribe](/docs/api-reference/parsed-streams/parsedtransactionunsubscribe).

A project may hold up to **100 concurrent connections**, shared across all of its API keys, with up to **25 subscriptions per connection**. See the [overview](/docs/api-reference/parsed-streams/overview#limits) for all limits.
