Execute Payment API
Process a cross-chain payment by generating transaction data for user wallet execution. This API provides the transaction plan that users need to sign and broadcast.
Endpoint
POST /v1/payment/executeAuthentication
This endpoint requires API key authentication:
Authorization: Bearer YOUR_API_KEYRequest Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orderId | string | ✅ | Order identifier from Create Order API |
userAddress | string | ✅ | User's wallet address |
gasSettings | object | ❌ | Custom gas price settings |
deadline | number | ❌ | Transaction deadline (Unix timestamp) |
GasSettings Object
interface GasSettings {
gasLimit?: string; // Custom gas limit
maxFeePerGas?: string; // Maximum fee per gas (EIP-1559)
maxPriorityFeePerGas?: string; // Maximum priority fee per gas
gasPrice?: string; // Gas price for legacy transactions
}Example Request
{
"orderId": "order_1759231185333_ghi789",
"userAddress": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8e8",
"gasSettings": {
"maxFeePerGas": "20000000000",
"maxPriorityFeePerGas": "2000000000"
},
"deadline": 1759234785
}Response Format
Success Response
{
"success": true,
"data": {
"orderId": "order_1759231185333_ghi789",
"executionPlan": {
"totalSteps": 3,
"estimatedTime": 420,
"totalGasEstimate": "650000",
"totalGasCostUsd": "15.50"
},
"transactions": [
{
"stepId": 1,
"type": "approval",
"description": "Approve USDC.e spending",
"chainId": 10,
"to": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607",
"data": "0x095ea7b3000000000000000000000000...",
"value": "0",
"gasLimit": "46000",
"maxFeePerGas": "20000000000",
"maxPriorityFeePerGas": "2000000000",
"nonce": 42,
"required": true
},
{
"stepId": 2,
"type": "swap",
"description": "Swap USDC.e to USDC on Optimism",
"chainId": 10,
"to": "0x89415a82d909a7238d69094C3Dd1dCC1aCbDa85C",
"data": "0x3593564c000000000000000000000000...",
"value": "0",
"gasLimit": "300000",
"maxFeePerGas": "20000000000",
"maxPriorityFeePerGas": "2000000000",
"nonce": 43,
"required": true
},
{
"stepId": 3,
"type": "bridge",
"description": "Bridge USDC from Optimism to Polygon",
"chainId": 10,
"to": "0x89415a82d909a7238d69094C3Dd1dCC1aCbDa85C",
"data": "0x7c025200000000000000000000000000...",
"value": "0",
"gasLimit": "304000",
"maxFeePerGas": "20000000000",
"maxPriorityFeePerGas": "2000000000",
"nonce": 44,
"required": true
}
],
"monitoring": {
"statusEndpoint": "/v1/payment/status/order_1759231185333_ghi789",
"webhookEvents": ["payment.started", "payment.bridging", "payment.completed"],
"pollInterval": 5000
},
"validUntil": 1759234785
},
"timestamp": "2024-01-01T00:00:00Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
executionPlan | object | Overview of the payment execution |
transactions | array | Step-by-step transaction data |
monitoring | object | Instructions for tracking payment progress |
validUntil | number | Expiration timestamp for transaction data |
Transaction Object Fields
| Field | Type | Description |
|---|---|---|
stepId | number | Step sequence number |
type | string | Transaction type (approval, swap, bridge) |
description | string | Human-readable description |
chainId | number | Blockchain network ID |
to | string | Target contract address |
data | string | Encoded transaction data |
value | string | ETH value to send (usually "0") |
gasLimit | string | Gas limit for the transaction |
nonce | number | Transaction nonce |
required | boolean | Whether this step is mandatory |
Transaction Types
| Type | Description | When Used |
|---|---|---|
approval | ERC-20 token approval | When user needs to approve token spending |
permit | EIP-2612 permit signature | Alternative to approval for supported tokens |
swap | Token swap on DEX | When token conversion is needed |
bridge | Cross-chain bridge | When transferring between networks |
transfer | Direct token transfer | For same-chain payments |
Error Responses
Order Not Found
{
"success": false,
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order not found or expired",
"details": {
"orderId": "order_1759231185333_ghi789"
}
},
"timestamp": "2024-01-01T00:00:00Z"
}Insufficient Balance
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "User has insufficient balance for payment",
"details": {
"required": "100.50",
"available": "50.25",
"token": "USDC.e",
"chainId": 10,
"userAddress": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8e8"
}
},
"timestamp": "2024-01-01T00:00:00Z"
}Route Not Available
{
"success": false,
"error": {
"code": "ROUTE_NOT_AVAILABLE",
"message": "Payment route is temporarily unavailable",
"details": {
"reason": "Bridge maintenance",
"estimatedResolution": 1759235000,
"alternativeRoutes": []
}
},
"timestamp": "2024-01-01T00:00:00Z"
}Code Examples
JavaScript/TypeScript
import { CyberPaySDK } from '@cyberpay/sdk';
const sdk = new CyberPaySDK({
apiKey: 'YOUR_API_KEY',
environment: 'production'
});
async function executePayment(orderId: string, userAddress: string) {
try {
// Get execution plan
const execution = await sdk.payment.execute({
orderId,
userAddress,
gasSettings: {
maxFeePerGas: '20000000000',
maxPriorityFeePerGas: '2000000000'
}
});
console.log('Execution plan:', execution);
// Execute transactions sequentially
const txHashes = [];
for (const tx of execution.transactions) {
console.log(`Executing step ${tx.stepId}: ${tx.description}`);
// Send transaction using user's wallet
const txHash = await window.ethereum.request({
method: 'eth_sendTransaction',
params: [{
from: userAddress,
to: tx.to,
data: tx.data,
value: tx.value,
gas: `0x${parseInt(tx.gasLimit).toString(16)}`,
maxFeePerGas: `0x${parseInt(tx.maxFeePerGas).toString(16)}`,
maxPriorityFeePerGas: `0x${parseInt(tx.maxPriorityFeePerGas).toString(16)}`
}]
});
txHashes.push(txHash);
console.log(`Step ${tx.stepId} transaction hash:`, txHash);
// Wait for confirmation before next step
await waitForConfirmation(txHash);
}
// Monitor payment status
const finalStatus = await monitorPaymentStatus(orderId);
console.log('Payment completed:', finalStatus);
return { txHashes, finalStatus };
} catch (error) {
console.error('Payment execution failed:', error);
throw error;
}
}
async function waitForConfirmation(txHash: string): Promise<void> {
return new Promise((resolve, reject) => {
const checkConfirmation = async () => {
try {
const receipt = await window.ethereum.request({
method: 'eth_getTransactionReceipt',
params: [txHash]
});
if (receipt && receipt.status === '0x1') {
resolve();
} else if (receipt && receipt.status === '0x0') {
reject(new Error('Transaction failed'));
} else {
// Still pending, check again in 2 seconds
setTimeout(checkConfirmation, 2000);
}
} catch (error) {
reject(error);
}
};
checkConfirmation();
});
}
async function monitorPaymentStatus(orderId: string) {
const maxAttempts = 120; // 10 minutes with 5-second intervals
let attempts = 0;
while (attempts < maxAttempts) {
const status = await sdk.payment.getStatus(orderId);
console.log(`Payment ${orderId} status: ${status.status}`);
if (['completed', 'failed'].includes(status.status)) {
return status;
}
await new Promise(resolve => setTimeout(resolve, 5000));
attempts++;
}
throw new Error('Payment monitoring timeout');
}React Hook Example
import { useState, useCallback } from 'react';
import { CyberPaySDK } from '@cyberpay/sdk';
export function usePaymentExecution() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [currentStep, setCurrentStep] = useState(0);
const [txHashes, setTxHashes] = useState<string[]>([]);
const executePayment = useCallback(async (orderId: string, userAddress: string) => {
setLoading(true);
setError(null);
setCurrentStep(0);
setTxHashes([]);
try {
const sdk = new CyberPaySDK({ apiKey: process.env.REACT_APP_CYBERPAY_API_KEY });
// Get execution plan
const execution = await sdk.payment.execute({ orderId, userAddress });
// Execute each transaction
const hashes: string[] = [];
for (let i = 0; i < execution.transactions.length; i++) {
const tx = execution.transactions[i];
setCurrentStep(i + 1);
// Request user signature
const txHash = await window.ethereum.request({
method: 'eth_sendTransaction',
params: [{
from: userAddress,
to: tx.to,
data: tx.data,
value: tx.value,
gas: `0x${parseInt(tx.gasLimit).toString(16)}`
}]
});
hashes.push(txHash);
setTxHashes([...hashes]);
// Wait for confirmation
await waitForConfirmation(txHash);
}
// Monitor final status
const finalStatus = await monitorPaymentStatus(orderId);
setLoading(false);
return { txHashes: hashes, status: finalStatus };
} catch (err: any) {
setError(err.message);
setLoading(false);
throw err;
}
}, []);
return {
executePayment,
loading,
error,
currentStep,
txHashes
};
}cURL Example
curl -X POST https://api.cyberpay.org/v1/payment/execute \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "order_1759231185333_ghi789",
"userAddress": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8e8",
"gasSettings": {
"maxFeePerGas": "20000000000",
"maxPriorityFeePerGas": "2000000000"
}
}'Integration Patterns
Sequential Execution
Execute transactions one by one, waiting for confirmation:
async function executeSequentially(transactions, userAddress) {
const results = [];
for (const tx of transactions) {
const txHash = await sendTransaction(tx, userAddress);
await waitForConfirmation(txHash);
results.push({ stepId: tx.stepId, txHash });
}
return results;
}Parallel Execution (Same Chain)
For same-chain transactions, execute in parallel with proper nonce management:
async function executeParallel(transactions, userAddress) {
const promises = transactions.map(async (tx) => {
const txHash = await sendTransaction(tx, userAddress);
return { stepId: tx.stepId, txHash };
});
return Promise.all(promises);
}Error Recovery
Handle failed transactions with retry logic:
async function executeWithRetry(tx, userAddress, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const txHash = await sendTransaction(tx, userAddress);
await waitForConfirmation(txHash);
return txHash;
} catch (error) {
if (attempt === maxRetries) throw error;
console.log(`Attempt ${attempt} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
}Best Practices
Gas Management
- Use dynamic gas pricing based on network conditions
- Provide gas estimation to users before execution
- Allow users to customize gas settings
- Monitor gas price trends for optimal timing
User Experience
- Show clear progress indicators for multi-step payments
- Provide estimated completion times
- Allow users to cancel pending transactions
- Display transaction hashes for tracking
Error Handling
- Implement comprehensive error recovery
- Provide clear error messages to users
- Log all transaction attempts for debugging
- Handle network-specific errors appropriately
Security
- Validate all transaction data before signing
- Verify contract addresses and function calls
- Implement transaction simulation when possible
- Use secure wallet connection methods
Rate Limits
- Standard: 50 executions per minute
- Premium: 500 executions per minute
- Enterprise: Custom limits available
Next Steps
After executing payment:
- Query Status - Monitor payment progress
- Webhook Setup - Configure real-time notifications
Support
- 📧 Email: support@cyberpay.org
- 💬 Telegram: @cyberpay_support
- 📖 Documentation: docs.cyberpay.org
