How It Works
EpPay uses a secure server-to-server callback architecture. The callback URL is set by the merchant at payment creation and cannot be tampered with by the mobile app.
Payment Flow
Your app/website sends POST /api/v2/create-payment with amount, wallet, network, token, and callback URL. EpPay returns a payment_id and qr_data.
Your app displays the QR code (from qr_data) to the customer. The QR encodes the payment ID for the EpPay mobile app.
Customer scans the QR with the EpPay mobile app, reviews the payment details, and approves the blockchain transaction.
After the blockchain transaction is confirmed, the mobile app sends the transaction proof (tx hash, sender address) to POST /api/v2/payments/{id}/verify.
EpPay saves the payment as completed and sends a server-to-server POST to your callback URL with the payment details (payment_id, amount, tx_hash, from, network).
EpPay returns a success response to the mobile app, which displays a confirmation screen to the customer.
Your frontend polls GET /api/v2/payments/{id}/status every 3-5 seconds. When confirmed is true, show the success screen to the customer.
Why this architecture? The callback URL is stored server-side at payment creation by the merchant — the mobile app never sees or touches it. This prevents callback URL tampering and ensures server-to-server delivery even if the customer's browser disconnects.
Merchant App EpPay Server EpPay Mobile App Blockchain
| | | |
| POST /api/v2/create-payment | | |
| (amount, to, network, | | |
| token_type, callback_url) | | |
|------------------------------>| | |
| | Stores payment + callback | |
| { payment_id, qr_data, ... } | | |
|<------------------------------| | |
| | | |
| Display QR code | | |
| | Scan QR code | |
| |<-----------------------------| |
| | Payment info | |
| |----------------------------->| |
| | | |
| | | Send transaction |
| | |--------------------->|
| | | TX confirmed |
| | |<---------------------|
| | | |
| | POST /verify (txHash, from) | |
| |<-----------------------------| |
| | | |
| POST callback_url | Saves payment, fires callback| |
| (payment_id, tx_hash, ...) | | |
|<------------------------------| | |
| | { success, payment_id } | |
| |----------------------------->| |
| | | Show success |
| | | |
| Poll GET /status | | |
|------------------------------>| | |
| { confirmed: true } | | |
|<------------------------------| | |
| Show success page | | |
| | | |
Quick Start
Accept crypto payments in 3 steps:
Get your API key
Register and generate an API key from your dashboard.
Create a payment
Send a POST request to POST /api/v2/create-payment:
curl -X POST https://eppay.io/api/v2/create-payment \
-H "Content-Type: application/json" \
-d '{
"apiKey": "YOUR_API_KEY",
"amount": "25.00",
"to": "0xYourWalletAddress",
"network": "bsc",
"token_type": "USDT",
"success": "https://yoursite.com/payment-callback"
}'
Poll for payment status
Use the returned payment_id to poll GET /api/v2/payments/{payment_id}/status every 3-5 seconds. When confirmed is true, the payment is done. Your callback URL also receives a server-to-server POST automatically.
Even easier? Use the Checkout Widget (drop-in JS) or the Laravel Package for server-side integration.
Create Payment
Creates a new payment and returns a rich response with QR data and payment URL.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| apiKey | String | Yes | Your EpPay API key |
| amount | String | Yes | Payment amount (e.g. "25.00") |
| to | String | Yes | Your wallet address to receive the payment |
| network | String | Yes | Network slug: "bsc", "eth", "polygon", etc. See Supported Networks |
| token_type | String | Yes | "USDT" or "USDC" |
| success | String | No | Your server callback URL — receives a POST when payment is confirmed |
Response
{
"payment_id": "8a020135-19b7-42df-be4b-1a8722ad0570",
"amount": "25.00",
"network": "bsc",
"token_type": "USDT",
"to": "0xYourWalletAddress",
"status": "pending",
"qr_data": "product=uuideppay&id=8a020135-19b7-42df-be4b-1a8722ad0570",
"payment_url": "https://eppay.io/payment/8a020135-19b7-42df-be4b-1a8722ad0570",
"created_at": "2026-02-28T12:00:00+00:00",
"is_existing": false
}
QR Code
Use the qr_data field to generate a QR code. The customer scans it with the EpPay mobile app to approve the payment.
product=uuideppay&id=PAYMENT_ID
Check Payment Status
Rich status including network, transaction hash, sender address, and timestamps.
Response (Pending)
{
"payment_id": "8a020135-...",
"status": "pending",
"confirmed": false,
"amount": "25.00",
"network": "bsc",
"token_type": "USDT",
"tx_hash": null,
"from": null,
"completed_at": null
}
Response (Completed)
{
"payment_id": "8a020135-...",
"status": "completed",
"confirmed": true,
"amount": "25.00",
"network": "bsc",
"token_type": "USDT",
"tx_hash": "0xabc123...",
"from": "0xSenderAddress",
"completed_at": "2026-02-28T12:05:30+00:00"
}
Tip: Poll every 3-5 seconds until confirmed is true. Set a timeout (e.g. 30 minutes) to stop polling. Your callback URL is also notified server-to-server.
Payment Details
Full payment object with nested network details.
{
"payment_id": "8a020135-...",
"amount": "25.00",
"to": "0xYourWalletAddress",
"from": "0xSenderAddress",
"network": {
"slug": "bsc",
"name": "binance",
"coin": "BNB"
},
"token_type": "USDT",
"status": "completed",
"tx_hash": "0xabc123...",
"created_at": "2026-02-28T12:00:00+00:00",
"completed_at": "2026-02-28T12:05:30+00:00"
}
Verify Payment
Called by the EpPay mobile app after the blockchain transaction is confirmed. Triggers the merchant callback.
Request Parameters
| Parameter | Type | Description |
|---|---|---|
| status | String | Must be "success" |
| txHash | String | On-chain transaction hash |
| from | String | Sender wallet address |
Response
{
"success": true,
"message": "Payment verified successfully",
"payment_id": "8a020135-...",
"status": "completed",
"tx_hash": "0xabc123...",
"amount": "25.00",
"completed_at": "2026-02-28T12:05:30+00:00"
}
Merchant Callback (server-to-server)
EpPay POSTs to your success callback URL:
{
"success": "success",
"message": "Payment verified successfully",
"payment_id": "8a020135-...",
"amount": "25.00",
"tx_hash": "0xabc123...",
"from": "0xSenderAddress",
"token_type": "USDT",
"network": "bsc"
}
Networks API
Returns all supported blockchain networks with available tokens.
[
{
"slug": "bsc",
"name": "binance",
"coin": "BNB",
"chain_id": 56,
"explorer": "https://bscscan.com",
"tokens": [
{ "type": "USDT", "available": true },
{ "type": "USDC", "available": true }
]
}
]
Laravel Package
The eppay/laravel-eppay package provides a clean Facade, Blade components, and automatic status polling for Laravel applications.
Installation
composer require eppay/laravel-eppay
Publish Config
php artisan vendor:publish --tag=eppay-config
Environment Variables
EPPAY_API_KEY=your_api_key_here
EPPAY_DEFAULT_BENEFICIARY=0xYourWalletAddress
EPPAY_DEFAULT_NETWORK=bsc
EPPAY_DEFAULT_TOKEN_TYPE=USDT
EPPAY_SUCCESS_URL=https://yoursite.com/eppay/callback
Usage
Create a Payment
use EpPay\LaravelEpPay\Facades\EpPay;
// Create payment with defaults from .env
$payment = EpPay::createPayment(amount: 25.00);
// Or specify everything
$payment = EpPay::createPayment(
amount: 25.00,
to: '0xWalletAddress',
network: 'bsc',
tokenType: 'USDT',
successUrl: route('payment.callback'),
);
// Response:
// $payment['payment_id'] → "8a020135-..."
// $payment['qr_data'] → "product=uuideppay&id=..."
// $payment['payment_url'] → "https://eppay.io/payment/..."
// $payment['network'] → "bsc"
// $payment['token_type'] → "USDT"
Check Payment Status
// Rich status response
$status = EpPay::checkStatus($paymentId);
// $status['confirmed'] → true/false
// $status['status'] → "pending" or "completed"
// $status['tx_hash'] → "0x..." (when completed)
// $status['from'] → "0x..." (sender address)
// $status['completed_at'] → "2026-02-28T..."
// Simple boolean check
if (EpPay::isPaymentCompleted($paymentId)) {
// Payment is done!
}
// Full payment details (with nested network object)
$details = EpPay::getPaymentDetails($paymentId);
QR Code Generation
// Get QR data string
$qrData = EpPay::getQrCodeData($paymentId);
// → "product=uuideppay&id=8a020135-..."
// Get QR as base64 SVG (for img src)
$qrUrl = EpPay::getQrCodeUrl($paymentId, 300);
// → "data:image/svg+xml;base64,..."
// Get payment page URL
$url = EpPay::getPaymentUrl($paymentId);
// → "https://eppay.io/payment/8a020135-..."
Blade Component
<!-- Auto-polling QR code component -->
<x-eppay-payment-qr
:payment-id="$paymentId"
:auto-refresh="true"
success-url="/payment/success"
cancel-url="/payment/cancel"
/>
Handle Callback
// routes/web.php
Route::post('/eppay/callback', [PaymentController::class, 'handleCallback']);
// In your controller:
public function handleCallback(Request $request)
{
$paymentId = $request->input('payment_id');
$txHash = $request->input('tx_hash');
$amount = $request->input('amount');
$network = $request->input('network');
// Verify payment is actually complete (double-check)
if (!EpPay::isPaymentCompleted($paymentId)) {
return response()->json(['error' => 'Not confirmed'], 400);
}
// Update your order
Order::where('payment_id', $paymentId)
->update(['status' => 'paid', 'tx_hash' => $txHash]);
return response()->json(['received' => true]);
}
Available Networks
$networks = EpPay::getNetworks();
// Returns array of networks with slug, name, coin, tokens
JavaScript Checkout Widget
Drop-in payment widget that handles network/token selection, QR code display, and automatic payment status polling. No build tools or dependencies required.
Installation
Add the script tag to your page:
<script src="https://eppay.io/js/eppay-checkout.js"></script>
Usage
<div id="eppay-checkout"></div>
<script src="https://eppay.io/js/eppay-checkout.js"></script>
<script>
EpPayCheckout.init({
container: '#eppay-checkout',
apiKey: 'YOUR_API_KEY',
to: '0xYourWalletAddress',
amount: 25.00, // Fixed amount (omit for variable)
successUrl: 'https://yoursite.com/callback', // Server callback URL
onComplete: function(paymentId) {
console.log('Payment completed:', paymentId);
window.location.href = '/thank-you?payment=' + paymentId;
}
});
</script>
Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
| container | String | Yes | CSS selector for the container element |
| apiKey | String | Yes | Your EpPay API key |
| to | String | Yes | Your wallet address to receive payments |
| amount | Number | No | Fixed amount. Omit for customer-editable input. |
| successUrl | String | No | Server callback URL — receives POST on payment confirmation |
| onComplete | Function | No | Client-side callback when payment is confirmed. Receives paymentId. |
| baseUrl | String | No | Override API base URL (default: https://eppay.io) |
Widget Flow
- Widget loads and fetches available networks from
GET /api/v2/networks - Customer selects a blockchain network and token type (USDT or USDC)
- If amount is variable, customer enters the payment amount
- Widget creates payment via
POST /api/v2/create-payment - QR code is displayed for the customer to scan with EpPay mobile app
- Widget auto-polls
GET /api/v2/payments/{id}/statusevery 3 seconds - On confirmation, success screen is shown and
onCompletecallback fires
Hosted Checkout Page
Redirect customers to the hosted checkout instead of embedding:
https://eppay.io/checkout?apiKey=YOUR_API_KEY&to=0xYourWallet&amount=25.00&success=https://yoursite.com/callback
CORS Enabled: The widget JS and all /api/* endpoints support cross-origin requests from any domain.
Supported Networks
Use the slug value as the network parameter in your API requests.
Binance
bsc
Ethereum
eth
Scimatic
scimatic
Avalanche
avalanche
Polygon
polygon
Fantom
fantom
Cronos
cronos
Arbitrum
arbitrum
Cosmos
cosmos
Celo
celo
Network Reference Table
| Network | Slug | Coin | USDT | USDC |
|---|---|---|---|---|
| Binance | bsc |
BNB | ✓ | ✓ |
| Ethereum | eth |
ETH | ✓ | ✓ |
| Scimatic | scimatic |
SCI | ✓ | ✗ |
| Avalanche | avalanche |
AVAX | ✓ | ✓ |
| Polygon | polygon |
MATIC | ✓ | ✓ |
| Fantom | fantom |
FTM | ✓ | ✓ |
| Cronos | cronos |
CRO | ✓ | ✓ |
| Arbitrum | arbitrum |
ARB | ✓ | ✓ |
| Cosmos | cosmos |
ATOM | ✓ | ✗ |
| Celo | celo |
CELO | ✓ | ✓ |
Code Examples
JavaScript (Vanilla)
// 1. Create a payment
const response = await fetch('https://eppay.io/api/v2/create-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: 'YOUR_API_KEY',
amount: '25.00',
to: '0xYourWalletAddress',
network: 'bsc',
token_type: 'USDT',
success: 'https://yoursite.com/payment-callback'
})
});
const data = await response.json();
console.log('Payment ID:', data.payment_id);
console.log('QR data:', data.qr_data);
console.log('Payment URL:', data.payment_url);
// 2. Display QR code (using any QR library)
generateQR(data.qr_data);
// 3. Poll for status
const poll = setInterval(async () => {
const res = await fetch(
`https://eppay.io/api/v2/payments/${data.payment_id}/status`
);
const status = await res.json();
if (status.confirmed) {
clearInterval(poll);
console.log('Payment confirmed!');
console.log('TX Hash:', status.tx_hash);
console.log('From:', status.from);
window.location.href = '/success?id=' + data.payment_id;
}
}, 3000);
PHP (cURL)
<?php
// 1. Create a payment
$ch = curl_init('https://eppay.io/api/v2/create-payment');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'apiKey' => 'YOUR_API_KEY',
'amount' => '25.00',
'to' => '0xYourWalletAddress',
'network' => 'bsc',
'token_type' => 'USDT',
'success' => 'https://yoursite.com/payment-callback',
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
$paymentId = $result['payment_id'];
echo "QR Data: " . $result['qr_data'];
echo "Payment URL: " . $result['payment_url'];
// 2. Check status
$status = json_decode(
file_get_contents("https://eppay.io/api/v2/payments/{$paymentId}/status"),
true
);
if ($status['confirmed']) {
echo "Paid! TX: " . $status['tx_hash'];
}
Python
import requests, time
# 1. Create payment
resp = requests.post('https://eppay.io/api/v2/create-payment', json={
'apiKey': 'YOUR_API_KEY',
'amount': '25.00',
'to': '0xYourWalletAddress',
'network': 'bsc',
'token_type': 'USDT',
'success': 'https://yoursite.com/callback'
})
data = resp.json()
print(f"Payment: {data['payment_id']}")
print(f"QR: {data['qr_data']}")
# 2. Poll for confirmation
while True:
status = requests.get(
f"https://eppay.io/api/v2/payments/{data['payment_id']}/status"
).json()
if status['confirmed']:
print(f"Confirmed! TX: {status['tx_hash']}")
break
time.sleep(3)
Laravel (using eppay/laravel-eppay)
<?php
use EpPay\LaravelEpPay\Facades\EpPay;
// Create payment (uses .env defaults)
$payment = EpPay::createPayment(
amount: 25.00,
successUrl: route('payment.callback'),
);
// Redirect to payment page or show QR
return view('payment', [
'paymentId' => $payment['payment_id'],
'qrData' => $payment['qr_data'],
]);