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

# Inicio rápido de Parsed Streams

> Conéctate a Parsed Streams, envía tu primer filtro y lee una notificación decodificada. Además, consulta la referencia completa del protocolo JSON-RPC 2.0.

<Tip>
  ¿Es tu primera vez con Parsed Streams? Lee primero [el modelo mental](/docs/es/parsed-streams#el-modelo-mental). Explica por qué los filtros tienen esa estructura.
</Tip>

## Inicio rápido

<Steps>
  <Step title="Get Access">
    Parsed Streams está en beta abierta y disponible en los planes de pago. Obtén tu clave de API en el [panel de Helius](https://dashboard.helius.dev) y conéctate al endpoint beta en `wss://fs-beta.helius-rpc.com`.

    Autentícate con la clave de API de tu proyecto. Pásala como parámetro de consulta `api-key` o como encabezado `x-api-key`.
  </Step>

  <Step title="Connect">
    ```bash wscat theme={"system"}
    wscat -c "wss://fs-beta.helius-rpc.com/?api-key=YOUR_API_KEY"
    ```

    Si falta la clave o no es válida, la solicitud se rechaza con HTTP 401. Si un proyecto alcanza su límite de conexiones, recibe HTTP 429.
  </Step>

  <Step title="Subscribe with a Filter">
    Envía `parsedTransactionSubscribe` con un filtro y opciones opcionales:

    ```json theme={"system"}
    {"jsonrpc":"2.0","id":1,"method":"parsedTransactionSubscribe","params":[{"programs":["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"]}]}
    ```

    El campo `result` de la respuesta es un **id de suscripción** entero:

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

  <Step title="Read a Notification">
    Cada transacción coincidente llega como `parsedTransactionNotification`, ya decodificada, con `matchedIndexes` apuntando a las instrucciones que coincidieron con tu filtro. Consulta [Notificaciones](#notificaciones) para ver la estructura completa.
  </Step>

  <Step title="Unsubscribe">
    ```json theme={"system"}
    { "jsonrpc": "2.0", "id": 2, "method": "parsedTransactionUnsubscribe", "params": [23] }
    ```

    O simplemente cierra la conexión. Esto elimina todas sus suscripciones.
  </Step>
</Steps>

## Guías

<CardGroup cols={2}>
  <Card title="Track Jupiter Swaps" icon="arrow-right-arrow-left" href="/docs/es/parsed-streams/guides/track-jupiter-swaps">
    Usa `describeProgram` para crear un filtro confiable antes de suscribirte.
  </Card>

  <Card title="Track Pump.fun Mints" icon="rocket" href="/docs/es/parsed-streams/guides/track-pumpfun-mints">
    Un listener seguro frente a reconexiones que registra cada nuevo despliegue de tokens de Pump.fun.
  </Card>

  <Card title="Handling Reconnects" icon="rotate" href="/docs/es/parsed-streams/guides/handling-reconnects">
    Supera los tiempos de espera por inactividad y los despliegues. Después, recupera exactamente lo que te perdiste.
  </Card>
</CardGroup>

## Referencia del protocolo

Parsed Streams usa **JSON-RPC 2.0** mediante una única conexión WebSocket. Cada solicitud recibe una respuesta con el mismo `id`. Después, una suscripción envía mensajes `parsedTransactionNotification` hasta que canceles la suscripción o te desconectes.

| Método                         | Propósito                                                                    |
| ------------------------------ | ---------------------------------------------------------------------------- |
| `parsedTransactionSubscribe`   | Iniciar una suscripción con un filtro                                        |
| `parsedTransactionUnsubscribe` | Detener una suscripción                                                      |
| `ping`                         | Comprobar la disponibilidad; devuelve el slot actual                         |
| `describeProgram`              | Enumerar las instrucciones, los eventos y los roles de cuenta de un programa |

### Suscribirse

Envía `parsedTransactionSubscribe` con un filtro y opciones opcionales. El campo `result` de la respuesta es un **id de suscripción** entero.

```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" }
  ]
}
```

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

#### Campos del filtro

Se requiere al menos uno de `programs` o `accounts.include`. Los campos que configures se combinan con **AND**: una instrucción debe satisfacerlos todos para coincidir.

<ParamField body="programs" type="string[]">
  IDs de programa que deben coincidir (direcciones base58, no nombres). Una instrucción coincide si su programa está en esta lista. Se aplica OR dentro de la lista.
</ParamField>

<ParamField body="instructionNames" type="string[]">
  Nombres de instrucciones decodificadas, como `route`. Primero se busca una coincidencia exacta y, luego, se usa una alternativa que no distingue mayúsculas, minúsculas ni separadores. Por lo tanto, `sharedAccountsRoute` también coincide con el nombre en el protocolo `shared_accounts_route`. Se aplica OR dentro de la lista. Solo pueden coincidir las instrucciones cuyo nombre haya identificado el catálogo. Por eso, obtén los nombres de `describeProgram`.
</ParamField>

<ParamField body="accounts.include" type="string[]">
  Direcciones de cuentas. Una instrucción coincide si alguna de estas aparece en su lista de cuentas. Se aplica OR dentro de la lista. Funciona con todas las instrucciones, estén decodificadas o no. Aquí, el id del programa no cuenta como una cuenta.
</ParamField>

<ParamField body="accounts.roles" type="object">
  Un mapa que relaciona el nombre del rol de una cuenta decodificada con una dirección, como `{ "user_transfer_authority": "<pubkey>" }`. Cada entrada debe cumplirse (AND entre entradas) y la instrucción debe estar decodificada para que esto se aplique. Los nombres de roles coinciden **exactamente**, sin normalizar mayúsculas y minúsculas. Cópialos de `describeProgram` en lugar de adivinarlos.
</ParamField>

<ParamField body="includeFailed" type="boolean" default="false">
  Incluye instrucciones de transacciones fallidas.
</ParamField>

<ParamField body="includeCpi" type="boolean" default="true">
  Las instrucciones internas (CPI) pueden coincidir. Configura `false` para que solo coincidan las instrucciones de nivel superior.
</ParamField>

Los campos desconocidos en cualquier parte del filtro o de las opciones se rechazan con `-32602` en lugar de ignorarse silenciosamente. Así, los errores tipográficos generan un error explícito en vez de no producir coincidencias.

#### Opciones

El segundo parámetro es opcional.

<ParamField body="commitment" type="string" default="confirmed">
  Solo se admite `confirmed`.
</ParamField>

<ParamField body="details" type="string" default="full">
  Define qué contiene cada notificación. `full`: la transacción completa, todas las instrucciones y `matchedIndexes`, que apunta a las coincidencias del filtro. `matched`: solo las instrucciones coincidentes, sin lista de índices. `raw`: solo las instrucciones coincidentes, cada una reducida a su posición, `programId` y un blob `data` en base58, sin campos decodificados ni array `accountKeys`. Usa `matched` cuando el ancho de banda sea más importante que el contexto (los payloads completos tienen, en promedio, aproximadamente el triple de tamaño). Usa `raw` cuando decodifiques tú mismo los datos de las instrucciones y solo necesites los bytes.
</ParamField>

Un proyecto puede mantener hasta **100 conexiones simultáneas**, compartidas entre todas sus claves de API.

### Notificaciones

Se envía una notificación por cada transacción coincidente y por suscripción. Con el valor predeterminado `details: "full"`:

```json 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]
      }
    }
  }
}
```

Cómo interpretarla:

* **`transaction`** contiene el contexto completo. `fee` está expresado en lamports. `accountKeys` es la lista completa de claves, incluidas las cargadas desde tablas de consulta de direcciones, en el mismo orden en que las informa la cadena. `feePayer` siempre es `accountKeys[0]`. `error` contiene el error de la transacción como JSON estructurado, por ejemplo, `{"InstructionError": [2, {"Custom": 6001}]}`, cuando `status` es `"error"`.
* **`summary`** tiene la misma estructura en todos los lugares donde aparece: un `type` (como `swap` o `transfer`), un `description` legible y un payload `parsedData` estructurado cuando el analizador reconoce la acción. Para un swap, incluye el protocolo, las cantidades y los mints. `transaction.summary` etiqueta la acción principal de la transacción. Cada instrucción reconocida contiene su propio `summary` con la misma estructura. Para recopilar todos los swaps de una transacción, recorre `instructions` y lee `summary.parsedData` cuando `summary.type` sea `"swap"`.
* **`nativeTransfers`** y **`tokenTransfers`** enumeran los movimientos de SOL y tokens que el analizador extrajo de toda la transacción. Tienen la misma estructura que devuelve la API de Parsed Events, por lo que los consumidores del stream y de la API pueden compartir código de procesamiento. Ambos siempre están presentes, aunque pueden estar vacíos.
* **`instructions`** contiene todas las instrucciones de la transacción en orden de ejecución: cada instrucción de nivel superior seguida de sus instrucciones internas. Cada entrada incluye su propia posición: `topIndex` indica a qué instrucción de nivel superior pertenece (comenzando en 0), `innerIndex` indica su posición entre las llamadas internas de esa instrucción (`null` significa que es la propia instrucción de nivel superior) e `stackHeight` indica la profundidad de la llamada (1 para el nivel superior). Usa estos valores, no la posición en el array.
* **`matchedIndexes`** contiene índices de `instructions` que indican cuáles coincidieron realmente con tu filtro. El resto se incluye como contexto. Con `details: "matched"`, el array solo contiene las coincidencias y `matchedIndexes` no está presente.
* **Los nombres de `decoded` usan snake\_case** (`in_amount`, `user_transfer_authority`), tal como se publican en la IDL del programa. Los argumentos enteros suelen ser strings (`"1000000"`), ya que los valores u64 no caben en los números de JavaScript.
* **`blockTime`** actualmente siempre es `null`. No dependas de este campo.
* En una misma transacción, puede haber una **combinación de instrucciones decodificadas y sin decodificar**: un swap completamente decodificado puede aparecer junto a un memo no reconocido. Bifurca según `decoded`. Cuando sea `null`, la instrucción contendrá `rawData` (bytes en base58) e `rawAccounts` (lista simple de claves públicas), por lo que siempre tendrás datos con los que trabajar.

Con `details: "raw"`, `value` se reduce a los metadatos y blobs de la transacción. `accountKeys`, `nativeTransfers`, `tokenTransfers`, `matchedIndexes` y todos los campos decodificados desaparecen (el `summary` de la transacción sigue incluido). Cada instrucción coincidente contiene su posición, su programa y sus bytes `data` en base58, exactamente como aparecen en la cadena. Esto también se aplica a las instrucciones que el catálogo podría haber decodificado:

```json theme={"system"}
"value": {
  "transaction": {
    "signature": "3riSYL4HTRxgQjLayt6L2JPaDR3oaEQg1H4v3fnjUxNU...",
    "slot": 430172053,
    "blockTime": null,
    "feePayer": "6jduWNCTQzG91JGBchfGGxd55Vi5FxJCCJEV18RkXzJX",
    "fee": 5000,
    "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"
      }
    }
  },
  "instructions": [
    { "topIndex": 4, "innerIndex": null, "stackHeight": 1, "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4", "data": "3Bxs4h24hBtQy9rw" }
  ]
}
```

### Cancelar la suscripción

```json theme={"system"}
{ "jsonrpc": "2.0", "id": 2, "method": "parsedTransactionUnsubscribe", "params": [23] }
```

Devuelve `true` si la suscripción existía y te pertenecía. Las notificaciones se detienen de inmediato. Al cerrar la conexión, se eliminan todas sus suscripciones.

### Descubrimiento

El error más común con este tipo de API es usar un filtro válido que no coincide con nada, normalmente porque se adivinó el nombre de una instrucción o de un rol. `describeProgram` evita ese problema al devolver los nombres exactos que usa el comparador:

```json Request theme={"system"}
{ "jsonrpc": "2.0", "id": 1, "method": "describeProgram", "params": [{ "program": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4" }] }
```

```json Response theme={"system"}
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "id": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
    "name": "jupiter",
    "instructions": ["route", "shared_accounts_route", "exact_out_route"],
    "events": ["SwapEvent"],
    "roles": ["user_transfer_authority", "destination_token_account"]
  }
}
```

Puedes pasar la dirección de un programa o un nombre del catálogo, pero **es preferible usar la dirección**. Los nombres pueden ser ambiguos entre versiones del programa (más de una entrada del catálogo se llama `jupiter` y una búsqueda por nombre puede devolver la versión más antigua). Si buscas por nombre, comprueba que `result.id` sea el programa al que quieres suscribirte.

Flujo recomendado: usa `describeProgram` para obtener los nombres exactos de las instrucciones y los roles, crea el filtro con esos nombres y, luego, suscríbete. La guía [Rastrear swaps de Jupiter](/docs/es/parsed-streams/guides/track-jupiter-swaps) explica todo el proceso de principio a fin.

### Límites

| Límite                              | Valor                                               |
| ----------------------------------- | --------------------------------------------------- |
| Conexiones simultáneas por proyecto | 100                                                 |
| Suscripciones por conexión          | 25                                                  |
| Mensajes del cliente                | 10 por segundo, ráfaga de 20                        |
| Tamaño de los mensajes del cliente  | 64 KiB                                              |
| `programs` por filtro               | 10                                                  |
| `instructionNames` por filtro       | 50, cada uno de hasta 64 caracteres                 |
| `accounts.include` por filtro       | 100                                                 |
| `accounts.roles` por filtro         | 20, cada nombre de hasta 64 caracteres              |
| Búfer de salida por conexión        | 2048 notificaciones; después, se cierra la conexión |

### Errores

Los errores siguen JSON-RPC 2.0: `{ "error": { "code": <int>, "message": "<text>" }, "id": <id> }`. Los mensajes indican exactamente qué salió mal y dónde.

| Código   | Significado                                                                                                      |
| -------- | ---------------------------------------------------------------------------------------------------------------- |
| `-32700` | Error de análisis (JSON no válido)                                                                               |
| `-32600` | Solicitud no válida                                                                                              |
| `-32601` | Método no encontrado                                                                                             |
| `-32602` | Parámetros no válidos: clave pública incorrecta, campo desconocido o valor de commitment o details no compatible |
| `-32000` | Se superó el límite del filtro                                                                                   |
| `-32001` | El servidor no está listo; vuelve a intentarlo con espera incremental                                            |
| `-32002` | Límite de frecuencia alcanzado (10 mensajes por segundo)                                                         |
| `-32006` | Demasiadas suscripciones (25 por conexión)                                                                       |

Las conexiones también pueden cerrarse con un código de cierre de WebSocket. Consulta [Manejo de reconexiones](/docs/es/parsed-streams/guides/handling-reconnects) para saber qué significa cada código y cómo recuperarte.

## Ejemplos de clientes

<CodeGroup>
  ```bash wscat theme={"system"}
  wscat -c "wss://fs-beta.helius-rpc.com/?api-key=<API_KEY>"
  # then send:
  {"jsonrpc":"2.0","id":1,"method":"parsedTransactionSubscribe","params":[{"programs":["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"]}]}
  ```

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

  const ws = new WebSocket("wss://fs-beta.helius-rpc.com/?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://fs-beta.helius-rpc.com/?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())
  ```
</CodeGroup>
