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:
<!-- 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>
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():
| Option | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Your publishable key (pk_live_xxx) |
apiUrl | string | Yes | KryptoPay API URL |
amount | string | Yes | Amount in USD (e.g. "25.00") |
merchantName | string | No | Displayed in the widget header |
metadata | object | No | Custom data attached to the payment (e.g. { orderId: "123" }) |
branding | object | No | Customize colors, logo, theme |
onSuccess | function | No | Called when payment is confirmed |
onFailure | function | No | Called when payment fails |
onClose | function | No | Called 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
},
});
| Property | Type | Description |
|---|---|---|
brandColor | string | Hex color for buttons and accents. Optional — if omitted, the widget uses KryptoPay's brand color. |
businessName | string | Displayed in the modal header |
theme | string | "dark" (default) or "light" |
logoUrl | string | URL to your logo (displayed in header) |
customCss | string | Inject 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 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.
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
}
// 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
- Publishable keys (
pk_live_) — safe for frontend/widget use - Secret keys (
sk_live_) — backend only, never expose in client code
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
| Status | Description |
|---|---|
pending | Waiting for payment |
processing | Payment received, being swept to merchant |
confirmed | Payment confirmed and delivered |
failed | Payment failed |
expired | Payment 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"
}
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
| Network | Tokens | Status |
|---|---|---|
| Ethereum | USDT, USDC, DAI, ETH, WBTC | Live |
| Base | USDT, USDC, DAI, ETH | Live |
| Arbitrum | USDT, USDC, DAI, ETH | Live |
| BNB Smart Chain | USDT, USDC, DAI, BNB, BTCB | Live |
| Polygon | USDT, USDC, DAI | Live |
| Apertum | wUSDT, APTM, PUG, wBTC | Live |
| TRON | USDT, CS | Live |
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:
- Create a Test Mode API key in the Dashboard
- Use the test key in your widget integration
- Payments will use testnet networks (Sepolia, Amoy, BSC Testnet)