Skip to main content

Typed Python SDK for the TronDealer API

Project description

TronDealer Python SDK

CI PyPI Python Versions License Code style: ruff

Typed Python SDK for the TronDealer API, built for backend integrations that assign deposit wallets, reconcile balances and transactions, and verify HMAC-signed webhooks.

The SDK follows the official integration guide as the primary source for the payment flow.

Installation

pip install trondealer

For local development:

pip install -e ".[dev]"

This repository also supports uv, which is useful when your system Python is externally managed:

uv sync --extra dev

Configuration

Store your API key in an environment variable or secret manager:

export TRONDEALER_API_KEY="td_..."
import os

from trondealer import TronDealerClient

client = TronDealerClient(api_key=os.environ["TRONDEALER_API_KEY"])

Default configuration:

client = TronDealerClient(
    api_key=os.environ["TRONDEALER_API_KEY"],
    base_url="https://www.trondealer.com/api/v2",
    timeout=10.0,
    max_retries=2,
)

Public Registration

Public registration does not use normal API-key authentication. It posts to /clients/register-public, the canonical endpoint documented by the integration guide.

from trondealer import TronDealerClient

client = TronDealerClient()
registration = client.register_client_public(
    name="My Shop",
    webhook_url="https://example.com/webhooks/trondealer",
    webhook_secret="a-long-random-secret",
    min_confirmations=15,
    sweep_wallet="0xABC...123",
    payout_method="wallet",
    turnstile_token="...",
)

api_key = registration.client.api_key

Advanced users can override the registration path if TronDealer changes the canonical endpoint:

client = TronDealerClient(registration_endpoint="/clients/register-public")

Assign A Wallet

Use one label per order or customer. TronDealer documents label as the user-side idempotency key.

import os

from trondealer import TronDealerClient

client = TronDealerClient(api_key=os.environ["TRONDEALER_API_KEY"])

wallet = client.assign_wallet(label="order-A-1024")
print(wallet.address)

Check A Balance

balance = client.get_wallet_balance(address="0xABC...123")
print(balance.balances)

The integration guide shows balances grouped by network. The embedded OpenAPI schema currently shows a flatter balance map. The SDK accepts both shapes.

List Transactions

transactions = client.list_wallet_transactions(
    address="0xABC...123",
    status="confirmed",
    limit=20,
    offset=0,
)

for tx in transactions.transactions:
    print(tx.tx_hash, tx.amount, tx.status)

Supported transaction statuses:

  • detected
  • confirmed
  • notified
  • swept

Verify Webhooks

TronDealer sends HMAC-SHA256 signatures in the X-Signature-256 header when a webhook secret is configured. Always verify the signature against the raw request body before parsing JSON.

from trondealer import parse_webhook_event, verify_webhook_signature

if verify_webhook_signature(raw_body, signature, webhook_secret):
    event = parse_webhook_event(raw_body)

The SDK accepts both documented signature formats: raw hex and sha256=<hex>.

FastAPI

import os

from fastapi import FastAPI, Header, HTTPException, Request

from trondealer import parse_webhook_event, verify_webhook_signature

app = FastAPI()


@app.post("/webhooks/trondealer")
async def trondealer_webhook(
    request: Request,
    x_signature_256: str | None = Header(default=None),
) -> dict[str, str]:
    raw_body = await request.body()
    secret = os.environ["TRONDEALER_WEBHOOK_SECRET"]

    if not x_signature_256 or not verify_webhook_signature(raw_body, x_signature_256, secret):
        raise HTTPException(status_code=401, detail="invalid signature")

    event = parse_webhook_event(raw_body)
    return {"status": "ok"}

Flask

import os

from flask import Flask, abort, request

from trondealer import parse_webhook_event, verify_webhook_signature

app = Flask(__name__)


@app.post("/webhooks/trondealer")
def trondealer_webhook() -> tuple[str, int]:
    raw_body = request.get_data(cache=False)
    signature = request.headers.get("X-Signature-256")
    secret = os.environ["TRONDEALER_WEBHOOK_SECRET"]

    if not signature or not verify_webhook_signature(raw_body, signature, secret):
        abort(401)

    event = parse_webhook_event(raw_body)
    return "ok", 200

Recommended Payment Flow

  1. Create one wallet per order or customer using label.
  2. Show the returned address to the user.
  3. Wait for the confirmed or notified webhook.
  4. Store tx_hash + log_index as a unique key to prevent double crediting.
  5. Do not mark an order as paid when the transaction is only in detected status.

Security Warnings

  • Never expose the x-api-key in frontend or mobile apps.
  • Store api_key and webhook_secret in environment variables or a secret manager.
  • Always verify the webhook HMAC signature.
  • Persist the raw body and signature for audit/debugging purposes.
  • Do not print API keys, webhook secrets, or full signed webhook payloads in logs.

Documentation Discrepancies

The official integration guide documents public registration as:

POST /api/v2/clients/register-public
Auth: none, with Turnstile token

The API docs/OpenAPI surface may list the same public operation as:

POST /api/v2/clients/register-open

This SDK uses /clients/register-public as canonical because the integration guide documents the complete registration flow, request body, auth behavior, and cURL example for that endpoint. The SDK does not silently switch to /clients/register-open. If needed, pass registration_endpoint="/clients/register-open" explicitly.

TODO before stable v1.0: verify /clients/register-public directly against the live API or with TronDealer maintainers.

Other known discrepancies:

  • The guide shows per-network balance responses; embedded OpenAPI shows a flatter balance object.
  • The guide shows raw hex webhook signatures; embedded OpenAPI describes sha256=<hex>.
  • The guide says EVM wallet assignment returns an existing wallet for the same label; embedded OpenAPI only documents 201 for EVM assignment.

Development

The Makefile runs tools through uv run --extra dev, so commands use the project development environment instead of depending on packages installed in your global Python.

make help
make test
make test:coverage
make lint
make format
make format:check

Equivalent direct commands after installing development dependencies:

pip install -e ".[dev]"
ruff check .
ruff format --check .
pytest

If your Python installation is externally managed and pip install -e ".[dev]" is blocked, use:

uv sync --extra dev
uv run pytest
uv run ruff check .
uv run ruff format --check .

Publishing To PyPI

Do not publish until endpoint behavior has been verified against the live API or with TronDealer maintainers.

Example publishing flow:

python -m build
twine check dist/*
twine upload dist/*

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trondealer-0.1.0.tar.gz (83.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

trondealer-0.1.0-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file trondealer-0.1.0.tar.gz.

File metadata

  • Download URL: trondealer-0.1.0.tar.gz
  • Upload date:
  • Size: 83.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trondealer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9497288a4f9294a268befbacb27a5d0eacb4633fd06c831e18f222abe5650b1a
MD5 c21acaabce0db0654afe54ece1ac86d0
BLAKE2b-256 cb92842cac1b1e23e090f963de9adc4037e7dbfc5c5fea7d3b1ca2b8b0e338c8

See more details on using hashes here.

Provenance

The following attestation bundles were made for trondealer-0.1.0.tar.gz:

Publisher: publish.yml on ragnarok22/trondealer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file trondealer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: trondealer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trondealer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d00b600fa658b788f00c5d24222572026ef082f934570da9751b185b05301032
MD5 706ec649b39e9b56145602526b4ebf10
BLAKE2b-256 ff7e071bcb816f68519c5e006fb4365eb15dccd4c3961610a18e1bf752215e93

See more details on using hashes here.

Provenance

The following attestation bundles were made for trondealer-0.1.0-py3-none-any.whl:

Publisher: publish.yml on ragnarok22/trondealer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page