TONAPI Python SDK

repository·main·Indexed 41 days ago

https://github.com/nessshon/tonapi

A Python SDK (pytonapi) for interacting with the TON blockchain via the tonapi.io REST API, real-time streaming (SSE/WebSocket), and webhooks. It provides tools for querying accounts, NFTs, jettons, and DNS, as well as simulating messages and executing get methods. Includes a plugin for Claude Code to enable natural language queries of the TON blockchain.

Tokens
44.6K
Snippets
267
Records
305
Agent score
47%

What's inside TONAPI

  1. Overview of pytonapi capabilities

    main

    The pytonapi SDK provides three primary ways to interact with the TON blockchain via tonapi.io:

    1. REST API: Query data for accounts, NFTs, jettons, DNS, and more.
    2. Streaming: Receive real-time events using Server-Sent Events (SSE) or WebSockets.
    3. Webhooks: Set up push notifications using an event dispatcher.

    Important Distinction:

    • Use pytonapi for reading blockchain data and receiving events.
    • Use tonutils for writing to the blockchain (e.g., creating wallets, transferring TON or jettons).
  2. Use the Lite Server for low-level blockchain access

    main
    The tonapi.lite_server module provides access to raw Lite Server protocol operations. These methods allow for low-level interaction with the TON blockchain, including retrieving masterchain info, block data, account states, and shard information. All methods in this module are asynchronous and return a dict[str, Any].
  3. Subscribe to real-time blockchain events via SSE or WebSocket

    main

    The pytonapi streaming module allows you to subscribe to real-time blockchain events using either Server-Sent Events (SSE) or WebSockets. Both transports multiplex all subscriptions over a single connection and use a decorator-based API to handle incoming events.

    Transport Options

    • TonapiSSE: A one-way stream. It uses a single POST request where the server pushes events to the client.
    • TonapiWebSocket: A bidirectional stream. It allows for dynamic subscribing and unsubscribing after the initial connection is established.

    Note: An API key is required for all streaming connections. Unauthenticated connections will be rejected. You can obtain a key at tonconsole.com.

    from pytonapi.streaming import TonapiSSE, TonapiWebSocket
    
    # For SSE
    sse = TonapiSSE("YOUR_API_KEY", Network.MAINNET)
    
    # For WebSocket
    ws = TonapiWebSocket("YOUR_API_KEY", Network.MAINNET)
  4. How TON API webhooks work

    main

    Webhooks deliver real-time POST notifications to your server when blockchain events occur. The SDK provides three main components to manage this:

    1. TonapiWebhookClient: A low-level HTTP client used for CRUD operations on webhooks (create, list, delete, subscribe/unsubscribe).
    2. TonapiWebhook: A bound webhook object that manages subscriptions without requiring you to handle explicit IDs manually.
    3. TonapiWebhookDispatcher: A high-level, decorator-based dispatcher used to register event handlers, automatically set up webhook subscriptions, and process incoming HTTP requests.

    Security Note: Every webhook has a unique secret token. TON API sends this token in the Authorization: Bearer {token} header with every event. The TonapiWebhookDispatcher.process() method verifies this token automatically to ensure requests are genuine.

    from pytonapi.webhook import TonapiWebhookClient, TonapiWebhookDispatcher
    
    client = TonapiWebhookClient("YOUR_API_KEY", Network.MAINNET)
    dispatcher = TonapiWebhookDispatcher(
        "https://example.com/webhook",
        client=client,
        accounts=["ACCOUNT_ADDRESS"],
    )
  5. Configure TONAPI Networks

    main

    The Python SDK supports three primary networks. You can specify the network using the Network enum or via the --network CLI flag/TONAPI_NETWORK environment variable.

    NetworkEnumBase URL
    MainnetNetwork.MAINNEThttps://tonapi.io
    TestnetNetwork.TESTNEThttps://testnet.tonapi.io
    TetraNetwork.TETRAhttps://tetra.tonapi.io
    from pytonapi.types import Network
    # Use Network.MAINNET, Network.TESTNET, or Network.TETRA
  6. Signing and Sending Transactions

    main

    The pytonapi SDK can send a signed BOC (Bag of Cells) using the blockchain.send_message method. However, the SDK cannot sign transactions itself as it does not have access to private keys.

    For building and signing transactions, it is recommended to use the tonutils library (pip install tonutils).

  7. Configure SDK Retries and Error Handling

    main

    The SDK includes built-in exponential backoff for specific error codes:

    • 429 (Too Many Requests): 5 attempts, 0.3s base.
    • 500, 502, 503, 504 (Server Errors): 3 attempts, 0.5s base.

    Retries can be customized using a RetryPolicy or disabled by setting retry_policy=None.

    Common Error Codes:

    • 401: Invalid API key.
    • 403: API key permission issues.
    • 404: Resource (address, transaction, etc.) not found.
    • TONAPIValidationError: Response body did not match the expected Pydantic model.
  8. Understand transaction finality levels

    main

    Every trace-based notification includes a finality field. The lifecycle is monotonic: pending $\rightarrow$ confirmed $\rightarrow$ finalized. A trace_invalidated event may occur at any point before finalized to signal a rollback.

    LevelLatencyGuarantee
    Finality.PENDING~30-100 msSpeculative. May be rolled back.
    Finality.CONFIRMEDSecondsIn a signed shard block. Small rollback risk.
    Finality.FINALIZEDSecondsCommitted in masterchain. Irreversible.

    Use min_finality in your handlers to filter the minimum level of certainty required.

    • If min_finality=Finality.CONFIRMED, PENDING events are skipped.
    • If min_finality=Finality.FINALIZED, both PENDING and CONFIRMED events are skipped.
  9. Manage TonapiWebhookClient sessions

    main

    The client supports both context manager and manual session management to ensure connections are properly closed.

    Context Manager (Recommended): Use async with to automatically handle setup and teardown.

    Manual Management: Call await client.create_session() to start and await client.close_session() in a finally block to clean up.

    # Context manager
    async with TonapiWebhookClient("YOUR_API_KEY", Network.MAINNET) as client:
        webhooks = await client.list()
    
    # Manual
    client = TonapiWebhookClient("YOUR_API_KEY", Network.MAINNET)
    await client.create_session()
    try:
        webhooks = await client.list()
    finally:
        await client.close_session()
  10. Manage TonapiRestClient sessions

    main

    The client manages an underlying HTTP session. You can manage its lifecycle using a context manager, manual calls, or by providing an external aiohttp.ClientSession.

    # Context manager (Recommended)
    async with TonapiRestClient("YOUR_API_KEY", Network.MAINNET) as tonapi:
        account = await tonapi.accounts.get_account(account_id="EQ...")
    
    # Manual lifecycle management
    tonapi = TonapiRestClient("YOUR_API_KEY", Network.MAINNET)
    await tonapi.create_session()
    try:
        account = await tonapi.accounts.get_account(account_id="EQ...")
    finally:
        await tonapi.close_session()
    
    # Using an external session
    import aiohttp
    
    async with aiohttp.ClientSession() as session:
        async with TonapiRestClient(
            "YOUR_API_KEY",
            Network.MAINNET,
            session=session,
        ) as tonapi:
            account = await tonapi.accounts.get_account(account_id="EQ...")
        # Note: The client does not close the external session; you must manage it.
  11. Install the Claude Code plugin for TONAPI

    main

    You can install the TONAPI plugin for Claude Code using the marketplace commands or by cloning the repository locally.

    Via Claude Code Marketplace

    Run these commands within your Claude Code session:

    /plugin marketplace add nessshon/claude-plugins
    /plugin install tonapi@nessshon-plugins

    Via Local Installation

    Clone the repository and point Claude to the plugin directory:

    git clone https://github.com/nessshon/tonapi.git
    claude --plugin-dir ./tonapi
  12. Handle webhook events with TonapiWebhookDispatcher

    main

    The TonapiWebhookDispatcher manages handler registration, webhook lifecycle, and event routing. It is designed to receive incoming HTTP requests and route them to the correct handler.

    Initialization:

    dispatcher = TonapiWebhookDispatcher(
        url="https://example.com",
        client=client,
        accounts=["EQ..."],
        opcodes=["0x7362d09c"],
        db=database # Example dependency
    )

    Registering Handlers: Use decorators to register handlers. Decorators can accept *accounts for local filtering and a path for custom URL paths. Default paths are /account-tx, /mempool-msg, /opcode-msg, and /new-contracts.

    • @dispatcher.account_tx()
    • @dispatcher.mempool_msg()
    • @dispatcher.opcode_msg()
    • @dispatcher.new_contracts()

    Lifecycle:

    • await dispatcher.setup(): Opens a session, creates webhooks, and subscribes to events. Existing webhooks are reused via ensure().
    • await dispatcher.teardown(cleanup=True): Closes the session. If cleanup=True, it unsubscribes from all events first.

    Processing Events: When your web server receives a request, pass the data to process():

    await dispatcher.process(
        path="/account-tx",
        data=payload,
        authorization=headers.get("Authorization"),
    )

    Dependencies: Dependencies passed to the constructor via **kwargs are injected into handlers. Per-request dependencies passed to process() take priority.

    from pytonapi.webhook import TonapiWebhookClient, TonapiWebhookDispatcher
    from pytonapi.types import Network
    
    client = TonapiWebhookClient("YOUR_API_KEY", Network.MAINNET)
    
    dispatcher = TonapiWebhookDispatcher(
        "https://example.com",
        client=client,
        accounts=["EQ..."],
        opcodes=["0x7362d09c"],
    )
    
    @dispatcher.account_tx()
    async def handler(event: AccountTxEvent, db: Database) -> None:
        await db.save(event)
    
    # Lifecycle management
    await dispatcher.setup()
    # ... receive requests ...
    await dispatcher.teardown(cleanup=True)