https://api.paychainly.comAPI Reference
v1REST API for integrating USDT (BEP-20) payments into your platform. Manage customers, generate deposit addresses or payment links, and query transactions — all secured with an API key. Never expose your key in client-side code.
Authentication
Integration Patterns
For patterns 2, 3, and 4 — all three payment options come from the same single API call. Pick whichever fits your UI:
link.payUrl → https://paychainly.com/pay/:slug // ① redirect to hosted page
link.address → 0xABC... // ② show in your own UI
link.address → 0xABC... (QR-encode it) // ③ QR code
link.amount → "49.99"
link.expiresAt → "2026-06-03T10:00:00.000Z"Customers
8Deposit Addresses
5Payment Links
6Transactions
3Invoices
3Withdrawals
7Sandbox
1Error Codes
@paychainly/sdkNode.js SDK
TypeScript SDK for the Paychainly platform. Accept USDT on BNB Smart Chain — manage customers, deposit addresses, payment links, invoices, and withdrawals without writing raw HTTP calls.
Installation
Setup
Create one instance and export it — import everywhere else.
Integration Patterns
| # | Pattern | Customer | Address | Payment Link | Best For |
|---|---|---|---|---|---|
| 1 | Wallet — address only | Required | reuse — permanent | Not needed | Deposit wallets, top-ups |
| 2 | Wallet — with link | Required | reuse — same | createForAddress() | Fixed-amount top-ups |
| 3 | Order Checkout (logged in) | Required | generate_new | paymentLinks.create() | E-commerce, invoices |
| 4 | Guest Checkout | Not needed | generate_new | paymentLinks.create() | One-off, anonymous |
Pattern 1 — Permanent Wallet
Each user gets one permanent deposit address. Same address every time — safe to call on every login.
Pattern 2 — Wallet + Payment Link
Same permanent address, wrapped in a hosted checkout page with a fixed amount and expiry.
Pattern 3 — Order Checkout
Each order gets a fresh deposit address. uniqueId is an idempotency key — safe to retry.
Pattern 4 — Guest Checkout
No customer required. Anyone can pay — fully anonymous.
Receiving Payments
Set your webhook URL in the dashboard. Use express.raw() — not express.json() — so signature verification works.
Testing signatures without a real payment:
What's new in 1.0.14
Retry with exponential backoff
Per-call timeout
Auto-pagination
Extended transaction filters
Revoke by wallet address
Sandbox credit
API Reference
@paychainly/reactReact Package
React hooks and components for Paychainly. Accept USDT payments with real-time detection — no API key in the browser, ever.
Installation
How it works — no API key in browser
Your server creates payment links using @paychainly/sdk (API key stays server-side). It returns only the slug to your frontend. @paychainly/react fetches public data and listens for real-time events — no API key needed.
Quick Start
Full checkout in 10 lines — pass a slug from your server.
<PaymentCheckout />
Full checkout from a single slug. Handles loading, QR, copy, countdown, confirmed, and expired states automatically.
classNames slots
| Slot | Applied to |
|---|---|
| container | outer div (active state) |
| header | memo text |
| qr | QR code wrapper |
| address | AddressCopy wrapper |
| amount | amount display |
| countdown | countdown badge |
| confirmedBanner | confirmed state div |
| expiredBanner | expired state div |
| errorBanner | error state div |
| loadingContainer | loading state div |
<WalletAddressView />
Permanent wallet display — no API calls, no Socket.io. Pass the address directly.
<PaymentStatus />
Minimal badge — colored dot + label. Embeds in order pages, tables, dashboards.
Hooks
Primitives
Unstyled building blocks for fully custom UIs.
Theming
Pass a theme prop to any full component. All colors, border radius, and fonts are configurable.
MetaMask / Web3 — useWalletPay
Trigger a direct USDT transfer from the user's MetaMask wallet — no copy-paste needed. Tracks every step of the transaction.
paychainlyPython SDK
Python SDK for the Paychainly platform. Accept USDT on BNB Smart Chain — sync and async clients, typed dataclass models, HMAC webhook verification. Works with Flask, FastAPI, Django, and plain scripts.
Installation
Requires Python 3.10+. Only dependency: httpx.
Setup — Sync (Flask / Django / scripts)
Create one instance and import it everywhere. Use Paychainly for sync apps.
Context manager (recommended — ensures connection pool cleanup):
Setup — Async (FastAPI / async Django)
Use AsyncPaychainly in async frameworks. Identical API — every method is awaitable.
Async context manager:
Integration Patterns
| # | Pattern | Customer | Address | Payment Link | Best For |
|---|---|---|---|---|---|
| 1 | Wallet — address only | Required | reuse — permanent | Not needed | Deposit wallets, top-ups |
| 2 | Wallet — with link | Required | reuse — same | create_for_address() | Fixed-amount top-ups |
| 3 | Order Checkout (logged in) | Required | generate_new | payment_links.create() | E-commerce, invoices |
| 4 | Guest Checkout | Not needed | generate_new | payment_links.create() | One-off, anonymous |
Pattern 1 — Permanent Wallet
Each user gets one permanent deposit address. Same address every time — safe to call on every login.
Pattern 2 — Wallet + Payment Link
Same permanent address, wrapped in a hosted checkout page with a fixed amount and expiry.
Pattern 3 — Order Checkout
Each order gets a fresh deposit address. unique_id is an idempotency key — safe to retry.
Pattern 4 — Guest Checkout
No customer required. Anyone can pay — fully anonymous.
Receiving Payments
Set your webhook URL in the dashboard. Read the raw request body before any JSON parsing — signature verification requires the unmodified bytes.
Flask:
FastAPI (async):
Testing signatures without a real payment:
API Reference
Paychainly (sync) and AsyncPaychainly (async). Async versions return coroutines — prefix with await.@paychainly/cliv1.1.3Relay live Paychainly webhooks to your local server during development — no public URL, no tunneling tool required. Inspect payloads, verify signatures, capture events to disk, and replay them against your handler any time.
Installation
Install globally — one command, no config file needed:
Verify the install:
listen — relay webhooks
Connects to api.paychainly.com over a persistent WebSocket and forwards every webhook event it receives to your local server in real time.
| Flag | Default | Description | |
|---|---|---|---|
| --api-key | required | — | Your Paychainly API key (pk_live_... or pk_test_...) |
| --forward-to | string | localhost:3000/webhook | Full URL of your local webhook endpoint |
| --port | number | 3000 | Shorthand — sets forward-to to http://localhost:<port>/webhook |
| --host | string | https://api.paychainly.com | Override the Paychainly server URL |
| --secret | string | — | Webhook signing secret — enables HMAC-SHA256 signature verification on every event |
| --verbose | flag | — | Pretty-print the full JSON payload for each event |
| --filter | string | — | Only relay events matching this name, e.g. deposit_detected |
| --log | filepath | — | Append every received event to a JSONL file (one JSON per line) |
Examples
Press Ctrl+C to stop. A per-event-type summary is printed on exit.
status — check API key
Validates your API key and confirms the server is reachable. Prints your account email and mode. Exits with code 0 on success, 1 on failure.
Example output:
replay — resend saved events
Reads a JSONL file produced by listen --log and replays each event to your local server. Useful after fixing a bug in your webhook handler — no real payment needed.
| Flag | Default | Description | |
|---|---|---|---|
| --log | required | — | Path to the JSONL file produced by listen --log |
| --forward-to | string | localhost:3000/webhook | Local URL to POST events to |
| --filter | string | — | Only replay events matching this name |
| --delay | ms | 500 | Milliseconds to wait between replayed events |
| --verbose | flag | — | Pretty-print each payload before sending |
Examples
How relay forwarding works
The CLI connects to api.paychainly.com over a persistent WebSocket. When a payment event fires, the server checks whether the CLI is connected and routes accordingly. You do not need a webhook configured in your account for the CLI to receive events.
| Scenario | Webhook configured? | CLI connected? | Result |
|---|---|---|---|
| 1 — CLI only | None | Yes | ✅ Event delivered to CLI → forwarded to --forward-to URL |
| 2 — localhost webhook + CLI | Yes — localhost URL | Yes | ✅ Event delivered through CLI relay (single delivery, no double-send) |
| 3 — public webhook + CLI | Yes — public HTTPS URL | Yes | ✅ Webhook POSTed to public URL AND CLI relay also receives the event |
| 4 — public webhook, no CLI | Yes — public HTTPS URL | No | ✅ Webhook POSTed to public URL only |
| 5 — nothing configured | None | No | ⚠️ Event fires on-chain but nothing receives it — configure a webhook or connect the CLI |
Key rules
- No webhook required — the CLI relay works independently of any webhook URL you have saved in your account.
- No double-send for localhost webhooks — if your saved webhook URL is a
localhostaddress, the server routes through the CLI relay and does not send it a second time. - Public webhook + CLI = both receive — the public URL is called via HTTP and the CLI relay also gets the event so you can inspect it locally.
- Relay uses your
--forward-toflag — the server passes an empty target URL for relay-only deliveries; the CLI falls back to the value you set with--forward-to.
Covered events: deposit_detected, sweep_started/completed/failed/skipped, address_created, withdrawal_*, manual_drain_*
Environment variables
Set these in your shell profile or .env to avoid passing flags every session:
Developer workflow
Typical dev cycle
Use sandbox mode for free end-to-end testing
Webhook event types
| Event | Triggered when | ||
|---|---|---|---|
| deposit_detected | — | A USDT transfer to a monitored deposit address was confirmed on-chain | |
| sweep_completed | — | Funds were swept from the deposit address to your master wallet | |
| address_expired | — | A deposit address session expired without receiving a payment | |
| withdrawal_completed | — | A user-initiated USDT withdrawal was processed successfully |
Use --filter deposit_detected during development to focus on the payment event and reduce noise.
POST your-urlPaychainly sends a signed POST request to your registered webhook URL whenever a key event occurs. All requests use Content-Type: application/json.
deposit_detected
Fired as soon as a USDT transfer to one of your deposit addresses is confirmed on-chain. Use this event to credit the user's balance immediately. The payload includes full customer and payment-link context when available.
Signing string: event|txHash|fromAddress|toAddress|amount|blockNumber|timestamp|userId
deposit_settled
Fired after the full sweep pipeline completes — gas top-up, USDT transfer to your master wallet, and fee deduction. Contains everything from deposit_detected plus a complete fee breakdown and net amount credited to you.
Signing string: event|txHash|fromAddress|toAddress|amount|blockNumber|timestamp|userId
address_created
Fired when a new deposit address is generated for your account — whether via the API, dashboard, or a payment link flow. Useful for syncing your internal records.
withdrawal_completed
Fired when a withdrawal request has been fully processed and the USDT transfer is confirmed on-chain. The payload includes all transaction hashes and the final fee breakdown.
Signing string: Generic format — event|timestamp|{sorted JSON of data}
withdrawal_failed
Fired when a withdrawal request could not be completed after all retry attempts. The failureReason field describes what went wrong. The withdrawal remains in a failed state and can be retried manually from the dashboard.
Signing string: Generic format — event|timestamp|{sorted JSON of data}
Signature Verification
Every webhook includes a signature field — an HMAC-SHA256 hex digest computed over a deterministic signing string using your webhook secret. Always verify this before processing the event.
| Events | Format |
|---|---|
| deposit_detected, deposit_settled | event|txHash|fromAddress|toAddress|amount|blockNumber|timestamp|userId |
| all other events | event|timestamp|{sorted JSON of data} |