API Documentation

Everything you need to integrate crypto payment infrastructure into your website.

Quick Start

Accepting crypto payments with RevionPay is completed in 3 steps:

1

Create an API Key

Go to the Settings page and create an API key. The key is shown only once — store it securely.

2

Create a Payment

Use your API key to send a request to the POST /api/v1/payments endpoint to create a payment.

3

Receive the Result via Webhook

Set up a webhook URL in Settings to receive instant payment status updates.

Base URL

https://www.revionpay.com/api/v1

Authentication

All payment API requests are authenticated using the x-api-key header. You can create your API key from the Settings page.

Important Security Notes

  • The API key is shown only once when created
  • Never use the key in client-side code (frontend, mobile app)
  • Store the key as an environment variable
  • If a key is compromised, revoke it immediately and create a new one

Example request:

bash
curl -X POST https://www.revionpay.com/api/v1/payments \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_YOUR_API_KEY_HERE" \
  -d '{"amount": "29.99", "network": "BTC", "fiatCurrency": "USD"}'

Supported Networks

RevionPay supports 12 cryptocurrencies across multiple blockchains. Use the network value when creating payments.

Network ValueCoinBlockchainType
BTCBitcoinBitcoinNative
ETHEtherEthereumNative
LTCLitecoinLitecoinNative
DOGEDogecoinDogecoinNative
TRXTRXTronNative
BNBBNBBNB ChainNative
USDTTether (USDT)TronTRC-20 Token
USDCUSD Coin (USDC)TronTRC-20 Token
ETH_USDTTether (USDT)EthereumERC-20 Token
ETH_USDCUSD Coin (USDC)EthereumERC-20 Token
BNB_USDTTether (USDT)BNB ChainBEP-20 Token
BNB_USDCUSD Coin (USDC)BNB ChainBEP-20 Token

Stablecoins on Multiple Chains

USDT and USDC are available on three chains: Tron (cheapest fees), Ethereum, and BNB Chain. Choose the chain that best fits your use case. Tron (TRC-20) is recommended for lowest transaction costs.

Create Payment

POST/api/v1/paymentsCreate a new payment

Request Body Parameters:

ParameterTypeRequiredDescription
amountstringRequired *Amount in fiat currency (e.g. "29.99")
networkstringRequired *Which network/coin to receive payment on. See the network table below.
currencystringOptionalDisplay label for the coin (e.g. "BTC", "USDT"). Defaults to the network value. Only needed if you want a custom label.
fiatCurrencystringOptionalFiat currency code (default: "USD")
orderIdstringOptionalYour system's order ID
descriptionstringOptionalPayment description
metadataobjectOptionalExtra data (JSON object)

How it works

You specify the price in fiat (USD, EUR, etc.) and RevionPay automatically calculates the crypto amount based on the current exchange rate.

network vs currency

The network field determines which blockchain and coin is used for the payment. The currency field is just a display label.

For example, to accept USDT on the Ethereum network, use network: "ETH_USDT". For USDT on Tron, use network: "USDT". See the full list in Supported Networks.

Example Request (Bitcoin):

json
{
  "amount": "29.99",
  "network": "BTC",
  "fiatCurrency": "USD",
  "orderId": "order-456",
  "description": "Premium subscription - 1 month",
  "metadata": {
    "customerId": "cust_123",
    "plan": "premium"
  }
}

Example Request (USDT on Tron):

json
{
  "amount": "100.00",
  "network": "USDT",
  "fiatCurrency": "USD",
  "orderId": "order-789"
}

Example Request (USDC on Ethereum):

json
{
  "amount": "500.00",
  "network": "ETH_USDC",
  "fiatCurrency": "USD",
  "orderId": "order-101"
}

Common Mistake

Do not use the currency field to select which coin to receive. The network field is required and determines the coin and blockchain. If you omit network, the request will be rejected with a 400 error.

Example Response:

json
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "PENDING",
  "paymentUrl": "https://www.revionpay.com/pay/a1b2c3d4...",
  "walletAddress": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "cryptoAmount": "0.00034521",
  "exchangeRate": "86850.00",
  "grossAmount": "0.00034521",
  "feePercent": "1.0000",
  "platformFee": "0.00000345",
  "netAmount": "0.00034176",
  "createdAt": "2026-03-07T18:00:00.000Z"
}

Key Response Fields

  • paymentUrl — Redirect your customer to this URL to show wallet address and QR code
  • walletAddress — The crypto wallet address the customer pays to
  • cryptoAmount — The exact amount to be paid in crypto
  • id — Save this ID for payment tracking
  • platformFee — Platform commission taken
  • netAmount — Net amount you receive

Payment Status

GET/api/v1/payments/:idGet payment details
GET/api/v1/paymentsList payments (paginated)

Query Parameters (for listing):

ParameterTypeRequiredDescription
pagenumberOptionalPage number (default: 1)
limitnumberOptionalItems per page (default: 20, max: 100)
statusstringOptionalFilter by status
networkstringOptionalFilter by network

Payment Statuses:

PENDINGPayment created, waiting for customer to send crypto
PROCESSINGPartial payment received, awaiting full amount
SETTLEDFull payment received and confirmed on-chain
EXPIREDPayment window expired (set by the payment provider, typically 24h). No crypto was received in time.
INVALIDInvalid payment (e.g. wrong amount sent)
FAILEDPayment creation failed (provider error)

Payment detail example:

bash
curl https://www.revionpay.com/api/v1/payments/PAYMENT_ID \
  -H "x-api-key: pk_YOUR_API_KEY_HERE"

Polling for Status Updates

You can poll GET /api/v1/payments/:id to check if a payment status has changed. This is useful if you don't have a webhook URL configured, or as a fallback alongside webhooks. We recommend polling every 10-30 seconds while a payment is in PENDING or PROCESSING state.

Webhooks

When a payment status changes, an automatic notification is sent to your system. Configure your webhook URL from the Settings page. Webhooks are optional — you can also poll GET /api/v1/payments/:id to check payment status.

Setup:

  1. Enter your endpoint URL in the Webhook URL field in Settings (e.g., https://yoursite.com/api/webhook)
  2. Your system must accept POST requests at this URL
  3. Each webhook is signed with HMAC-SHA256

Webhook Payload Example:

json
{
  "event": "payment.updated",
  "paymentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "SETTLED",
  "grossAmount": "0.00100000",
  "netAmount": "0.00099000",
  "currency": "BTC",
  "orderId": "order-456"
}

HMAC Signature Verification:

Each webhook request includes an x-webhook-signature header. Use this to verify the webhook is genuinely from RevionPay.

javascript
// Node.js - Webhook verification example
const crypto = require('crypto');

function verifyWebhook(req) {
  const signature = req.headers['x-webhook-signature'];
  const body = JSON.stringify(req.body);

  // webhookSecret is auto-generated when you create an API key
  // You can view it on the Settings page
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(body)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express.js example
app.post('/api/webhook', (req, res) => {
  if (!verifyWebhook(req)) {
    return res.status(401).send('Invalid signature');
  }

  const { event, paymentId, status, orderId } = req.body;

  if (status === 'SETTLED') {
    // Payment confirmed! Activate product/service
    console.log('Payment settled:', paymentId, orderId);
  }

  // Must return 200, otherwise the webhook will be retried
  res.status(200).send('OK');
});

Retry Policy

If a webhook fails (non-200 response or timeout), it is retried up to 5 times:

30s → 2min → 10min → 1hr → 6hr

Error Handling

On error, the API returns a JSON response in this format:

json
{
  "statusCode": 401,
  "message": "Invalid API key",
  "error": "Unauthorized"
}

HTTP Status Codes:

CodeMeaningSolution
400Bad RequestCheck request body parameters
401UnauthorizedCheck your API key — it must be valid and active
403ForbiddenYour account is not active — contact admin
404Not FoundEndpoint or resource not found
429Rate LimitedToo many requests — burst: 20/min per endpoint, overall: 100/min
500Server ErrorServer error — retry or contact support

Rate Limiting

API requests are subject to two rate limits:

  • Burst limit: 20 requests per minute per endpoint
  • Overall limit: 100 requests per minute total

If you exceed either limit, you will receive a 429 Too Many Requests response. Wait and retry.

Full Examples

Node.js (Express)

javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());

const REVIONPAY_URL = 'https://www.revionpay.com/api/v1';
const API_KEY = process.env.REVIONPAY_API_KEY;
const WEBHOOK_SECRET = process.env.REVIONPAY_WEBHOOK_SECRET;

// Create payment
app.post('/checkout', async (req, res) => {
  // network comes from frontend: 'BTC', 'ETH', 'USDT', 'ETH_USDT', etc.
  const { orderId, amount, network, description } = req.body;

  const response = await fetch(REVIONPAY_URL + '/payments', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': API_KEY,
    },
    body: JSON.stringify({
      amount: amount,
      network: network,  // Required! e.g. 'BTC', 'USDT', 'ETH_USDC'
      fiatCurrency: 'USD',
      orderId: orderId,
      description: description,
    }),
  });

  const payment = await response.json();

  if (!response.ok) {
    return res.status(400).json({ error: payment.message });
  }

  // Return payment URL to frontend — redirect customer there
  res.json({
    paymentId: payment.id,
    paymentUrl: payment.paymentUrl,
  });
});

// Webhook handler
app.post('/webhook/revionpay', (req, res) => {
  // 1. Signature verification
  const signature = req.headers['x-webhook-signature'];
  const body = JSON.stringify(req.body);
  const expected = 'sha256=' + crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Handle payment status
  const { paymentId, status, orderId } = req.body;

  switch (status) {
    case 'SETTLED':
      console.log('Payment completed!', orderId);
      await db.orders.update({ where: { id: orderId }, data: { status: 'paid' } });
      await sendConfirmationEmail(orderId);
      break;
    case 'EXPIRED':
      console.log('Payment expired', orderId);
      await db.orders.update({ where: { id: orderId }, data: { status: 'cancelled' } });
      break;
    case 'PROCESSING':
      console.log('Partial payment received', orderId);
      break;
  }

  res.status(200).send('OK');
});

app.listen(4000, () => console.log('Server running on :4000'));

Python (Flask)

python
import requests
import hmac
import hashlib
from flask import Flask, request, jsonify

app = Flask(__name__)

REVIONPAY_URL = 'https://www.revionpay.com/api/v1'
API_KEY = 'pk_YOUR_API_KEY_HERE'
WEBHOOK_SECRET = 'whsec_YOUR_WEBHOOK_SECRET'

@app.route('/checkout', methods=['POST'])
def create_checkout():
    data = request.json

    response = requests.post(
        f'{REVIONPAY_URL}/payments',
        json={
            'amount': data['amount'],
            'network': data['network'],  # Required! e.g. 'BTC', 'USDT', 'ETH_USDC'
            'fiatCurrency': 'USD',
            'orderId': data['orderId'],
            'description': data.get('description', ''),
        },
        headers={
            'Content-Type': 'application/json',
            'x-api-key': API_KEY,
        }
    )

    payment = response.json()
    if response.status_code != 201:
        return jsonify({'error': payment.get('message')}), 400

    return jsonify({
        'paymentId': payment['id'],
        'paymentUrl': payment['paymentUrl'],
    })

@app.route('/webhook/revionpay', methods=['POST'])
def handle_webhook():
    # Signature verification
    signature = request.headers.get('x-webhook-signature', '')
    body = request.get_data(as_text=True)
    expected = 'sha256=' + hmac.new(
        WEBHOOK_SECRET.encode(),
        body.encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        return 'Invalid signature', 401

    data = request.json
    status = data['status']
    order_id = data.get('orderId')

    if status == 'SETTLED':
        print(f'Payment completed: {order_id}')
        db.execute('UPDATE orders SET status = %s WHERE id = %s', ('paid', order_id))

    return 'OK', 200

if __name__ == '__main__':
    app.run(port=4000)

PHP

php
<?php
// Create payment
function createPayment($orderId, $amount, $network, $description) {
    $apiKey = getenv('REVIONPAY_API_KEY');
    $url = 'https://www.revionpay.com/api/v1/payments';

    $data = json_encode([
        'amount'       => $amount,
        'network'      => $network,  // Required! e.g. 'BTC', 'USDT', 'ETH_USDC'
        'fiatCurrency' => 'USD',
        'orderId'      => $orderId,
        'description'  => $description,
    ]);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $data,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'x-api-key: ' . $apiKey,
        ],
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

// Webhook handler (webhook.php)
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');
$secret = getenv('REVIONPAY_WEBHOOK_SECRET');

$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$data = json_decode($body, true);

if ($data['status'] === 'SETTLED') {
    $orderId = $data['orderId'];
    $pdo->prepare('UPDATE orders SET status = ? WHERE id = ?')
        ->execute(['paid', $orderId]);
}

http_response_code(200);
echo 'OK';

Frontend — Payment Redirect

html
<!-- Checkout button example -->
<select id="coin-select">
  <option value="BTC">Bitcoin</option>
  <option value="ETH">Ethereum</option>
  <option value="USDT">USDT (TRC-20)</option>
  <option value="ETH_USDT">USDT (ERC-20)</option>
  <option value="BNB_USDT">USDT (BEP-20)</option>
  <option value="USDC">USDC (TRC-20)</option>
</select>
<button id="pay-btn" onclick="startPayment()">
  Pay Now
</button>

<script>
async function startPayment() {
  const btn = document.getElementById('pay-btn');
  const network = document.getElementById('coin-select').value;
  btn.disabled = true;
  btn.textContent = 'Loading...';

  try {
    // Send request to YOUR backend (which calls RevionPay API)
    const res = await fetch('/checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        orderId: 'order-789',
        amount: '49.99',
        network: network,  // Pass selected coin to your backend
        description: 'Order #789',
      }),
    });

    const data = await res.json();

    if (data.paymentUrl) {
      // Customer is redirected to the crypto payment page
      window.location.href = data.paymentUrl;
    } else {
      alert('Error: ' + (data.error || 'Unknown error'));
    }
  } catch (err) {
    alert('Connection error');
  } finally {
    btn.disabled = false;
    btn.textContent = 'Pay with Bitcoin';
  }
}
</script>

Payment Flow

Customer → Clicks "Pay with Crypto" on your site

↓

Your Backend → POST /api/v1/payments (with x-api-key)

↓

RevionPay → Generates wallet address, returns paymentUrl + walletAddress

↓

Your Backend → Returns paymentUrl to frontend

↓

Customer → Scans QR code or sends crypto to wallet address on payment page

↓

RevionPay → Detects payment, sends webhook

↓

Your Backend → Receives webhook, verifies signature, confirms order