# ZyndPay — Full LLM Reference > ZyndPay is a crypto payment gateway for accepting and sending USDT TRC20 payments on the TRON blockchain. It provides a developer-friendly REST API modeled after Stripe, with hosted checkout pages at checkout.zyndpay.io, shareable pay links, signed webhooks, a full sandbox environment, and team management. This file is the complete reference for AI assistants helping developers integrate ZyndPay. --- ## Table of Contents 1. Core Concepts 2. Authentication & API Keys 3. Payin (Receiving Payments) 4. Paylinks (Shareable Payment Pages) 5. Payout (Sending Payments) 6. Withdrawals (Withdraw Balance) 7. Webhooks 8. Sandbox 9. SDKs (Node.js, Python, PHP) 10. Error Reference 11. Fee Structure --- ## 1. Core Concepts ### What ZyndPay Does ZyndPay is a B2B crypto payment infrastructure provider. Merchants integrate ZyndPay to: - Accept USDT TRC20 payments from their customers (payins) - Send USDT TRC20 payouts to any wallet (payouts) - Withdraw their balance to whitelisted addresses (withdrawals) - Create shareable pay links for products, subscriptions, and donations - Automate payment flows via webhooks ### Supported Currency - **Currency**: USDT_TRC20 (Tether USD on the TRON blockchain) - **Chain**: TRON ### Base URL ``` https://api.zyndpay.io/v1 ``` --- ## 2. Authentication & API Keys Include your API key in the `X-Api-Key` header: ```bash curl https://api.zyndpay.io/v1/payments \ -H "X-Api-Key: zyp_live_sk_..." ``` | Prefix | Type | Description | |--------|------|-------------| | `zyp_live_sk_` | Live secret | Full API access. Never expose client-side. | | `zyp_live_pk_` | Live publishable | Read-only, client-safe. | | `zyp_test_sk_` | Sandbox secret | Identical to live but no real transactions. | | `zyp_test_pk_` | Sandbox publishable | Read-only sandbox. | | `zyp_rk_` | Restricted | Custom scopes only. | --- ## 3. Payin (Receiving Payments) ### Create a Payin `POST /v1/payments` Generates a unique TRON wallet address for your customer to send USDT to. The address expires after expiresInSeconds seconds (default 30 minutes). **Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | amount | string | Yes | Amount in USDT as a decimal string (e.g. "100.00"). Minimum: "1.00". | | externalRef | string | No | Your order or reference ID (optional). Must be unique per merchant if provided. | | expiresInSeconds | integer | No | Seconds until the address expires. Minimum: 900. Default: 1800 (30 minutes). | | successUrl | string | No | URL to redirect the customer after a successful payment. | | cancelUrl | string | No | URL to redirect the customer if the payment expires or is cancelled. | | metadata | object | No | Arbitrary key-value pairs stored with the payment and included in webhooks. | ```bash curl -X POST https://api.zyndpay.io/v1/payments \ -H "X-Api-Key: zyp_live_sk_..." \ -H "Content-Type: application/json" \ -d '{ "amount": "100.00", "externalRef": "order_123", "expiresInSeconds": 3600, "successUrl": "https://yoursite.com/payment/success", "cancelUrl": "https://yoursite.com/payment/cancel" }' ``` ```json { "success": true, "data": { "transactionId": "pay_abc123...", "address": "TRXabc123def456ghi789jkl", "paymentUrl": "https://checkout.zyndpay.io/pay_abc123...", "qrCodeUrl": "data:image/png;base64,iVBOR...", "amount": "100.00", "amountExpected": "101.00", "networkFee": "1", "currency": "USDT_TRC20", "chain": "TRON", "status": "AWAITING_PAYMENT", "expiresAt": "2026-03-06T12:00:00.000Z" } } ``` ### Get a Payin `GET /v1/payments/:id` ```json { "success": true, "data": { "id": "f4b2cb0f-08ce-4408-88d4-0a678ca0aae2", "address": "TRXabc123def456ghi789jkl", "amount": "100", "amountReceived": "100.00", "zyndpayFee": "1.00", "status": "CONFIRMED", "txHash": "abc123def456...", "externalRef": "order_123", "currency": "USDT_TRC20", "chain": "TRON", "paymentUrl": "https://checkout.zyndpay.io/f4b2cb0f...", "isSandbox": false, "createdAt": "2026-03-06T11:00:00.000Z", "updatedAt": "2026-03-06T11:01:02.000Z" } } ``` **Statuses:** PENDING, CONFIRMING, CONFIRMED, UNDERPAID, OVERPAID, EXPIRED ### List Payins `GET /v1/payments` Query: `page`, `limit`, `status`, `currency` --- ## 4. Paylinks (Shareable Payment Pages) ### Create a Paylink `POST /v1/paylinks` ```bash curl -X POST https://api.zyndpay.io/v1/paylinks \ -H "X-Api-Key: zyp_live_sk_..." \ -H "Content-Type: application/json" \ -d '{ "type": "FIXED", "products": [ { "name": "Premium Course", "price": "49.99", "productType": "DIGITAL", "digitalUrl": "https://drive.google.com/file/d/abc123" } ], "collectEmail": "REQUIRED", "brandColor": "#635BFF" }' ``` ```json { "success": true, "data": { "id": "pl_cma1xyz8f0001yx5k", "slug": "aB3dE6fG7hI9", "type": "FIXED", "status": "ACTIVE", "paymentUrl": "https://dashboard.zyndpay.io/pay/link/aB3dE6fG7hI9", "products": [ { "id": "prod_abc123", "name": "Premium Course", "price": "49.990000000000000000", "productType": "DIGITAL", "digitalUrl": "https://drive.google.com/file/d/abc123" } ], "createdAt": "2026-03-08T10:00:00.000Z" } } ``` ### Checkout via Paylink `POST /v1/pay/link/:slug/checkout` ```bash curl -X POST https://api.zyndpay.io/v1/pay/link/aB3dE6fG7hI9/checkout \ -H "Content-Type: application/json" \ -d '{ "items": [ { "productId": "prod_abc123", "quantity": 1 } ], "customerEmail": "buyer@example.com", "customerName": "John Doe" }' ``` --- ## 5. Payout (Sending Payments) ### Create a Payout `POST /v1/payout` Supports `Idempotency-Key` header to prevent duplicate payouts. ```bash curl -X POST https://api.zyndpay.io/v1/payout \ -H "X-Api-Key: zyp_live_sk_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -d '{ "amount": "50.00", "destinationAddress": "TXYZabc123def456ghi789jkl012mno345", "externalRef": "payout_vendor_456" }' ``` ```json { "success": true, "data": { "transactionId": "cma2abc9g0002yz6l0def5678", "status": "PROCESSING", "processingFee": "1.50", "requiresManualApproval": false, "currentPayinFee": "1%", "currentTier": "flat" } } ``` **Statuses:** PENDING, PROCESSING, BROADCAST, CONFIRMED, FAILED, CANCELLED --- ## 6. Withdrawals (Withdraw Balance) ### Request a Withdrawal `POST /v1/withdrawals` Withdrawals go to your whitelisted TRON addresses only. ```bash curl -X POST https://api.zyndpay.io/v1/withdrawals \ -H "X-Api-Key: zyp_live_sk_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -d '{ "amount": "500.00", "whitelistAddressId": "addr_cma1xyz8f0001yx5k" }' ``` ```json { "success": true, "data": { "id": "wdr_cma1xyz8f0001yx5k", "amount": "500.00", "fee": "5.00", "netAmount": "495.00", "destinationAddress": "TRXabc123def456ghi789jkl", "status": "PENDING", "createdAt": "2026-03-06T11:00:00.000Z" } } ``` **Statuses:** PENDING_REVIEW, APPROVED, BROADCAST, CONFIRMED, REJECTED, FAILED, CANCELLED ### Cancel a Withdrawal `DELETE /v1/withdrawals/:id` — Only works for PENDING_REVIEW withdrawals. --- ## 7. Webhooks ZyndPay sends signed POST requests to your registered endpoint. ### Payload Example ```json { "event": "payin.confirmed", "data": { "transactionId": "cma1xyz8f0001yx5k9abc1234", "status": "CONFIRMED", "currency": "USDT_TRC20", "chain": "TRON", "externalRef": "order_123", "amount": "100.00", "amountRequested": "100.00", "txHash": "abc123def456...", "confirmedAt": "2026-03-06T11:01:02.000Z" }, "createdAt": "2026-03-06T11:01:03.000Z" } ``` ### Signature Verification (Node.js) ```javascript const crypto = require('crypto'); app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-zyndpay-signature']; const [tPart, v1Part] = sig.split(','); const timestamp = tPart.split('=')[1]; const received = v1Part.split('=')[1]; // Reject events older than 5 minutes const age = Math.abs(Date.now() / 1000 - parseInt(timestamp)); if (age > 300) return res.status(400).send('Webhook too old'); const expected = crypto .createHmac('sha256', process.env.WEBHOOK_SECRET) .update(`${timestamp}.${req.body}`) .digest('hex'); // Use timing-safe comparison to prevent timing attacks if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) { return res.status(400).send('Invalid signature'); } const event = JSON.parse(req.body); // Handle event... res.json({ received: true }); }); ``` ### Signature Verification (Python) ```python import hmac, hashlib, time def verify_webhook(payload: bytes, sig_header: str, secret: str) -> bool: parts = dict(p.split("=", 1) for p in sig_header.split(",")) timestamp = parts["t"] received = parts["v1"] # Reject events older than 5 minutes if abs(time.time() - int(timestamp)) > 300: return False expected = hmac.new( secret.encode(), f"{timestamp}.{payload.decode()}".encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, received) ``` ### All Webhook Events | Event | Description | |-------|-------------| | payin.created | Payment request created, awaiting funds | | payin.confirming | Funds detected, awaiting confirmations | | payin.confirmed | Payment confirmed, balance credited | | payin.expired | Payment window expired | | payin.underpaid | Less than expected received | | payin.overpaid | More than expected received | | payin.failed | Processing error | | deposit.confirmed | Direct deposit confirmed | | payout.broadcast | Payout submitted to TRON | | payout.confirmed | Payout confirmed on-chain | | payout.failed | Payout failed, refunded | | withdrawal.requested | Withdrawal created | | withdrawal.approved | Withdrawal approved | | withdrawal.broadcast | Withdrawal submitted to TRON | | withdrawal.confirmed | Withdrawal confirmed on-chain | | withdrawal.failed | Withdrawal failed, refunded | | aml.flagged | Transaction blocked by AML | | kyb.approved | KYB application approved | | kyb.rejected | KYB application rejected | --- ## 8. Sandbox Create sandbox payments with `?sandbox=true` and simulate confirmation: ```bash curl -X POST \ https://api.zyndpay.io/v1/sandbox/payments/{id}/simulate \ -H "X-Api-Key: zyp_test_sk_..." ``` --- ## 9. SDKs ### Node.js SDK ```bash npm install @zyndpay/sdk ``` ```javascript const { ZyndPay } = require('@zyndpay/sdk'); const client = new ZyndPay({ apiKey: 'zyp_live_sk_...', webhookSecret: process.env.ZYNDPAY_WEBHOOK_SECRET, }); // Create a payment const payment = await client.payins.create({ amount: '100.00', externalRef: 'order_123', }); console.log(payment.address); // Verify a webhook (uses raw body, not parsed JSON) const event = client.webhooks.verify( rawBody, req.headers['x-zyndpay-signature'] ); ``` ### Python SDK ```bash pip install zyndpay ``` ```python from zyndpay import ZyndPay client = ZyndPay( api_key="zyp_live_sk_...", webhook_secret=os.environ.get("ZYNDPAY_WEBHOOK_SECRET"), ) payment = client.payins.create( amount="100.00", external_ref="order_123" ) print(payment["address"]) ``` ### PHP SDK ```bash composer require zyndpay/zyndpay-php ``` ```php getenv('ZYNDPAY_WEBHOOK_SECRET'), ]); // Create a payment $payment = $client->payins->create([ 'amount' => '100.00', 'externalRef' => 'order_123', ]); echo $payment['address']; // Verify a webhook $event = $client->webhooks->verify( $rawBody, $_SERVER['HTTP_X_ZYNDPAY_SIGNATURE'] ); ``` --- ## 10. Error Reference ```json { "success": false, "error": { "code": "AMOUNT_TOO_LOW", "message": "Minimum payin amount is 1 USDT" }, "statusCode": 400 } ``` | Code | Status | Description | |------|--------|-------------| | UNAUTHORIZED | 401 | API key is missing or invalid. | | FORBIDDEN | 403 | API key does not have the required scope. | | NOT_FOUND | 404 | The requested resource does not exist. | | AMOUNT_TOO_LOW | 400 | Payin amount is below the 1 USDT minimum. | | EXTERNAL_REF_TAKEN | 409 | A payin with this externalRef already exists for your account. | | INSUFFICIENT_BALANCE | 402 | Your balance is too low for the requested withdrawal amount. | | ADDRESS_NOT_FOUND | 404 | The whitelistAddressId does not match any saved withdrawal address on your account. | | IDEMPOTENCY_CONFLICT | 409 | Idempotency key reused with different request parameters. | | RATE_LIMITED | 429 | Too many requests. Retry after the Retry-After header value. | | INTERNAL_ERROR | 500 | Unexpected server error. Contact support if it persists. | --- ## 11. Fee Structure | Operation | Formula | |-----------|---------| | Payin | `amount x 1%` (merchant pays commission only) | | Network fee | $1.00 added to amountExpected (customer pays) | | Payout | `clamp(amount x 1%, $1.50 min, $5 max)` | | Withdrawal | `max(amount x 1%, $1.50 min)` | --- ## Links - Full API reference: https://zyndpay.io/docs - Dashboard: https://dashboard.zyndpay.io - Support: support@zyndpay.io