Complete guide for merchants to integrate KLYCoin x402 payments into their platforms
KLYCoin x402 allows merchants to accept crypto payments while automatically crediting KolayMiles rewards to customers
Get up and running in minutes
Your merchant address is the wallet address where you'll receive payments.
# Example merchant address
MERCHANT_ADDRESS=0x8ba1f109551bD432803012645Hac136c461c0000⚠️ Important
Keep your merchant private key secure. Use a hardware wallet for production.
// Contract addresses (BSC Testnet)
const CONFIG = {
facilitator: "0x565a7Af88C3C00757a00098f3fcc6b8fB355c899",
paymentsApi: "http://localhost:8081",
oracleApi: "http://localhost:8090",
rpcUrl: "https://data-seed-prebsc-1-s1.binance.org:8545",
assets: {
usdc: "0x64544969ed7EBf5f083679233325356EbE738930"
}
};curl -X POST http://localhost:8081/api/x402/charge \
-H "Content-Type: application/json" \
-d '{
"payer": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"merchant": "0x8ba1f109551bD432803012645Hac136c461c0000",
"asset": "USDC",
"amount": 10.50,
"metadata": {
"receiptId": "ORDER-12345"
}
}'Understand how payments are processed from start to finish
Customer Checkout
↓
Frontend (Web3 Wallet)
↓ (1) Create Charge
KLYCoin Payments API
↓ (2) Get Oracle Rate
Oracle Service
↓ (3) Sign Rate
KLYCoin Payments API
↓ (4) Return Signed Payload
Frontend
↓ (5) Execute payWithKolay()
KolayFacilitator Contract (BSC)
↓ (6) Emit Paid Event
Listener Service
↓ (7) Forward to KolayMiles
KolayMiles API
↓ (8) Credit Miles + Send Webhook
Merchant BackendCustomer selects "Pay with Kolay" at checkout and connects wallet.
POST /api/x402/charge
{
"payer": "0x...", // Customer wallet
"merchant": "0x...", // Your merchant address
"asset": "USDC", // Payment token
"amount": 10.50, // Amount in USD
"metadata": {
"receiptId": "ORDER-123",
"description": "Product Purchase"
}
}POST /api/v1/prepare-payment
{
"payer": "0x...",
"merchant": "0x...",
"asset": "0x...", // USDC address
"amount": "10500000" // In wei (10.5 USDC)
}// 1. Approve facilitator to spend tokens
await erc20.approve(facilitatorAddress, amountWei);
// 2. Execute payment
await facilitator.payWithKolay(
assetAddress,
amountWei,
merchantAddress,
receiptId,
oracleRate,
oracleSignature
);POST /your-webhook-endpoint
{
"x402Id": "402-ORDER-123-abc",
"txHash": "0x...",
"status": "succeeded",
"amount": 10.50,
"payer": "0x...",
"merchant": "0x...",
"milesCredited": 2500,
"timestamp": 1730500000
}Complete API documentation for KLYCoin services
{
"payer": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"merchant": "0x8ba1f109551bD432803012645Hac136c461c0000",
"asset": "USDC",
"amount": 10.50,
"metadata": {
"receiptId": "ORDER-123",
"description": "Product purchase"
}
}{
"ok": true,
"x402Id": "402-ORDER-123-abc",
"expires_in": 300,
"signature": "0x...",
"status": "pending"
}{
"x402Id": "402-ORDER-123-abc",
"txHash": "0x...",
"status": "succeeded",
"amount": 10.50,
"payer": "0x...",
"merchant": "0x...",
"timestamp": 1730500000
}Real-world integration examples
// lib/payment.ts
import { ethers } from 'ethers';
import KOLAY_FACILITATOR_ABI from '@/lib/abi/KolayFacilitator.json';
const CONFIG = {
facilitator: '0x565a7Af88C3C00757a00098f3fcc6b8fB355c899',
paymentsApi: process.env.NEXT_PUBLIC_PAYMENTS_URL || 'http://localhost:8081',
facilitatorApi: process.env.NEXT_PUBLIC_FACILITATOR_URL || 'http://localhost:8082',
};
export async function executePayment({
provider,
amount,
assetAddress,
merchantAddress,
receiptId
}: {
provider: ethers.BrowserProvider;
amount: string;
assetAddress: string;
merchantAddress: string;
receiptId: string;
}) {
const signer = await provider.getSigner();
const payerAddress = await signer.getAddress();
// Step 1: Get oracle-signed rate
const prepareRes = await fetch(`${CONFIG.facilitatorApi}/api/v1/prepare-payment`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payer: payerAddress,
merchant: merchantAddress,
asset: assetAddress,
amount: ethers.parseUnits(amount, 18).toString()
})
});
const { oracle, payment } = await prepareRes.json();
// Step 2: Approve facilitator
const erc20 = new ethers.Contract(
assetAddress,
['function approve(address,uint256) external returns(bool)'],
signer
);
const amountWei = ethers.parseUnits(amount, 18);
const approveTx = await erc20.approve(CONFIG.facilitator, amountWei);
await approveTx.wait();
// Step 3: Execute payment
const facilitator = new ethers.Contract(
CONFIG.facilitator,
KOLAY_FACILITATOR_ABI.abi,
signer
);
const payTx = await facilitator.payWithKolay(
assetAddress,
amountWei,
merchantAddress,
receiptId,
oracle.payload,
oracle.signature
);
const receipt = await payTx.wait();
return {
txHash: receipt.hash,
blockNumber: receipt.blockNumber,
milesCredited: payment.milesCredited,
fee: payment.fee
};
}// components/PayWithKolayButton.tsx
'use client';
import { useState } from 'react';
import { executePayment } from '@/lib/payment';
import toast from 'react-hot-toast';
export function PayWithKolayButton({
amount,
assetAddress,
merchantAddress,
orderId
}: {
amount: string;
assetAddress: string;
merchantAddress: string;
orderId: string;
}) {
const [loading, setLoading] = useState(false);
const handlePay = async () => {
if (!window.ethereum) {
toast.error('Please install MetaMask');
return;
}
try {
setLoading(true);
const provider = new ethers.BrowserProvider(window.ethereum);
const result = await executePayment({
provider,
amount,
assetAddress,
merchantAddress,
receiptId: orderId
});
toast.success(`Payment confirmed! Miles credited: ${result.milesCredited}`);
// Handle success (redirect, update UI, etc.)
console.log('Payment result:', result);
} catch (error: any) {
console.error('Payment error:', error);
toast.error(error.message || 'Payment failed');
} finally {
setLoading(false);
}
};
return (
<button
onClick={handlePay}
disabled={loading}
className="px-6 py-3 bg-blue-600 text-white rounded-lg disabled:opacity-50"
>
{loading ? 'Processing...' : `Pay ${amount} with Kolay`}
</button>
);
}Track transactions, conversions, and customer metrics
Login at: https://kolaymiles.com/merchant
Protect your integration with security best practices
import crypto from 'crypto';
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const hmac = crypto.createHmac('sha256', secret);
const expected = `sha256=${hmac.update(body).digest('hex')}`;
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler
app.post('/webhooks/payment', (req, res) => {
const signature = req.headers['x-kolay-signature'];
const isValid = verifyWebhook(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
processPayment(req.body);
res.json({ ok: true });
});Test your integration on BSC Testnet
Get testnet BNB from faucets:
Swap on PancakeSwap testnet or contact support for faucet
curl -X POST http://localhost:8082/api/v1/prepare-payment \
-H "Content-Type: application/json" \
-d '{
"payer": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"merchant": "0x8ba1f109551bD432803012645Hac136c461c0000",
"asset": "0x64544969ed7EBf5f083679233325356EbE738930",
"amount": "1000000000000000000"
}'Get help when you need it
A: Check customer approved transaction in wallet, sufficient gas (BNB) in wallet, network connectivity, and BSC network is selected in wallet.
A: Check webhook URL is publicly accessible (no localhost), SSL certificate is valid, firewall allows inbound requests, and HMAC signature verification is correct.
A: Check oracle service is running, rate signature is valid, customer address is correct, and check on-chain event logs.
Ready to go live?
Contact us at merchants@klycoin.io for mainnet setup and merchant verification.
We use cookies to improve your experience. Strictly necessary cookies are always on. Others require your consent.
See our Cookie Policy for details.