C
CryptoPAY API

CryptoPAY Merchant API

Accept USDT TRC-20 payments on your platform. Fast integration, real-time blockchain confirmation, automatic webhook notifications.

Base URL: https://cryptopay.webprompt.icu
All API requests use HTTPS. HTTP requests are redirected.

How it works

1. Create order
2. Redirect to payment page
3. User pays USDT
4. Blockchain confirms
5. Webhook callback

Authentication

Every API request must include your api_key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

You receive your api_key and api_secret after your merchant account is approved by the platform administrator. Find them in your Merchant Dashboard → API Keys.

Keep your api_secret private. Never expose it in client-side code, mobile apps, or public repositories. All API calls must be made from your backend server.

Supported Currencies

CryptoPAY accepts payments in fiat currencies and converts them to USDT TRC-20 at the current market rate.

CodeCurrencyMin AmountRate SourceNotes
RUB Russian Ruble 1 ₽ CoinMarketCap (live, updated every 60s) Default. Rate markup may apply per merchant.
USD US Dollar 1 $ CoinMarketCap (live, ≈1.00) No rate markup. USDT ≈ USD.
How to use: Pass "currency": "RUB" or "currency": "USD" in the request body. If omitted, defaults to RUB. The amount field is always in the specified fiat currency — the system calculates the USDT equivalent automatically.

Rate calculation

// Example: 1000 RUB order at rate 83.21 RUB/USDT
actual_usdt = 1000 / 83.21 = 12.0178 USDT

// Example: 50 USD order at rate ~1.00 USD/USDT
actual_usdt = 50 / 1.00 = 50.0000 USDT

// The rate_used field in the response shows the exact rate applied.
// Max order: 10,000 USDT equivalent (configurable by platform admin).

Request Signing (HMAC-SHA256)

Every POST request body must include a sign field. This prevents request tampering and proves your identity.

1

Collect fields

Take all request body fields except sign.

2

Sort alphabetically

Sort field names by ASCII value (A-Z, a-z).

3

Concatenate

Join as key1=value1&key2=value2&...

4

HMAC-SHA256

Compute HMAC-SHA256 of the string using your api_secret as the key. The result (lowercase hex) is your sign value.

Signing example

Given these fields and api_secret = "abc123secret":

// Input fields (excluding "sign"):
order_id = "ORDER-001"
amount = 1000
currency = "RUB"
notify_url = "https://example.com/callback"

// Step 2: Sort by key name
amount, currency, notify_url, order_id

// Step 3: Concatenate
"amount=1000¤cy=RUB¬ify_url=https://example.com/callback&order_id=ORDER-001"

// Step 4: HMAC-SHA256 with api_secret
sign = hmac_sha256("amount=1000¤cy=RUB¬ify_url=https://example.com/callback&order_id=ORDER-001", "abc123secret")
// → "e5f3a1b2c4d6..."

Integration Flow

1

Create an order

Call POST /api/v1/orders/create from your backend with the payment amount and your webhook URL.

2

Redirect the user

Redirect the user to the payment_url from the response. They'll see a checkout page with a QR code, wallet address, and countdown timer.

3

Receive the webhook

When payment is confirmed on the TRON blockchain (~5 seconds), we POST to your notify_url. Verify the sign field and respond with HTTP 200.

4

Fulfill the order

Mark the order as paid in your system. The user is automatically redirected to your redirect_url.

Create Order

Create a new payment order. Returns a payment URL to redirect the user to.

POST /api/v1/orders/create

Request body

FieldTypeRequiredDescription
order_idstringrequiredYour unique order identifier (max 100 chars)
amountnumberrequiredPayment amount in fiat currency (min 1 RUB / 1 USD)
currencystringoptional"RUB" (default) or "USD". See Currencies.
notify_urlstringoptionalWebhook URL for payment notifications (HTTPS required)
redirect_urlstringoptionalURL to redirect user after payment
signstringrequiredHMAC-SHA256 signature

Response

FieldTypeDescription
trade_idstringCryptoPAY unique payment ID
order_idstringYour order ID (echoed back)
amountnumberOriginal fiat amount
actual_amountnumberUSDT amount to be paid (4 decimal places)
currencystringCurrency code
rate_usednumberExchange rate applied (fiat/USDT)
tokenstringTRON wallet address for payment
expiration_timeintegerUnix timestamp when order expires
payment_urlstringRedirect user here to pay

Code examples

curl -X POST https://cryptopay.webprompt.icu/api/v1/orders/create \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "ORDER-001",
    "amount": 1000.00,
    "currency": "RUB",
    "notify_url": "https://yoursite.com/webhook",
    "redirect_url": "https://yoursite.com/success",
    "sign": "COMPUTED_HMAC_SHA256_HEX"
  }'

Response example

{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260322a1b2c3d4e5f67890",
    "order_id": "ORDER-001",
    "amount": 1000.00,
    "actual_amount": 12.0758,
    "currency": "RUB",
    "rate_used": 82.81,
    "token": "TN4JsVEyUBMcBjJbRGTriAPBDMjZaxnMet",
    "expiration_time": 1774131385,
    "payment_url": "https://cryptopay.webprompt.icu/pay/checkout-counter/20260322a1b2c3d4e5f67890"
  },
  "request_id": "req_abc123"
}

Cancel Order

Cancel a pending (unpaid) order. Only orders with status 0 (Awaiting) can be cancelled.

POST /api/v1/orders/cancel

Request body

FieldTypeRequiredDescription
trade_idstringrequiredCryptoPAY trade ID from create response
signstringrequiredHMAC-SHA256 signature
curl -X POST https://cryptopay.webprompt.icu/api/v1/orders/cancel \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"trade_id": "20260322a1b2c3d4e5f67890", "sign": "HMAC_HEX"}'

Query Order

Retrieve the current status and details of an order.

GET /api/v1/orders/query/{trade_id}
curl https://cryptopay.webprompt.icu/api/v1/orders/query/20260322a1b2c3d4e5f67890 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response example

{
  "status_code": 200,
  "data": {
    "trade_id": "20260322a1b2c3d4e5f67890",
    "order_id": "ORDER-001",
    "amount": 1000.00,
    "actual_amount": 12.0758,
    "currency": "RUB",
    "rate_used": 82.81,
    "token": "TN4JsVEyUBMcBjJbRGTriAPBDMjZaxnMet",
    "status": 1,
    "block_transaction_id": "7f3a2b1c...",
    "callback_status": 1,
    "commission": 0.2415,
    "net_amount": 11.8343,
    "created_at": "2026-03-22T12:00:00Z",
    "paid_at": "2026-03-22T12:03:45Z",
    "expiration_time": null,
    "callback_payload": { "..." }
  }
}

Payment Status (Polling)

Lightweight endpoint to check if a payment has been received. Useful for frontend polling while the user is on the checkout page. No authentication required.

GET /pay/status/{trade_id}
// Response
{"status_code": 200, "data": {"status": 1}}
Rate limited to 60 requests/minute per IP. The checkout page already polls this automatically — you don't need to implement polling yourself unless building a custom checkout UI.

Webhook Callback

When a payment is confirmed on the TRON blockchain, CryptoPAY sends a POST request to your notify_url with the payment details.

Callback payload

{
  "trade_id": "20260322a1b2c3d4e5f67890",
  "order_id": "ORDER-001",
  "amount": 1000.00,
  "actual_amount": 12.0758,
  "currency": "RUB",
  "rate_used": 82.81,
  "token": "TN4JsVEyUBMcBjJbRGTriAPBDMjZaxnMet",
  "block_transaction_id": "7f3a2b1c4d5e6f7890abcdef...",
  "status": 1,
  "sign": "a3f2b1c4d5e6f7890123456789abcdef..."
}
FieldTypeDescription
trade_idstringCryptoPAY payment ID
order_idstringYour order ID
amountnumberOriginal fiat amount
actual_amountnumberUSDT amount received
currencystringCurrency code
rate_usednumberExchange rate used
tokenstringTRON wallet that received payment
block_transaction_idstringTRON blockchain transaction hash
statusintegerAlways 1 (Paid)
signstringHMAC-SHA256 signature — verify this!
Return HTTP 200 to acknowledge receipt. Any other status code triggers a retry. Your balance is credited only after successful acknowledgment.

Verifying Webhook Signatures

Always verify the sign field in webhook callbacks to ensure the request is authentic.

# Flask example
from flask import Flask, request, jsonify
import hmac, hashlib

app = Flask(__name__)
API_SECRET = "your_api_secret"

def verify_sign(payload: dict, secret: str) -> bool:
    received_sign = payload.pop("sign", "")
    sorted_str = "&".join(f"{k}={v}" for k, v in sorted(payload.items()))
    expected = hmac.new(secret.encode(), sorted_str.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(received_sign, expected)

@app.route("/webhook", methods=["POST"])
def webhook():
    data = request.json

    if not verify_sign(dict(data), API_SECRET):
        return "Invalid signature", 403

    trade_id = data["trade_id"]
    order_id = data["order_id"]
    amount_usdt = data["actual_amount"]

    # ✅ Mark order as paid in your database
    print(f"Payment confirmed: {order_id} — {amount_usdt} USDT")

    return "ok", 200  # Must return 200!

Retry Policy

If your server doesn't respond with HTTP 200, we retry with exponential backoff:

AttemptDelayTotal elapsed
1stImmediate0 min
2nd1 minute1 min
3rd2 minutes3 min
4th5 minutes8 min
5th10 minutes18 min
6th15 minutes33 min
7th (final)30 minutes~63 min

After 7 failed attempts, the callback is marked as failed. You can still query the order status via the API. The platform administrator can also trigger a new retry cycle from the admin panel.

Order & Callback Statuses

Order status

ValueNameDescription
0AwaitingOrder created, waiting for USDT payment
1PaidPayment confirmed on TRON blockchain
2ExpiredOrder expired (default: 20 minutes)
3CancelledCancelled by merchant via API

Callback status

ValueNameDescription
0PendingNot yet attempted
1DeliveredMerchant returned HTTP 200
2RetryingDelivery in progress (retry cycle)
3FailedAll 7 attempts exhausted

Error Codes

CodeNameDescription
10001INVALID_REQUESTMissing or invalid request parameters
10002UNAUTHORIZEDInvalid API key or signature
10003MERCHANT_SUSPENDEDYour account has been suspended
10004ORDER_ALREADY_EXISTSDuplicate order_id for this merchant
10005PAY_AMOUNT_TOO_SMALLAmount below minimum (1 RUB / 1 USD)
10006PAY_AMOUNT_TOO_LARGEAmount exceeds maximum (10,000 USDT equivalent)
10007RATE_NOT_AVAILABLEExchange rate temporarily unavailable
10008ORDER_NOT_CANCELLABLEOrder is not in Awaiting status
10009NOT_AVAILABLE_AMOUNTNo payment slot available (all amounts taken)
10010NOT_AVAILABLE_WALLETNo wallet address available
10011INSUFFICIENT_BALANCENot enough balance for withdrawal
10012ORDER_NOT_FOUNDOrder doesn't exist or belongs to another merchant
10013ACCOUNT_PENDINGAccount pending admin approval
10014ACCOUNT_REJECTEDAccount registration was rejected
10015TWO_FACTOR_REQUIRED2FA verification needed

Error response format

{
  "status_code": 10004,
  "message": "order_id already exists for this merchant",
  "data": null,
  "request_id": "req_abc123"
}

Rate Limits

EndpointLimitScope
POST /api/v1/orders/create100 req/minPer API key
POST /api/v1/orders/create1,000 req/minGlobal (all merchants)
All /api/v1/* endpoints300 req/minPer API key
GET /pay/status/*60 req/minPer IP address

When rate limited, the API returns HTTP 429 (Too Many Requests).

Best Practices

Always verify webhook signatures

Use constant-time comparison (hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js) to prevent timing attacks.

Make your webhook handler idempotent

We may send the same callback multiple times. Check if the order is already fulfilled before processing. Use trade_id as the idempotency key.

Respond to webhooks quickly

Return HTTP 200 within 30 seconds. Do heavy processing asynchronously after acknowledging.

Use unique order_ids

Each order_id must be unique per merchant. Reusing an order_id returns error 10004.

Handle order expiration

Orders expire after 20 minutes by default. If the user doesn't pay in time, create a new order.

Keep your API secret secure

Store it in environment variables or a secrets manager. Rotate via the merchant dashboard if compromised.

CryptoPAY API Documentation · USDT TRC-20 Payment Gateway