Skip to main content

Official Python SDK for the WeEasyCrypto tenant API — deposit addresses, balances, withdrawals, Ed25519 request signing and verified webhooks.

Project description

weeasycrypto (Python)

Official Python SDK for the WeEasyCrypto tenant API: deposit addresses, balances, deposits, withdrawals, and signed webhooks.

  • One runtime dependency. HTTP via urllib; Ed25519 (request signing and webhook verification) via the audited cryptography package (the stdlib has none). A custom transport is injectable for proxies, test stubs, or record/replay.
  • Signing you never hand-write. Every request carries an Ed25519 signature (X-Timestamp + X-Signature) computed over the exact bytes sent on the wire — the platform holds only your public key and can verify, never forge. Webhook deliveries are Ed25519-signed too (v1a, per-tenant platform key) — verified with your tenant's public key, ±300 s tolerance.
  • Amounts are decimal strings, never floats. parse_amount / format_amount use pure integer arithmetic.

⚠️ Server-side only. Your Ed25519 private_key must never reach a browser or mobile bundle — it was generated locally when the key was issued and the platform cannot recover it.

Install

pip install weeasycrypto

Quickstart

import os
from weeasycrypto import WeEasyCrypto

cv = WeEasyCrypto(
    base_url="https://api.example.com",
    api_key=os.environ["WEEASYCRYPTO_API_KEY"],          # keyId, e.g. "ck_…"
    private_key=os.environ["WEEASYCRYPTO_PRIVATE_KEY"],  # hex Ed25519 seed, generated at issuance
    webhook_public_key=os.environ.get("WEEASYCRYPTO_WEBHOOK_PUBLIC_KEY"),  # portal → Settings → Integrations
)

# Issue a deposit address
addr = cv.addresses.create(label="user-42", chain_key="tron")
addr.family  # 'EVM' | 'TRON' | 'BTC' | 'SOL' | 'TON'

# Balances — amounts are decimal strings, never floats
balances = cv.balances.list()

# Deposits with auto-pagination
for d in cv.deposits.iterate(status="CONFIRMED"):
    print(d.tx_hash, d.amount)

Withdrawals — the idempotency contract

request_id is your idempotency key. Persist it in your own database before calling; the SDK deliberately never generates one, because a regenerated key after a crash is how double-payouts happen.

from weeasycrypto import ConflictError

try:
    w = cv.withdrawals.create(
        request_id="wd-20260710-0001",  # yours, persisted first
        chain_key="eth-mainnet",
        token_symbol="USDT",
        to="0x…",
        amount="100.5",  # always a string
    )
except ConflictError as err:
    if err.is_duplicate_request:
        # Safety signal, not a failure: an earlier attempt already created it.
        # Look the withdrawal up via the id you stored against this request_id.
        ...
    else:
        raise

# Poll to a terminal status (webhooks are the push-based alternative)
final = cv.withdrawals.wait_until_final(w.id)
# final.status: 'CONFIRMED' | 'FAILED' | 'REJECTED' | 'CANCELED'
if final.status == "CONFIRMED":
    print(final.tx_hash)

Network errors on withdrawals.create / create_batch are retried automatically with the same request_id — that can never double-spend. addresses.create has no idempotency key, so it is never auto-retried; list() recent addresses before creating again if the outcome was unknown.

Webhooks

Deliveries carry X-Webhook-Signature: t={ts},v1a={hex} — an Ed25519 signature over {ts}.{body} made with a per-tenant platform key. Verification needs only your tenant's public key (webhookSignPublicKey in the merchant portal, Settings → Integrations); there is no shared secret to protect.

# Flask example — raw body must be the exact bytes received.
from weeasycrypto import WebhookVerificationError

@app.post("/webhook")
def webhook():
    try:
        event = cv.webhooks.parse(
            request.get_data(), request.headers.get("X-Webhook-Signature")
        )
    except WebhookVerificationError:
        return "", 400

    if event.type == "deposit.confirmed":
        credit(event.data["depositId"], event.data["amount"])
    elif event.type == "withdrawal.completed":
        mark_paid(event.data["requestId"])
    # New event types appear over time — ignore what you don't know.
    return "", 200

Errors

WeEasyCryptoError
├─ APIError (status / code / request_id)
│   ├─ AuthenticationError(401)   ├─ PermissionDeniedError(403)
│   ├─ NotFoundError(404)         ├─ ConflictError(409)   # .is_duplicate_request
│   ├─ ValidationError(422)       └─ ServerError(5xx)
│   └─ RateLimitError(429)        # .retry_after_ms
├─ NetworkError                    # no HTTP response; safe to replay withdrawals
├─ WebhookVerificationError
└─ TimeoutError                    # wait_until_final budget exceeded

Testing

python3 -m venv .venv && .venv/bin/pip install -e . pytest
.venv/bin/pytest

Signing is verified against the shared golden vectors in ../vectors/signing-vectors.json.

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

weeasycrypto-0.2.0.tar.gz (20.4 kB view details)

Uploaded Source

Built Distribution

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

weeasycrypto-0.2.0-py3-none-any.whl (21.7 kB view details)

Uploaded Python 3

File details

Details for the file weeasycrypto-0.2.0.tar.gz.

File metadata

  • Download URL: weeasycrypto-0.2.0.tar.gz
  • Upload date:
  • Size: 20.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for weeasycrypto-0.2.0.tar.gz
Algorithm Hash digest
SHA256 6a781399c341709d4323ff9858b4c6db8f349b0eec541e9366ca3ec5142429cc
MD5 4914a33ba422efb634c6107f20c0d1eb
BLAKE2b-256 5227a1241a97fc12392a7b05a9d873c82273d9255d473a6660bdac9d411287db

See more details on using hashes here.

File details

Details for the file weeasycrypto-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: weeasycrypto-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for weeasycrypto-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc00b9c9180c5c468ed9d9a8eca4e03dfb04d3c5cdb3a1df1417eeaef791dae4
MD5 9f59bb018f39d38b485eb64dd7ee955c
BLAKE2b-256 4a970f34e8b2f435f13999c03651a1015bd290613bac3592f0e750d148568426

See more details on using hashes here.

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