Skip to main content

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.

Metadata

Release files for weeasycrypto 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for weeasycrypto 0.2.0
File Size Uploaded Provenance
weeasycrypto-0.2.0.tar.gz 20.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for weeasycrypto 0.2.0
File Interpreter ABI Platform
weeasycrypto-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.0 kB

Release files / weeasycrypto-0.2.0.tar.gz

Download URL weeasycrypto-0.2.0.tar.gz
Size 20.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6a781399c341709d4323ff9858b4c6db8f349b0eec541e9366ca3ec5142429cc
BLAKE2b-256 checksum
How to use checksums
5227a1241a97fc12392a7b05a9d873c82273d9255d473a6660bdac9d411287db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / weeasycrypto-0.2.0-py3-none-any.whl

Download URL weeasycrypto-0.2.0-py3-none-any.whl
Size 21.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fc00b9c9180c5c468ed9d9a8eca4e03dfb04d3c5cdb3a1df1417eeaef791dae4
BLAKE2b-256 checksum
How to use checksums
4a970f34e8b2f435f13999c03651a1015bd290613bac3592f0e750d148568426
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Security for weeasycrypto 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page