Guía de Solución de Problemas

Esta guía cubre problemas comunes de integración y soluciones concretas.

Errores de Autenticación

Síntoma

CryptoBotError: code=401, name=UNAUTHORIZED

Verificaciones

import os

from cryptobot import CryptoBotClient

client = CryptoBotClient(api_token=os.environ["CRYPTOBOT_API_TOKEN"])
print(client.get_me().name)

Si eso falla:

  1. Confirme que el token está presente y no está vacío.

  2. Confirme que el token pertenece al entorno previsto.

  3. Si usa un token de testnet, establezca is_mainnet=False.

Discrepancia entre Mainnet y Testnet

import os

from cryptobot import CryptoBotClient

mainnet = CryptoBotClient(api_token=os.environ["CRYPTOBOT_API_TOKEN"], is_mainnet=True)
testnet = CryptoBotClient(api_token=os.environ["CRYPTOBOT_TESTNET_TOKEN"], is_mainnet=False)

Use un token por entorno y no los mezcle.

Fallos de Validación de Monto

Síntoma

CryptoBotError: code=400, name=AMOUNT_TOO_SMALL

Solución

Valide el monto antes de las llamadas a la API:

from decimal import Decimal

from cryptobot.models import Asset


MIN_AMOUNTS = {
    Asset.USDT: Decimal("0.01"),
    Asset.USDC: Decimal("0.01"),
    Asset.TON: Decimal("0.01"),
    Asset.BTC: Decimal("0.000001"),
}


def validate_amount(asset: Asset, amount: float):
    value = Decimal(str(amount))
    minimum = MIN_AMOUNTS.get(asset)
    if minimum is not None and value < minimum:
        raise ValueError(f"Amount too small for {asset.name}. Minimum is {minimum}")

El Estado de la Factura No se Actualiza

Si una factura parece estar estancada:

  1. Consulte por ID de factura.

  2. Verifique Status.paid o Status.expired.

  3. Cree una factura de reemplazo si expiró.

from cryptobot.models import Asset, Status


def refresh_invoice(client, invoice_id: int):
    invoices = client.get_invoices(invoice_ids=str(invoice_id))
    return invoices[0] if invoices else None


def renew_if_expired(client, invoice):
    if invoice.status != Status.expired:
        return invoice

    return client.create_invoice(
        asset=invoice.asset,
        amount=float(invoice.amount),
        description=invoice.description,
        payload=invoice.payload,
        expires_in=3600,
    )

Problemas de Transferencia

Saldo insuficiente

CryptoBotError: code=400, name=INSUFFICIENT_FUNDS
from decimal import Decimal


def has_balance(client, asset, amount: float) -> bool:
    required = Decimal(str(amount))
    for bal in client.get_balances():
        if bal.currency_code == asset.name:
            return Decimal(bal.available) >= required
    return False

spend_id duplicado

CryptoBotError: code=400, name=SPEND_ID_ALREADY_USED
from datetime import datetime
import uuid


def unique_spend_id(prefix: str, user_id: int) -> str:
    return f"{prefix}_{user_id}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}_{uuid.uuid4().hex[:8]}"

Problemas de Timeout y Conexión

Aumente el timeout y habilite los reintentos/backoff integrados para errores de transporte transitorios:

import os

from cryptobot import CryptoBotClient
from cryptobot.models import Asset

client = CryptoBotClient(
    api_token=os.environ["CRYPTOBOT_API_TOKEN"],
    timeout=30.0,
    max_retries=3,
    retry_backoff=0.5,
)

invoice = client.create_invoice(asset=Asset.USDT, amount=5, description="network-safe")

Fallos de Firma de Webhook

La mayoría de los errores de firma provienen de verificar JSON analizado en lugar del cuerpo crudo.

import json
import os

from fastapi import FastAPI, HTTPException, Request

from cryptobot.webhook import check_signature

app = FastAPI()
api_token = os.environ["CRYPTOBOT_API_TOKEN"]


@app.post("/webhook")
async def webhook(request: Request):
    raw = await request.body()
    raw_str = raw.decode("utf-8")

    if not check_signature(api_token, raw_str, request.headers):
        raise HTTPException(status_code=400, detail="Invalid signature")

    data = json.loads(raw_str)
    return {"ok": True, "update_type": data.get("update_type")}

Webhooks No Recibidos

Lista de verificación:

  1. El endpoint es accesible públicamente a través de HTTPS.

  2. La URL del webhook en Crypto Bot es correcta.

  3. Su servicio está escuchando en la ruta/puerto esperados.

  4. El proxy reverso reenvía el cuerpo de la solicitud y los encabezados sin cambios.

Para pruebas locales, ejecute su script de listener y expóngalo con ngrok:

ngrok http 2203

Errores de Análisis de Enum

Al convertir la entrada del usuario a enums, normalice y valide:

from cryptobot.models import Asset, Status


def parse_asset(text: str) -> Asset:
    try:
        return Asset[text.upper()]
    except KeyError as exc:
        raise ValueError(f"Unsupported asset: {text}") from exc


def parse_status(text: str) -> Status:
    try:
        return Status[text.lower()]
    except KeyError as exc:
        raise ValueError(f"Unsupported status: {text}") from exc

Errores de Límite de Tasa

Síntoma

CryptoBotError: code=429, name=TOO_MANY_REQUESTS

Solución

import os

from cryptobot import CryptoBotClient

client = CryptoBotClient(
    api_token=os.environ["CRYPTOBOT_API_TOKEN"],
    max_retries=4,
    retry_backoff=0.5,
    retryable_status_codes={429},
)

app = client.get_me()
print(app.name)

Prueba Rápida de Testnet

import os

from cryptobot import CryptoBotClient
from cryptobot.models import Asset


def smoke_test() -> bool:
    client = CryptoBotClient(
        api_token=os.environ["CRYPTOBOT_TESTNET_TOKEN"],
        is_mainnet=False,
    )

    try:
        client.get_me()
        client.get_balances()
        client.get_exchange_rates()
        client.create_invoice(asset=Asset.USDT, amount=1, description="smoke")
        return True
    except Exception:
        return False

Obtener Ayuda

  1. Documentación de Crypto Pay API

  2. Ejemplos

  3. Temas Avanzados

  4. Issues de GitHub