Metadata-Version: 2.4
Name: nextwallet-pay
Version: 1.0.0
Summary: Python SDK for the NEXT Pay API — accept crypto payments in your service
License: MIT
Project-URL: Documentation, https://docs.nextwallet.one
Project-URL: Homepage, https://docs.nextwallet.one
Keywords: payments,crypto,usdt,ton,telegram,api,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.7
Provides-Extra: dev
Requires-Dist: pytest>=8.2; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"

# nextwallet-pay

Python SDK for the **NEXT Pay API** — accept crypto payments in your service and get paid to your
NEXT wallet.

```bash
pip install nextwallet-pay
```

## Getting a token

1. Open the NEXT bot → **Настройки → Приём платежей → Создать приложение**.
2. Save the **API token** (`123:AbCd...`) and the **webhook signing key** (`whsec_...`) —
   the token is shown **once**.
3. Set your callback URL (must be `https://`).

## Quick start

```python
from nextwallet_pay import NextPay, Asset

async with NextPay("123:AbCd...") as pay:
    invoice = await pay.create_invoice(
        Asset.USDT,          # USDT is $1 and unified across networks → use it to price in dollars
        "10.50",
        description="Pro subscription",
        payload="order-42",  # echoed back on the webhook — put your order id here
        expires_in=900,
    )
    print(invoice.pay_url)   # https://t.me/YourBot?start=payinv_XXXX
```

Send `pay_url` to the customer. They open it in Telegram and pay from their NEXT balance.

## Receiving the payment (webhook)

Two rules, both non-negotiable:

1. **Verify the signature.** Otherwise anyone who finds your endpoint can fake a payment.
2. **Dedupe by `invoice.id`.** Delivery is *at-least-once* — a retry can redeliver a callback you
   already processed.

```python
from fastapi import FastAPI, Request, HTTPException
from nextwallet_pay.webhook import verify_and_parse
from nextwallet_pay.errors import SignatureError

app = FastAPI()
SIGNING_SECRET = "whsec_..."

@app.post("/next-webhook")
async def next_webhook(request: Request):
    raw = await request.body()
    try:
        event = verify_and_parse(
            SIGNING_SECRET,
            raw,
            request.headers.get("X-Next-Signature", ""),
            timestamp=request.headers.get("X-Next-Timestamp"),
        )
    except SignatureError:
        raise HTTPException(status_code=403, detail="bad signature")

    inv = event.invoice
    if await already_processed(inv.id):      # idempotency — required
        return {"ok": True}
    await grant_order(inv.payload, inv.net)  # inv.net = what you actually received
    return {"ok": True}
```

Respond **2xx** to stop retries. Anything else is retried with backoff (~10s → 1h) for about a day.

## Amounts

Amounts are `Decimal`, never `float` — binary floats can't represent `0.1` exactly, and money must
round-trip precisely. Passing a `float` raises.

```python
from decimal import Decimal
await pay.create_invoice(Asset.TON, Decimal("1.234567890"))
```

`invoice.amount` is what the customer pays, `invoice.fee` is our commission, and `invoice.net` is
what lands on your balance.

## Other calls

```python
app_info = await pay.get_me()             # app_info.commission_percent → Decimal('3')
balances = await pay.get_balance()
invoices = await pay.get_invoices(status="paid", count=50)
await pay.delete_invoice(invoice.id)

# Pay a user out of your balance (payouts, refunds, cashback).
# Idempotent on spend_id — retrying the same one never pays twice.
await pay.transfer(user_id=12345, asset=Asset.USDT, amount="5.00", spend_id="refund-42")
```

## Sync client

```python
from nextwallet_pay import NextPaySync, Asset

with NextPaySync("123:AbCd...") as pay:
    inv = pay.create_invoice(Asset.USDT, "10.50")
```

## Errors

```python
from nextwallet_pay import NextPayAPIError, NextPayNetworkError

try:
    await pay.create_invoice(Asset.USDT, "10.50")
except NextPayAPIError as e:
    print(e.code, e.message)   # e.g. "bad_amount", "rate_limited", "unauthorized"
except NextPayNetworkError:
    ...                        # never got an answer, retries exhausted
```

## Supported assets

`USDT` (unified, $1), `TON`, `BNB`, `TRX`, `ETH`, `BTC`, `XMR`.

## Full documentation

- **[Merchant integration guide — English](https://docs.nextwallet.one)**
- **[Руководство по интеграции — Русский](https://docs.nextwallet.one)**
