Documentation v1.0

KryptoPay Developer Docs

Accept crypto payments — stablecoins and volatile tokens across Ethereum, Base, Arbitrum, BNB Chain, Polygon, Apertum, and TRON — on your website in minutes. No smart contract knowledge required.

🤖 Using an AI assistant? Point Claude/Cursor/Copilot at /llms.txt and ask it to "integrate KryptoPay checkout" — it has copy-paste-ready code for the widget, the server API, and webhook verification.

Getting Started

KryptoPay is a Web3 payment gateway that provides an embeddable checkout widget and a REST API. Merchants integrate the widget into their site and receive crypto payments directly to their wallet.

Create an Account

Sign up at the KryptoPay Dashboard with your email and wallet address. This is where you'll receive payments.

Get Your API Keys

Go to API Keys in the dashboard and create a Live Mode key. You'll get a pk_live_xxx (publishable) and sk_live_xxx (secret) key.

Integrate the Widget

Add the widget script to your site and call KryptoPay.open() with your publishable key and the payment amount.

Quick Start

The fastest way to accept crypto payments — copy this into any HTML page:

HTML
<!-- Add to <head> -->
<link rel="stylesheet" href="https://krypto-pay-checkout-widget.vercel.app/dist/kryptopay.css">

<!-- Add before </body> -->
<script src="https://krypto-pay-checkout-widget.vercel.app/dist/kryptopay.js"></script>

<button onclick="pay()">Pay $25.00</button>

<script>
  function pay() {
    KryptoPay.open({
      apiKey: 'pk_live_YOUR_KEY_HERE',
      apiUrl: 'https://krypto-pay-api-prod.onrender.com',
      amount: '25.00',
      onSuccess: function(payment) {
        alert('Payment confirmed! ID: ' + payment.id);
      },
    });
  }
</script>
That's it! The widget handles wallet connection, network switching, token selection, QR codes, and payment confirmation automatically.

Installation

Option 1: Script Tag (Recommended)

Add the CSS and JS files to your HTML. The widget is a single self-contained bundle (~9MB) that includes React, wagmi, and all dependencies.

<link rel="stylesheet" href="https://krypto-pay-checkout-widget.vercel.app/dist/kryptopay.css">
<script src="https://krypto-pay-checkout-widget.vercel.app/dist/kryptopay.js"></script>

Option 2: ES Module

For modern bundlers (webpack, Vite, Next.js):

import { CheckoutModal, PayButton } from '@kryptopay/checkout-widget';

Option 3: Next.js / React with Script Tag

import Script from 'next/script';

export default function PayPage() {
  return (
    <>
      <Script src="https://...kryptopay.js" />
      <button onClick={() => window.KryptoPay.open({ ... })}>
        Pay Now
      </button>
    </>
  );
}

Configuration

All options for KryptoPay.open():

OptionTypeRequiredDescription
apiKeystringYesYour publishable key (pk_live_xxx)
apiUrlstringYesKryptoPay API URL
amountstringYesAmount in USD (e.g. "25.00")
merchantNamestringNoDisplayed in the widget header
metadataobjectNoCustom data attached to the payment (e.g. { orderId: "123" })
brandingobjectNoCustomize colors, logo, theme
onSuccessfunctionNoCalled when payment is confirmed
onFailurefunctionNoCalled when payment fails
onClosefunctionNoCalled when user closes the modal

Branding

Customize the widget to match your brand:

KryptoPay.open({
  apiKey: 'pk_live_xxx',
  apiUrl: 'https://krypto-pay-api-prod.onrender.com',
  amount: '50.00',
  branding: {
    brandColor: '#8B5CF6',       // Primary color (optional)
    businessName: 'My Store',    // Header title
    theme: 'dark',               // 'dark' | 'light'
    logoUrl: 'https://...',     // Logo image URL
    customCss: '.kp-modal { ... }', // Custom CSS overrides
  },
});
PropertyTypeDescription
brandColorstringHex color for buttons and accents. Optional — if omitted, the widget uses KryptoPay's brand color.
businessNamestringDisplayed in the modal header
themestring"dark" (default) or "light"
logoUrlstringURL to your logo (displayed in header)
customCssstringInject custom CSS into the widget

Events

onSuccess(payment)

Called when the payment is confirmed on-chain. It runs in the browser — use it for the UI (redirect, show a receipt), not to fulfill the order. The payment object contains:

{
  id: "cmmqv992o...",           // Payment Intent ID — use it to verify server-side
  amount: "25.00",               // Amount in USD
  token: "USDT",                 // Token used
  network: "bsc",               // Network used
  status: "confirmed",           // Always "confirmed" when onSuccess fires
  txHash: "0x736cb...",          // On-chain transaction hash
  payerAddress: "0x0002C...",   // Payer's wallet
  depositAddress: "0xB1D0...", // Deposit wallet used
  amountValidation: "exact",     // "exact" | "overpaid" | "underpaid"
  metadata: { orderId: "123" }, // Your custom data, echoed back
}
⚠️ onSuccess runs in the browser — verify before you fulfill Client-side code can be tampered with, so never ship goods based on onSuccess alone. Use it to trigger your own endpoint, then confirm the payment server-side (below) or from a signed webhook.

Confirm on your server (recommended)

The pattern most integrations use: onSuccess pings your backend, which re-checks the payment against the KryptoPay API with your secret key before delivering anything.

Browser — just trigger your endpoint
onSuccess: async (payment) => {
  await fetch('/confirm', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ paymentIntentId: payment.id }),
  });
  window.location.href = '/thank-you';   // UI only
}
Your server — verify, then fulfill
// POST /confirm
app.post('/confirm', async (req, res) => {
  const { paymentIntentId } = req.body;
  // Re-check with the SECRET key — do NOT trust the browser payload
  const r = await fetch(
    `https://krypto-pay-api-prod.onrender.com/v1/payment-intents/${paymentIntentId}`,
    { headers: { Authorization: `Bearer ${process.env.KRYPTOPAY_SECRET}` } },
  );
  const { data } = await r.json();
  if (data.status === 'confirmed') {
    fulfillOrder(data.metadata.orderId);   // now it's safe to deliver
  }
  res.json({ ok: true });
});

Even more robust: skip the client round-trip and fulfill straight from the signed webhook — it's server-to-server and can't be spoofed.

onFailure(error)

Called when a payment fails. error is a standard Error object with a message.

onClose()

Called when the user closes the modal (by clicking X or the overlay). No payment was made.

React Integration

For React/Next.js apps, you can use the component API:

import { CheckoutModal } from '@kryptopay/checkout-widget';

function App() {
  const [showCheckout, setShowCheckout] = useState(false);

  return (
    <>
      <button onClick={() => setShowCheckout(true)}>Pay</button>
      {showCheckout && (
        <CheckoutModal
          apiKey="pk_live_xxx"
          apiUrl="https://krypto-pay-api-prod.onrender.com"
          amount="25.00"
          onSuccess={(payment) => console.log('Paid!', payment)}
          onClose={() => setShowCheckout(false)}
        />
      )}
    </>
  );
}

Authentication

The KryptoPay API uses API keys for authentication. Include your key in the Authorization header:

Authorization: Bearer pk_live_xxx
Keep your secret key safe! Never include sk_live_ keys in client-side code, repositories, or anywhere publicly accessible.

Payment Intents

POST /v1/payment-intents

Create a new payment intent. The widget does this automatically, but you can also create them server-side.

curl -X POST https://krypto-pay-api-prod.onrender.com/v1/payment-intents \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "25.00",
    "token": "USDT",
    "network": "bsc",
    "metadata": { "orderId": "ORD-123" }
  }'

Response:

{
  "data": {
    "id": "cmmqv992o...",
    "amount": "25.00",
    "token": "USDT",
    "network": "bsc",
    "status": "pending",
    "depositAddress": "0xB1D086cb...",
    "expiresAt": "2026-03-14T22:27:21Z",
    "metadata": { "orderId": "ORD-123" }
  }
}

GET /v1/payment-intents/:id

Retrieve a payment intent by ID. Use this to check payment status.

GET /v1/payment-intents

List all payment intents for your merchant account. Supports pagination with ?page=1&pageSize=20&status=confirmed.

Payment Statuses

StatusDescription
pendingWaiting for payment
processingPayment received, being swept to merchant
confirmedPayment confirmed and delivered
failedPayment failed
expiredPayment intent expired (15 min)

Transactions

GET /v1/transactions

List confirmed transactions. Each transaction includes the amount, fee, net amount, tx hash, and payer address.

curl https://krypto-pay-api-prod.onrender.com/v1/transactions \
  -H "Authorization: Bearer sk_live_xxx"

Webhooks

Receive real-time notifications when payments are confirmed. Configure webhook endpoints in the Dashboard.

Event: payment.confirmed

Sent when a payment is fully confirmed and swept to your wallet.

{
  "id": "cmmqv992o...",
  "type": "payment.confirmed",
  "data": {
    "paymentIntentId": "cmmqv992o...",
    "amount": "25.00",
    "token": "USDT",
    "network": "bsc",
    "txHash": "0xb88139...",
    "payerAddress": "0x0002C2..."
  },
  "createdAt": "2026-03-14T22:20:00Z"
}
Webhook Security Each endpoint has a unique secret. Every request carries a KryptoPay-Signature header of the form t=<unixSeconds>,v1=<hexHmac>. Verify it (Stripe-style): compute HMAC-SHA256(secret, `${t}.${rawBody}`), compare it to v1 in constant time, and reject requests older than 5 minutes. Fulfill orders on this verified webhook — never on the client-side onSuccess callback.

Supported Networks & Tokens

NetworkTokensStatus
EthereumUSDT, USDC, DAI, ETH, WBTCLive
BaseUSDT, USDC, DAI, ETHLive
ArbitrumUSDT, USDC, DAI, ETHLive
BNB Smart ChainUSDT, USDC, DAI, BNB, BTCBLive
PolygonUSDT, USDC, DAILive
ApertumwUSDT, APTM, PUG, wBTCLive
TRONUSDT, CSLive

Stablecoins (USDT, USDC, DAI, wUSDT, CS) settle 1:1. Volatile tokens (ETH, BNB, WBTC, BTCB, APTM, PUG, wBTC) are accepted at the live market rate and auto-swapped on-chain — the merchant always receives a stablecoin, never the volatile asset. You don't manage any of this: pick an amount in USD and KryptoPay handles the conversion, network fees, and settlement.

On TRON, USDT uses a From-Wallet contract (the customer pays gas directly from their wallet). More EVM chains (Polygon, Arbitrum, Base) are on the roadmap, and we integrate custom or private EVM networks on request.

Testing

To test payments without spending real money:

  1. Create a Test Mode API key in the Dashboard
  2. Use the test key in your widget integration
  3. Payments will use testnet networks (Sepolia, Amoy, BSC Testnet)
Need help? Contact us at [email protected] or open an issue on GitHub.
KryptoPay — Web3 Payment Gateway