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

# Overview

> SSE and WebSocket subscriptions with automatic reconnection

Subscribe to real-time blockchain events over SSE or WebSocket. Both transports use a decorator-based handler API and multiplex all subscriptions over a single connection.

<Info>
  API key is **required** — unauthenticated connections are rejected. Get a key at [tonconsole.com](https://tonconsole.com/).
</Info>

| Transport         | Description                                                 |
| ----------------- | ----------------------------------------------------------- |
| `TonapiSSE`       | One-way stream. Single POST request, server pushes events.  |
| `TonapiWebSocket` | Bidirectional. Dynamic subscribe/unsubscribe after connect. |

## Endpoints

<Tabs>
  <Tab title="SSE">
    | Network | URL                                          |
    | ------- | -------------------------------------------- |
    | Mainnet | `https://tonapi.io/streaming/v2/sse`         |
    | Testnet | `https://testnet.tonapi.io/streaming/v2/sse` |
  </Tab>

  <Tab title="WebSocket">
    | Network | URL                                       |
    | ------- | ----------------------------------------- |
    | Mainnet | `wss://tonapi.io/streaming/v2/ws`         |
    | Testnet | `wss://testnet.tonapi.io/streaming/v2/ws` |
  </Tab>
</Tabs>

## Quick Example

```python theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
import asyncio

from pytonapi.types import Network
from pytonapi.streaming import Finality, TonapiSSE, TransactionsNotification
from pytonapi.exceptions import TONAPIConnectionLostError

sse = TonapiSSE("YOUR_API_KEY", Network.MAINNET)


@sse.on_transactions(min_finality=Finality.FINALIZED)
async def on_tx(n: TransactionsNotification) -> None:
    for tx in n.transactions:
        print(tx.get("hash"))


async def main() -> None:
    try:
        await sse.start(addresses=["EQDtFpEwcFAEcRe5mLVh2N6C0x-_hJEM7W61_JLnSF74p4q2"])
    except TONAPIConnectionLostError as e:
        print(f"Connection lost after {e.attempts} reconnect attempts")
    finally:
        await sse.stop()


if __name__ == "__main__":
    asyncio.run(main())
```

## Event Models

All models are Pydantic `BaseModel` subclasses from `pytonapi.streaming`.

<Accordion title="TransactionsNotification">
  | Field                      | Type                      | Description                                |
  | -------------------------- | ------------------------- | ------------------------------------------ |
  | `type`                     | `Literal["transactions"]` | Always `"transactions"`.                   |
  | `finality`                 | `str`                     | `"pending"`, `"confirmed"`, `"finalized"`. |
  | `trace_external_hash_norm` | `str`                     | Links related notifications for a trace.   |
  | `transactions`             | `list[dict]`              | Transaction objects (LT descending).       |
  | `address_book`             | `dict \| None`            | Address -> name mapping.                   |
  | `metadata`                 | `dict \| None`            | Token metadata.                            |
</Accordion>

<Accordion title="ActionsNotification">
  | Field                      | Type                 | Description                                |
  | -------------------------- | -------------------- | ------------------------------------------ |
  | `type`                     | `Literal["actions"]` | Always `"actions"`.                        |
  | `finality`                 | `str`                | `"pending"`, `"confirmed"`, `"finalized"`. |
  | `trace_external_hash_norm` | `str`                | Links related notifications for a trace.   |
  | `actions`                  | `list[dict]`         | Classified action objects.                 |
  | `address_book`             | `dict \| None`       | Address -> name mapping.                   |
  | `metadata`                 | `dict \| None`       | Token metadata.                            |
</Accordion>

<Accordion title="TraceNotification">
  | Field                      | Type                 | Description                        |
  | -------------------------- | -------------------- | ---------------------------------- |
  | `type`                     | `Literal["trace"]`   | Always `"trace"`.                  |
  | `finality`                 | `str`                | Finality level.                    |
  | `trace_external_hash_norm` | `str`                | Trace identifier.                  |
  | `trace`                    | `dict \| None`       | Trace tree structure.              |
  | `transactions`             | `dict \| None`       | Hash -> transaction object map.    |
  | `actions`                  | `list[dict] \| None` | Classified actions for this trace. |
  | `address_book`             | `dict \| None`       | Address -> name mapping.           |
  | `metadata`                 | `dict \| None`       | Token metadata.                    |
</Accordion>

<Accordion title="AccountStateNotification">
  | Field      | Type                              | Description                          |
  | ---------- | --------------------------------- | ------------------------------------ |
  | `type`     | `Literal["account_state_change"]` | Always `"account_state_change"`.     |
  | `finality` | `str`                             | `"confirmed"` or `"finalized"` only. |
  | `account`  | `str`                             | Address in raw format.               |
  | `state`    | `AccountState \| None`            | Account state snapshot.              |

  `AccountState` fields: `hash`, `balance`, `account_status`, `data_hash`, `code_hash`.
</Accordion>

<Accordion title="JettonsNotification">
  | Field          | Type                        | Description                          |
  | -------------- | --------------------------- | ------------------------------------ |
  | `type`         | `Literal["jettons_change"]` | Always `"jettons_change"`.           |
  | `finality`     | `str`                       | `"confirmed"` or `"finalized"` only. |
  | `jetton`       | `JettonWallet \| None`      | Jetton wallet snapshot.              |
  | `address_book` | `dict \| None`              | Address -> name mapping.             |
  | `metadata`     | `dict \| None`              | Token metadata.                      |

  `JettonWallet` fields: `address`, `balance`, `owner`, `jetton`, `last_transaction_lt`.
</Accordion>

<Accordion title="TraceInvalidatedNotification">
  | Field                      | Type                           | Description                    |
  | -------------------------- | ------------------------------ | ------------------------------ |
  | `type`                     | `Literal["trace_invalidated"]` | Always `"trace_invalidated"`.  |
  | `trace_external_hash_norm` | `str`                          | Hash of the invalidated trace. |

  Fires when a previously delivered pending or confirmed trace becomes invalid. Discard cached data for that `trace_external_hash_norm`. No invalidation after finalized.
</Accordion>

<Note>
  No invalidation for `account_state_change` or `jettons_change`. Use `Finality.FINALIZED` for irreversible balance data.
</Note>

## Action Types

<Accordion title="All ActionType values (22)">
  | Enum member                           | Wire value                 |
  | ------------------------------------- | -------------------------- |
  | `ActionType.TON_TRANSFER`             | `ton_transfer`             |
  | `ActionType.JETTON_TRANSFER`          | `jetton_transfer`          |
  | `ActionType.JETTON_SWAP`              | `jetton_swap`              |
  | `ActionType.JETTON_BURN`              | `jetton_burn`              |
  | `ActionType.JETTON_MINT`              | `jetton_mint`              |
  | `ActionType.NFT_MINT`                 | `nft_mint`                 |
  | `ActionType.CALL_CONTRACT`            | `call_contract`            |
  | `ActionType.CONTRACT_DEPLOY`          | `contract_deploy`          |
  | `ActionType.STAKE_DEPOSIT`            | `stake_deposit`            |
  | `ActionType.STAKE_WITHDRAWAL`         | `stake_withdrawal`         |
  | `ActionType.STAKE_WITHDRAWAL_REQUEST` | `stake_withdrawal_request` |
  | `ActionType.DEX_DEPOSIT_LIQUIDITY`    | `dex_deposit_liquidity`    |
  | `ActionType.DEX_WITHDRAW_LIQUIDITY`   | `dex_withdraw_liquidity`   |
  | `ActionType.ELECTION_DEPOSIT`         | `election_deposit`         |
  | `ActionType.ELECTION_RECOVER`         | `election_recover`         |
  | `ActionType.AUCTION_BID`              | `auction_bid`              |
  | `ActionType.CHANGE_DNS`               | `change_dns`               |
  | `ActionType.DELETE_DNS`               | `delete_dns`               |
  | `ActionType.RENEW_DNS`                | `renew_dns`                |
  | `ActionType.TICK_TOCK`                | `tick_tock`                |
  | `ActionType.SUBSCRIBE`                | `subscribe`                |
  | `ActionType.UNSUBSCRIBE`              | `unsubscribe`              |
</Accordion>

For the raw wire protocol, see the [Streaming API v2 specification](https://gist.github.com/dungeon-master-666/98db8d73e9cd9a1b7802bc06ded5b155).
