Query Status API
Monitor the progress of cross-chain payments in real-time. This API provides detailed status information and transaction history for orders.
Endpoint
GET /v1/payment/status/{orderId}Authentication
This endpoint requires API key authentication:
Authorization: Bearer YOUR_API_KEYPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orderId | string | ✅ | Order identifier to query |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
includeTransactions | boolean | ❌ | Include transaction details (default: false) |
includeEvents | boolean | ❌ | Include event history (default: false) |
Example Request
GET /v1/payment/status/order_1759231185333_ghi789?includeTransactions=true&includeEvents=true
Authorization: Bearer YOUR_API_KEYResponse Format
Success Response
{
"success": true,
"data": {
"orderId": "order_1759231185333_ghi789",
"checkoutId": "checkout_1759231185333_abc123",
"status": "completed",
"substatus": "settled",
"progress": {
"currentStep": 3,
"totalSteps": 3,
"percentage": 100,
"estimatedCompletion": null
},
"payment": {
"paymentAmount": "100.50",
"settlementAmount": "100.00",
"actualReceived": "100.00",
"paymentToken": {
"symbol": "USDC.e",
"address": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607",
"chainId": 10
},
"settlementToken": {
"symbol": "USDC",
"address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"chainId": 137
}
},
"timing": {
"createdAt": 1759231185,
"startedAt": 1759231200,
"completedAt": 1759231605,
"totalDuration": 420,
"estimatedDuration": 420
},
"fees": {
"total": {
"amount": "0.50",
"amountUsd": "0.50"
},
"breakdown": {
"networkFees": "0.20",
"bridgeFees": "0.15",
"platformFee": "0.15"
}
},
"transactions": [
{
"stepId": 1,
"type": "approval",
"status": "confirmed",
"txHash": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"chainId": 10,
"blockNumber": 118234567,
"gasUsed": "46000",
"gasCost": "0.001",
"timestamp": 1759231215
},
{
"stepId": 2,
"type": "swap",
"status": "confirmed",
"txHash": "0x2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c",
"chainId": 10,
"blockNumber": 118234580,
"gasUsed": "299230",
"gasCost": "0.006",
"amountIn": "100.50",
"amountOut": "100.25",
"timestamp": 1759231245
},
{
"stepId": 3,
"type": "bridge",
"status": "confirmed",
"txHash": "0x3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d",
"chainId": 10,
"blockNumber": 118234590,
"destinationTxHash": "0x4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e",
"destinationChainId": 137,
"destinationBlockNumber": 52847291,
"gasUsed": "304000",
"gasCost": "0.007",
"amountIn": "100.25",
"amountOut": "100.00",
"bridgeFee": "0.15",
"timestamp": 1759231605
}
],
"events": [
{
"type": "order_created",
"timestamp": 1759231185,
"message": "Order created successfully"
},
{
"type": "payment_started",
"timestamp": 1759231200,
"message": "User initiated payment"
},
{
"type": "approval_confirmed",
"timestamp": 1759231215,
"message": "Token approval confirmed",
"txHash": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
},
{
"type": "swap_completed",
"timestamp": 1759231245,
"message": "Token swap completed on source chain",
"txHash": "0x2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c"
},
{
"type": "bridge_initiated",
"timestamp": 1759231250,
"message": "Cross-chain bridge initiated"
},
{
"type": "bridge_completed",
"timestamp": 1759231605,
"message": "Cross-chain bridge completed",
"txHash": "0x4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e"
},
{
"type": "payment_completed",
"timestamp": 1759231605,
"message": "Payment successfully completed"
}
],
"metadata": {
"customerNote": "Express delivery requested",
"referralCode": "FRIEND20"
}
},
"timestamp": "2024-01-01T00:00:00Z"
}Status Values
Primary Status
| Status | Description |
|---|---|
pending_payment | Waiting for user to initiate payment |
processing | Payment is being processed |
bridging | Cross-chain transfer in progress |
settling | Final settlement in progress |
completed | Payment successfully completed |
failed | Payment failed |
expired | Order expired without payment |
cancelled | Order cancelled |
Substatus Values
| Substatus | Description |
|---|---|
awaiting_approval | Waiting for token approval |
swapping | Token swap in progress |
bridging | Cross-chain bridge in progress |
confirming | Waiting for block confirmations |
settled | Final settlement confirmed |
refunding | Refund in progress |
refunded | Refund completed |
Transaction Status
| Status | Description |
|---|---|
pending | Transaction submitted, waiting for confirmation |
confirmed | Transaction confirmed on blockchain |
failed | Transaction failed |
replaced | Transaction was replaced (higher gas) |
Error Responses
Order Not Found
{
"success": false,
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order not found",
"details": {
"orderId": "order_1759231185333_ghi789"
}
},
"timestamp": "2024-01-01T00:00:00Z"
}Access Denied
{
"success": false,
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to access this order",
"details": {
"orderId": "order_1759231185333_ghi789"
}
},
"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 queryPaymentStatus(orderId: string) {
try {
const status = await sdk.payment.getStatus(orderId, {
includeTransactions: true,
includeEvents: true
});
console.log('Payment status:', status);
// Check if payment is complete
if (status.status === 'completed') {
console.log('Payment completed successfully!');
console.log('Amount received:', status.payment.actualReceived);
return status;
}
// Check if payment failed
if (status.status === 'failed') {
console.log('Payment failed:', status.failureReason);
return status;
}
// Payment still in progress
console.log(`Payment in progress: ${status.progress.percentage}%`);
console.log('Current step:', status.progress.currentStep, 'of', status.progress.totalSteps);
return status;
} catch (error) {
console.error('Error querying payment status:', error);
throw error;
}
}
// Monitor payment with polling
async function monitorPayment(orderId: string, onUpdate?: (status: any) => void) {
const maxAttempts = 120; // 10 minutes with 5-second intervals
let attempts = 0;
while (attempts < maxAttempts) {
try {
const status = await queryPaymentStatus(orderId);
if (onUpdate) {
onUpdate(status);
}
// Check if payment is in final state
if (['completed', 'failed', 'expired', 'cancelled'].includes(status.status)) {
return status;
}
// Wait before next check
await new Promise(resolve => setTimeout(resolve, 5000));
attempts++;
} catch (error) {
console.error('Error monitoring payment:', error);
attempts++;
}
}
throw new Error('Payment monitoring timeout');
}React Hook Example
import { useState, useEffect, useCallback } from 'react';
import { CyberPaySDK } from '@cyberpay/sdk';
export function usePaymentStatus(orderId: string, pollInterval: number = 5000) {
const [status, setStatus] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchStatus = useCallback(async () => {
try {
const sdk = new CyberPaySDK({ apiKey: process.env.REACT_APP_CYBERPAY_API_KEY });
const result = await sdk.payment.getStatus(orderId, {
includeTransactions: true,
includeEvents: true
});
setStatus(result);
setError(null);
// Stop polling if payment is in final state
if (['completed', 'failed', 'expired', 'cancelled'].includes(result.status)) {
setLoading(false);
return false; // Stop polling
}
return true; // Continue polling
} catch (err: any) {
setError(err.message);
return false; // Stop polling on error
}
}, [orderId]);
useEffect(() => {
let intervalId: NodeJS.Timeout;
const startPolling = async () => {
// Initial fetch
const shouldContinue = await fetchStatus();
if (shouldContinue) {
// Set up polling
intervalId = setInterval(async () => {
const shouldContinue = await fetchStatus();
if (!shouldContinue) {
clearInterval(intervalId);
}
}, pollInterval);
}
};
startPolling();
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [fetchStatus, pollInterval]);
return { status, loading, error, refetch: fetchStatus };
}
// Usage in component
function PaymentStatusComponent({ orderId }: { orderId: string }) {
const { status, loading, error } = usePaymentStatus(orderId);
if (loading) return <div>Loading payment status...</div>;
if (error) return <div>Error: {error}</div>;
if (!status) return null;
return (
<div className="payment-status">
<h3>Payment Status: {status.status}</h3>
{status.progress && (
<div className="progress">
<div className="progress-bar" style={{ width: `${status.progress.percentage}%` }} />
<span>Step {status.progress.currentStep} of {status.progress.totalSteps}</span>
</div>
)}
{status.status === 'completed' && (
<div className="success">
✅ Payment completed successfully!
<br />
Amount received: {status.payment.actualReceived} {status.payment.settlementToken.symbol}
</div>
)}
{status.status === 'failed' && (
<div className="error">
❌ Payment failed: {status.failureReason}
</div>
)}
{status.transactions && (
<div className="transactions">
<h4>Transactions:</h4>
{status.transactions.map((tx: any) => (
<div key={tx.stepId} className="transaction">
<span>{tx.type}</span>
<span>{tx.status}</span>
{tx.txHash && (
<a href={`https://etherscan.io/tx/${tx.txHash}`} target="_blank" rel="noopener noreferrer">
View on Explorer
</a>
)}
</div>
))}
</div>
)}
</div>
);
}cURL Example
# Basic status query
curl -X GET "https://api.cyberpay.org/v1/payment/status/order_1759231185333_ghi789" \
-H "Authorization: Bearer YOUR_API_KEY"
# With detailed information
curl -X GET "https://api.cyberpay.org/v1/payment/status/order_1759231185333_ghi789?includeTransactions=true&includeEvents=true" \
-H "Authorization: Bearer YOUR_API_KEY"Python Example
import requests
import time
def query_payment_status(order_id, include_transactions=False, include_events=False):
url = f"https://api.cyberpay.org/v1/payment/status/{order_id}"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
params = {
"includeTransactions": include_transactions,
"includeEvents": include_events
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error: {response.json()}")
def monitor_payment(order_id, max_attempts=120, poll_interval=5):
"""Monitor payment status with polling"""
attempts = 0
while attempts < max_attempts:
try:
status = query_payment_status(order_id, True, True)
print(f"Payment status: {status['data']['status']}")
# Check if payment is complete
if status['data']['status'] in ['completed', 'failed', 'expired', 'cancelled']:
return status
# Show progress
progress = status['data'].get('progress', {})
if progress:
print(f"Progress: {progress.get('percentage', 0)}%")
time.sleep(poll_interval)
attempts += 1
except Exception as e:
print(f"Error: {e}")
attempts += 1
raise Exception("Payment monitoring timeout")
# Usage
if __name__ == "__main__":
order_id = "order_1759231185333_ghi789"
final_status = monitor_payment(order_id)
print(f"Final status: {final_status['data']['status']}")WebSocket Real-Time Updates
For real-time updates without polling, use WebSocket connections:
const ws = new WebSocket('wss://api.cyberpay.org/v1/payment/stream');
ws.onopen = function() {
// Subscribe to order updates
ws.send(JSON.stringify({
action: 'subscribe',
orderId: 'order_1759231185333_ghi789',
apiKey: 'YOUR_API_KEY'
}));
};
ws.onmessage = function(event) {
const update = JSON.parse(event.data);
switch (update.type) {
case 'status_update':
console.log('Status updated:', update.data.status);
break;
case 'transaction_confirmed':
console.log('Transaction confirmed:', update.data.txHash);
break;
case 'payment_completed':
console.log('Payment completed!');
ws.close();
break;
}
};
ws.onerror = function(error) {
console.error('WebSocket error:', error);
};Best Practices
Polling Strategy
- Use reasonable poll intervals (5-10 seconds)
- Implement exponential backoff on errors
- Stop polling when payment reaches final state
- Set maximum polling duration to avoid infinite loops
Error Handling
- Handle network timeouts gracefully
- Implement retry logic for temporary failures
- Provide meaningful error messages to users
- Log errors for debugging purposes
User Experience
- Show real-time progress updates
- Display estimated completion times
- Provide transaction links for blockchain explorers
- Handle long-running payments gracefully
Performance
- Cache status responses when appropriate
- Use WebSocket for real-time updates when possible
- Batch multiple status queries when needed
- Implement proper timeout handling
Rate Limits
- Standard: 200 requests per minute
- Premium: 2000 requests per minute
- Enterprise: Custom limits available
Webhook Alternative
Instead of polling, consider using webhooks for real-time updates:
// Webhook endpoint
app.post('/webhooks/cyberpay/status', (req, res) => {
const { orderId, status, progress } = req.body.data;
console.log(`Order ${orderId} status: ${status}`);
// Update your database
updateOrderStatus(orderId, status, progress);
// Notify user via WebSocket, email, etc.
notifyUser(orderId, status);
res.status(200).send('OK');
});Next Steps
- Webhook Setup - Configure real-time notifications
- Merchant Configuration - Manage your merchant settings
Support
- 📧 Email: support@cyberpay.org
- 💬 Telegram: @cyberpay_support
- 📖 Documentation: docs.cyberpay.org
