API Documentation v1.0
CryptPal x402 is a gasless payment system for digital content using USDC on Binance Smart Chain (BSC). It implements the HTTP 402 Payment Required status code to gate access to content behind cryptocurrency payments.
Users can pay without gas fees using deposited balance
Standard web protocol for payment-gated content
Stable payments with low transaction costs
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Creator βββββ1ββββΆβ Server βββββ2ββββΆβ Database β
β (Wallet) β β (Node.js) β β (In-Memory) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β
β 3. Payment Link
βΌ
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Customer βββββ4ββββΆβ Relayer βββββ5ββββΆβ Blockchain β
β (Wallet) β β Wallet β β (BSC) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
Flow:
1. Creator creates payment link
2. Server stores link data
3. Customer receives link
4. Customer deposits USDC to relayer
5. Relayer executes gasless payment on blockchain
/
Serves the main application interface for creating payment links.
Response: HTML page
/pay?code={CODE}
Serves the payment interface with the specified payment code.
Query Parameters:
code (string, required): Unique payment identifierResponse: HTML payment page
/api/relayer-address
Returns the relayer wallet address for deposits.
Response:
{
"address": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db"
}
/api/balance?address={ADDRESS}
Returns the gasless balance for a specific wallet address.
Query Parameters:
address (string, required): BSC wallet address (0x...)Response:
{
"balance": 10.50
}
/api/create
Creates a new payment link for content.
Request Body:
{
"content": "https://example.com/premium-content.pdf",
"amount": 1.50,
"wallet": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db"
}
Response:
{
"code": "abc123",
"link": "http://localhost:3000/pay?code=abc123"
}
/api/deposit
Registers a USDC deposit to user's gasless balance.
Request Body:
{
"address": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db",
"amount": 10.00,
"txHash": "0x1234...abcd"
}
Response:
{
"success": true,
"balance": 10.00
}
/api/relay
Executes a gasless payment using deposited balance.
Request Body:
{
"code": "abc123",
"from": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db"
}
Response:
{
"success": true,
"txHash": "0x5678...efgh",
"newBalance": 8.50
}
Note: Deducts payment amount from user's gasless balance.
/api/pay?code={CODE}
Retrieves payment information or verifies payment completion.
Query Parameters:
code (string, required): Payment codeRequest Headers (optional):
x402-payment (string): Transaction hash to verify paymentResponse (without payment):
HTTP 402 Payment Required
{
"amount": 1.50,
"token": "USDC",
"address": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db",
"network": 56,
"message": "Payment required"
}
Response (with valid payment):
HTTP 200 OK
<!DOCTYPE html>
<html>
<!-- Success page with content access -->
</html>
1. Customer deposits USDC to relayer
POST /api/deposit
{ address, amount, txHash }
2. Server credits user's gasless balance
USER_DEPOSITS[address] += amount
3. Customer initiates payment
POST /api/relay
{ code, from: address }
4. Server deducts from balance
USER_DEPOSITS[address] -= payment_amount
5. Relayer sends USDC on-chain
relayerWallet.transfer(recipient, amount)
(Server pays gas fees ~$0.20)
6. Server verifies and grants access
GET /api/pay?code=xyz
Headers: { x402-payment: txHash }
7. Customer receives content
1. Customer initiates payment
Direct USDC transfer via MetaMask
2. User confirms transaction
(Pays ~$0.10 gas in BNB)
3. Transaction confirmed on-chain
4. Server verifies payment
GET /api/pay?code=xyz
Headers: { x402-payment: txHash }
5. Customer receives content
Token:
USDC (USD Coin)
Contract Address (BSC Mainnet):
0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
Decimals:
6 (1 USDC = 1,000,000 units)
Network:
Binance Smart Chain (BSC) - Chain ID: 56
// Transfer USDC from one address to another
function transfer(address to, uint256 amount) returns (bool)
// Check USDC balance of an address
function balanceOf(address account) view returns (uint256)
Missing or invalid parameters
Content requires payment to access
Server-side error (relayer issues, blockchain errors)
// Insufficient gasless balance
{
"error": "Insufficient deposit. Need 1.5, have 0.5"
}
// Invalid payment code
{
"error": "Invalid code"
}
// Relayer not configured
{
"error": "Relayer not configured"
}
// Missing data in request
{
"error": "Missing data"
}
// BSC RPC endpoint
const BSC_RPC = 'https://bsc-dataseed.binance.org/';
// USDC contract address on BSC
const USDC_ADDRESS = '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d';
// Relayer wallet private key (funds gasless transactions)
const RELAYER_PRIVATE_KEY = '0xYOUR_PRIVATE_KEY_HERE';
// Server port
const PORT = 3000;
// USDC contract address
const USDC_ADDRESS = "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d";
// BSC Chain ID (hex)
const BSC_CHAIN_ID = "0x38";
// API endpoints
const API_URL = "/api/pay";
const CREATE_URL = "/api/create";
const RELAY_URL = "/api/relay";
const BALANCE_URL = "/api/balance";
const DEPOSIT_URL = "/api/deposit";
Implement rate limiting to prevent abuse:
npm install express-rate-limit
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 20
});
app.post('/api/relay', limiter, async (req, res) => {
// ...
});
Current implementation uses in-memory storage. For production, use persistent database:
// Example with PostgreSQL
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
// Store deposit
await pool.query(
'INSERT INTO deposits (address, balance) VALUES ($1, $2) ON CONFLICT (address) DO UPDATE SET balance = deposits.balance + $2',
[address, amount]
);
const createPaymentLink = async () => {
const response = await fetch('http://localhost:3000/api/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: 'https://example.com/premium-video.mp4',
amount: 2.50,
wallet: '0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db'
})
});
const data = await response.json();
console.log('Payment link:', data.link);
// Output: http://localhost:3000/pay?code=abc123
};
import requests
def check_payment(code):
response = requests.get(
f'http://localhost:3000/api/pay',
params={'code': code}
)
if response.status_code == 402:
data = response.json()
print(f"Payment required: {data['amount']} {data['token']}")
return False
elif response.status_code == 200:
print("Payment completed! Content accessible")
return True
else:
print(f"Error: {response.status_code}")
return False
check_payment('abc123')
curl -X POST http://localhost:3000/api/deposit \
-H "Content-Type: application/json" \
-d '{
"address": "0x61C8A88dCE90C4Dc2EF04464b920C1f7299907db",
"amount": 10.00,
"txHash": "0x1234567890abcdef..."
}'
// Use BSC Testnet for testing
const BSC_TESTNET_RPC = 'https://data-seed-prebsc-1-s1.binance.org:8545/';
const USDC_TESTNET = '0x...' // Deploy test token or use existing
// Add testnet to MetaMask:
Network Name: BSC Testnet
RPC URL: https://data-seed-prebsc-1-s1.binance.org:8545/
Chain ID: 97
Symbol: BNB
Block Explorer: https://testnet.bscscan.com
# Start server
node server.js
# Open browser
http://localhost:3000
# Create payment link
1. Connect MetaMask
2. Fill form with test data
3. Generate link
# Test payment
1. Open payment link in new tab
2. Connect wallet
3. Deposit test USDC
4. Complete payment
# Clone repository
git clone https://github.com/your-repo/cryptpal-x402.git
cd cryptpal-x402
# Install dependencies
npm install express cors ethers@5.7.2
# Configure environment
cp .env.example .env
nano .env
# Set relayer private key
RELAYER_PRIVATE_KEY=0xYOUR_KEY_HERE
PORT=3000
# Start server
node server.js
# Install PM2
npm install -g pm2
# Start with PM2
pm2 start server.js --name cryptpal-x402
# Enable startup on boot
pm2 startup
pm2 save
# View logs
pm2 logs cryptpal-x402
# Monitor
pm2 monit
server {
listen 80;
server_name your-domain.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
BSC offers lower transaction fees (~$0.10-0.20) compared to Ethereum ($5-50), making it more practical for small payments.
Users deposit USDC to the relayer wallet once. The server then executes payments on their behalf using these deposits, paying the gas fees itself.
The relayer wallet is controlled by the server operator. Only deposit amounts you're comfortable with for gasless payments. For larger purchases, use the normal payment method.
In the current version, deposits are stored in-memory and used for payments. For production, implement a withdrawal feature.
For gasless payments, the amount is refunded to your balance. For normal payments, the transaction simply fails and no USDC is deducted.
Yes, modify the USDC_ADDRESS constant to any BEP-20 token contract address. Adjust decimals accordingly (USDC uses 6, most tokens use 18).
Each gasless transaction costs ~$0.20 in BNB. With 0.1 BNB (~$60), you can process approximately 300 gasless payments.
Yes, modify the HTML template in the server.js file under the `/api/pay` endpoint response.
CryptPal x402 is released under the MIT License.
MIT License
Copyright (c) 2025 CryptPal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.