PolyPay
Intermediate15 min read

API Key Mode - HTTP API Integration

Use an API Key from your server to access merchant business APIs, including orders, wallets, notifications, and merchant configuration. Account profile and login-security APIs continue to require JWT.

Get Your API Key

  1. Log in to PolyPay merchant dashboard
  2. Go to "API Keys" page
  3. Click "Create Key"
  4. Choose an expiration time. New API Keys expire after 7 days by default. If you choose never expires, the API Key will not expire automatically; existing API Keys never expire by default.
  5. Securely save the generated API Key

⚠️ API Key is only shown once. Save it immediately! If lost, you need to regenerate. Never expose API Key in frontend code, Git repos, or logs.

Plan Quotas and Billing Scope

  • Subscription plans apply per merchant. Monthly successful orders, wallet addresses, notification quotas, and available channels are isolated for each merchant; switching merchants neither inherits nor consumes another merchant plan.
  • See the public pricing page. PolyPay does not take a cut of payments; you pay for plan quotas and metered usage.
  • The first merchant created under an account keeps the Free live-payment entitlement; disabling another merchant does not transfer it. Additional merchants need Pay-as-you-go, Pro, or Business enabled before they can create live orders or Checkout.
  • Account balance is stored per user and split into paid balance and bonus credit; bonus credit is spent first. Mixed subscription checkout reserves the available balance and sends the remainder to crypto checkout, releasing the hold on failure or expiry. Below Available Plans, the paginated balance records include recharge and consumption ledger entries plus pending, completed, or rejected withdrawal requests with their status.
  • Both paid and bonus balances can be withdrawn as USDT. The receiving address can be selected from the current merchant’s enabled, network-matched wallets that support USDT, or entered manually. The backend prices the fee from the selected network’s live fast rate plus a 20% volatility buffer, reprices it on submission, and freezes it with the withdrawal amount using bonus balance first. The backend never initiates an on-chain payout; operations completes the debit or restores the original balance buckets from the bot message.
  • Paid recurring plans such as Pro and Business can enable balance auto-renewal independently per merchant. At expiry, PolyPay deducts that merchant’s next cycle from the shared account balance; insufficient balance leaves only that merchant’s plan expired.
  • Pay-as-you-go is enabled independently per merchant. That merchant’s orders, notifications, and wallet addresses are charged from the shared account balance from the first usage, without enabling it for other merchants.
  • Payment Webhook callbacks are used for order status synchronization and do not count toward external alert notification quota.
  • Telegram, Email, WhatsApp, notification Webhook, WeCom, Discord, and other business alerts count toward the current merchant’s plan quota; in-app notifications and system subscription expiry notices do not.
  • Subscription expiring and expired notices are sent by PolyPay with fixed system copy and cannot be customized in notification templates.
  • Custom Domain and AI Agent Payments require an active subscription, and are also available on Pay-as-you-go. When a subscription expires or becomes inactive, configurations are retained but frozen: they cannot be managed, the custom domain hostname is removed from PolyPay Cloudflare routing while your DNS record can stay in place, and x402 verify/settle runtime calls are rejected until an active subscription is restored. After restoration, PolyPay recreates the custom hostname automatically.

API Reference

Basic Information

SDK-compatible Base URLhttps://api.polypay.ai/api/v1/pay/sdk
Merchant API Base URLhttps://api.polypay.ai/api/v1/pay
AuthenticationX-API-Key (recommended) or Bearer Token (legacy-compatible)
Data FormatJSON

Authentication

Merchant business APIs accept either a dashboard JWT or an API Key. For server-side API Key calls, use either header below; X-API-Key is explicit and recommended:

HeaderValue
X-API-KeyYOUR_API_KEY (recommended)
AuthorizationBearer YOUR_API_KEY (legacy-compatible)
Content-Typeapplication/json

Redirect to Hosted Checkout

If you want PolyPay to show payment-method selection, request the checkout_url below with your API Key and redirect the customer to it. Without currency/network, PolyPay creates a Method pending order. The payment URL itself is the complete public payment entry; the client does not need to store a checkout session. The page may submit only currency and network, while amount, merchant order ID, and callback URLs are always read from the stored order. The URL uses /pay/{trade_id}, and selecting or changing a payment method preserves that trade_id and URL. Supplying both currency and network skips selection and opens the payment page directly. After expiry, request a new checkout_url with the same merchant order ID.

POST /order/checkout

curl -X POST https://api.polypay.ai/api/v1/pay/sdk/order/checkout \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "mch_order_id": "ORDER_001",
    "amount": 10.00,
    "notify_url": "https://your-site.com/webhook",
    "redirect_url": "https://your-site.com/success",
    "locale": "en"
  }'

Response example:

{
  "code": 0,
  "message": "",
  "data": {
    "checkout_url": "https://checkout.polypay.ai/en/pay/202607311785497228532519443",
    "payment_url": "https://checkout.polypay.ai/en/pay/202607311785497228532519443"
  }
}

Create Order

POST /order/add

Request Parameters

ParameterTypeRequiredDescription
currencystringCurrency (USDT/USDC/BUSD)
networkstringNetwork (tron/ethereum/bsc/polygon/solana)
amountnumberAmount
mch_order_idstringMerchant order ID (max 32 chars, auto-generated if not provided)
notify_urlstringWebhook callback URL
redirect_urlstringRedirect URL after payment

Response Parameters

ParameterTypeDescription
trade_idstringPolyPay transaction ID
currencystringCurrency
networkstringBlockchain network
amountnumberOrder amount
actual_amountnumberActual payment amount (4 decimals)
addressstringPayment wallet address
expiration_timenumberExpiration timestamp (seconds)
payment_urlstringPayment page URL

Code Examples

curl -X POST https://api.polypay.ai/api/v1/pay/sdk/order/add \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USDT",
    "network": "tron",
    "amount": 100.00,
    "mch_order_id": "ORDER_123456",
    "notify_url": "https://your-site.com/webhook",
    "redirect_url": "https://your-site.com/success"
  }'

Response Example

{
  "code": 0,
  "message": "success",
  "data": {
    "trade_id": "PP202412110001",
    "currency": "USDT",
    "network": "tron",
    "amount": 100.00,
    "actual_amount": 100.0001,
    "address": "TXxx...xxx",
    "expiration_time": 1704067200,
    "payment_url": "https://checkout.polypay.ai/status/PP202412110001"
  }
}

Query Order

POST /order/detail

Request Parameters

ParameterTypeRequiredDescription
trade_idstring*PolyPay transaction ID
mch_order_idstring*Merchant order ID

* Either trade_id or mch_order_id is required

Response Example

curl -X POST https://api.polypay.ai/api/v1/pay/sdk/order/detail \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "trade_id": "PP202412110001"
  }'

Cancel Order

POST /order/cancel-by-trade-id

When your platform cancels, voids, or replaces an unpaid order, synchronize the cancellation with PolyPay. A successful cancellation immediately releases the reserved receiving-address and payable-amount pair, preventing a later same-amount order from being adjusted because of the stale reservation (commonly by 0.01 for stablecoins). The request is safe to retry; paid or expired orders cannot be cancelled.

curl -X POST https://api.polypay.ai/api/v1/pay/order/cancel-by-trade-id \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "trade_id": "PP202412110001"
  }'

Webhook Callbacks

We send HTTP POST requests to your configured Webhook URL when an order is created and when its status changes.

Webhook Payload Example

{
  "order_no": "ORDER_123456",
  "status": 2,
  "amount": 100.0001,
  "currency": "USDT",
  "currency_name": "usdt",
  "network": "Tron",
  "contract_addr": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "hash": "abc123...",
  "wallet_address": "TXxx...xxx",
  "environment": "production",
  "event_id": "evt_xxx"
}

network is the payment chain; currency_name is the lowercase currency name such as usdt/usdc; hash is the on-chain transaction hash. contract_addr is an empty string for native assets or assets without a configured contract.

Status Types

status ValueDescription
1Pending payment
2Payment successful
3Order expired
4Order cancelled
5Manual recharge (handled as paid)
6On-chain confirming (treated as pending for merchants; no paid webhook is sent)
7Marked paid (handled as paid)

Verify Webhook v2 Signature

Webhook v2 uses a PolyPay platform Ed25519 signing key and does not depend on the merchant API Key. Verify the raw request body on your server with the public key obtained from the platform JWKS.

Verification Flow (Server-side)

  1. Require X-Webhook-Signature-Version to be v2 and read the key ID, merchant ID, environment, timestamp, nonce, and v2 signature headers.
  2. Require the merchant ID and environment to match server-side expectations and enforce a 300-second timestamp window.
  3. Select the Ed25519 public key by key ID from /api/v1/pay/public/webhook-jwks and verify the signature over the raw request body.
  4. Atomically consume the nonce in shared storage such as Redis and reject replays.
  5. Parse the event only after successful verification and process it idempotently by environment and event_id.
<?php
use PolyPay\PolyPay;
use PolyPay\WebhookHandler;
use PolyPay\Exception\SignatureException;

$polypay = new PolyPay(getenv('POLYPAY_API_KEY') ?: '');

try {
    $event = $polypay
        ->webhookV2('MCH_YOUR_ID', 'production')
        ->handle();

    $status = WebhookHandler::resolveStatus($event);
    if ($status === 'paid') {
        handleOrderPaidIdempotently($event);
    }

    http_response_code(200);
    echo 'OK';
} catch (SignatureException $e) {
    http_response_code($e->getHttpStatus());
    echo 'Unauthorized';
}

For the complete header contract, signed payload, and Node.js example, see Webhook Security.

Error Codes

CodeDescription
0Success
10001Invalid parameters
10002Invalid signature
10003Order not found
10004Merchant disabled
10005Invalid API Key

Security Best Practices

  • Protect API Key: Never expose API Key in frontend code, Git repos, or logs
  • Use Environment Variables: Store API Key in environment variables
  • Verify Webhook Signatures: Always verify Webhook request signatures
  • Use HTTPS: Ensure your Webhook endpoint uses HTTPS
  • Implement Idempotency: Webhooks may be sent multiple times, ensure idempotent logic

Rate limits and safe retries

When a request exceeds its current policy, PolyPay returns a real HTTP 429. Application responses use error code 40001; a CDN or WAF may instead return HTML or plain text, so clients must check HTTP status before parsing by Content-Type.

HTTP/1.1 429 Too Many Requests
Retry-After: 10
RateLimit-Limit: 60
RateLimit-Remaining: 0
RateLimit-Reset: 10

{"code":40001,"message":"RateLimitExceeded","data":{"retry_after":10}}

Honor Retry-After first; it may be seconds or an HTTP-date. If absent, use jittered exponential backoff. Automatically retry only replay-safe or idempotency-protected requests, with a bounded retry count.

When retrying API Key writes such as order creation, reuse the original merchant order ID or idempotency key. Do not generate a new identifier for every retry.