Skip to content

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/execute

Authentication

This endpoint requires API key authentication:

Authorization: Bearer YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
orderIdstringOrder identifier from Create Order API
userAddressstringUser's wallet address
gasSettingsobjectCustom gas price settings
deadlinenumberTransaction 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

FieldTypeDescription
executionPlanobjectOverview of the payment execution
transactionsarrayStep-by-step transaction data
monitoringobjectInstructions for tracking payment progress
validUntilnumberExpiration timestamp for transaction data

Transaction Object Fields

FieldTypeDescription
stepIdnumberStep sequence number
typestringTransaction type (approval, swap, bridge)
descriptionstringHuman-readable description
chainIdnumberBlockchain network ID
tostringTarget contract address
datastringEncoded transaction data
valuestringETH value to send (usually "0")
gasLimitstringGas limit for the transaction
noncenumberTransaction nonce
requiredbooleanWhether this step is mandatory

Transaction Types

TypeDescriptionWhen Used
approvalERC-20 token approvalWhen user needs to approve token spending
permitEIP-2612 permit signatureAlternative to approval for supported tokens
swapToken swap on DEXWhen token conversion is needed
bridgeCross-chain bridgeWhen transferring between networks
transferDirect token transferFor 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:

  1. Query Status - Monitor payment progress
  2. Webhook Setup - Configure real-time notifications

Support