Query Top-Up Order
Overview
Use this endpoint to query the status of a specific top-up order. This allows you to verify whether funds were successfully added to a budget account, which is essential for reconciliation and error handling in your budget funding workflows.
NOTE: This API is offered on a client-by-client approval basis. Speak to your account manager to check eligibility.
Resource Access
Production (api.ahrvo.network)
GET https://api.ahrvo.network/card/issuance/api/issuing/budget/v2/top-up/order
Staging (gateway.ahrvo.network)
GET https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/top-up/order
Request Headers
| Header | Value | Required | Description |
|---|---|---|---|
Accept | application/json | Yes | Content type for the response |
Authorization | Bearer {access_token} | Yes | Bearer token for authentication |
x-api-key | API Key | Yes | API key for authentication |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
unique_order_id | string | Yes | The unique order ID provided by you when initiating the top-up |
Response
Success Response (200 OK)
{
"code": "SUCCESS",
"data": {
"status": "SUCCESS"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
code | string | Status string indicating the result of the query. "SUCCESS" refers to a successful query |
data | object | Response data object |
data.status | string | The processing status of the top-up order |
Top-Up Status Values
| Status | Description |
|---|---|
SUCCESS | The top-up was completed successfully and funds have been added to the budget |
FAILED | The top-up failed (payment declined, insufficient funds, invalid account, etc.) |
PROCESSING | The top-up is still being processed |
Error Responses
- 400 Bad Request: Invalid or missing
unique_order_id - 401 Unauthorized: Invalid or missing authentication token
- 403 Forbidden: Card issuance feature not enabled for this account
- 404 Not Found: Top-up order does not exist
Code Examples
cURL
curl -X GET \
'https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/top-up/order?unique_order_id=1621924039' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'x-api-key: YOUR_API_KEY'
Python
import requests
url = "https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/top-up/order"
headers = {
"Accept": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"x-api-key": "YOUR_API_KEY"
}
params = {
"unique_order_id": "1621924039"
}
response = requests.get(url, headers=headers, params=params)
result = response.json()
if result['code'] == 'SUCCESS':
top_up_status = result['data']['status']
if top_up_status == 'SUCCESS':
print("✓ Top-up completed successfully")
elif top_up_status == 'FAILED':
print("✗ Top-up failed")
elif top_up_status == 'PROCESSING':
print("⏳ Top-up is still processing")
else:
print(f"Top-up status: {top_up_status}")
else:
print(f"Failed to query top-up order: {result}")
JavaScript (Node.js)
const axios = require('axios');
const url = 'https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/top-up/order';
const headers = {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'x-api-key': 'YOUR_API_KEY'
};
const params = {
unique_order_id: '1621924039'
};
axios.get(url, { headers, params })
.then(response => {
const result = response.data;
if (result.code === 'SUCCESS') {
const topUpStatus = result.data.status;
if (topUpStatus === 'SUCCESS') {
console.log('✓ Top-up completed successfully');
} else if (topUpStatus === 'FAILED') {
console.log('✗ Top-up failed');
} else if (topUpStatus === 'PROCESSING') {
console.log('⏳ Top-up is still processing');
} else {
console.log(`Top-up status: ${topUpStatus}`);
}
}
})
.catch(error => {
console.error('Failed to query top-up order:', error.response.data);
});
Usage Notes
- Unique Order ID: Use the same
unique_order_idyou provided when initiating the top-up - Asynchronous Processing: Top-ups may be processed asynchronously, so query the status to confirm completion
- Status Polling: Implement polling logic to check status periodically until SUCCESS or FAILED
- Idempotent: You can query the same top-up order multiple times safely
- Reconciliation: Use this endpoint for reconciliation and audit purposes
Common Use Cases
Verify Top-Up After Initiation
Check if a top-up completed successfully with retry logic:
def verify_top_up_completion(unique_order_id, max_attempts=10, wait_seconds=3):
"""
Verify a top-up has completed successfully with polling
"""
import time
for attempt in range(max_attempts):
try:
response = query_top_up_order(unique_order_id)
if response['code'] == 'SUCCESS':
status = response['data']['status']
if status == 'SUCCESS':
print(f"✓ Top-up {unique_order_id} completed successfully")
return True
elif status == 'FAILED':
print(f"✗ Top-up {unique_order_id} failed")
return False
elif status == 'PROCESSING':
print(f"⏳ Attempt {attempt + 1}/{max_attempts}: Top-up still processing...")
if attempt < max_attempts - 1:
time.sleep(wait_seconds)
continue
except Exception as e:
print(f"Error checking top-up status: {e}")
if attempt < max_attempts - 1:
time.sleep(wait_seconds)
print(f"⚠ Could not verify top-up status after {max_attempts} attempts")
return None
# Example usage
unique_order_id = "1621924039"
success = verify_top_up_completion(unique_order_id)
if success:
print("Proceeding with card issuance...")
else:
print("Cannot proceed - top-up failed or timed out")
Top-Up with Confirmation Workflow
Initiate a top-up and wait for confirmation:
async function topUpWithConfirmation(budgetId, amount, uniqueOrderId) {
try {
// Step 1: Initiate top-up
console.log('Initiating top-up...');
const topUpResponse = await initiateBudgetTopUp({
budget_id: budgetId,
amount: amount,
unique_order_id: uniqueOrderId
});
console.log(`Top-up initiated: ${uniqueOrderId}`);
// Step 2: Poll for completion
console.log('Waiting for top-up to complete...');
const maxAttempts = 10;
const delayMs = 3000; // 3 seconds
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
await new Promise(resolve => setTimeout(resolve, delayMs));
const statusResponse = await queryTopUpOrder(uniqueOrderId);
if (statusResponse.code === 'SUCCESS') {
const status = statusResponse.data.status;
if (status === 'SUCCESS') {
console.log('✓ Top-up completed successfully');
return {
success: true,
unique_order_id: uniqueOrderId,
budget_id: budgetId,
amount: amount
};
} else if (status === 'FAILED') {
console.log('✗ Top-up failed');
return {
success: false,
unique_order_id: uniqueOrderId,
error: 'Top-up failed'
};
} else if (status === 'PROCESSING') {
console.log(`⏳ Attempt ${attempt}/${maxAttempts}: Still processing...`);
continue;
}
}
}
console.log('⚠ Top-up status could not be confirmed');
return {
success: null,
unique_order_id: uniqueOrderId,
error: 'Status verification timeout'
};
} catch (error) {
console.error('Top-up with confirmation failed:', error);
throw error;
}
}
// Example usage
const result = await topUpWithConfirmation(
'ci202507232016182661',
10000.00,
`topup_${Date.now()}`
);
Batch Top-Up Verification
Verify multiple top-ups at once:
def verify_batch_top_ups(unique_order_ids):
"""
Verify the status of multiple top-up orders
"""
results = {
'successful': [],
'failed': [],
'processing': [],
'unknown': []
}
for order_id in unique_order_ids:
try:
response = query_top_up_order(order_id)
if response['code'] == 'SUCCESS':
status = response['data']['status']
if status == 'SUCCESS':
results['successful'].append(order_id)
elif status == 'FAILED':
results['failed'].append(order_id)
elif status == 'PROCESSING':
results['processing'].append(order_id)
else:
results['unknown'].append(order_id)
except Exception as e:
print(f"Error checking top-up {order_id}: {e}")
results['unknown'].append(order_id)
# Print summary
print("\n=== Top-Up Verification Summary ===")
print(f"Total Orders: {len(unique_order_ids)}")
print(f"✓ Successful: {len(results['successful'])}")
print(f"✗ Failed: {len(results['failed'])}")
print(f"⏳ Processing: {len(results['processing'])}")
print(f"? Unknown: {len(results['unknown'])}")
return results
# Example usage
order_ids = [
"1621924039",
"1621924040",
"1621924041"
]
verification_results = verify_batch_top_ups(order_ids)
# Retry processing orders
if verification_results['processing']:
print("\nRetrying processing orders in 5 seconds...")
time.sleep(5)
retry_results = verify_batch_top_ups(verification_results['processing'])
Top-Up Reconciliation Report
Generate a reconciliation report for top-ups:
async function generateTopUpReconciliationReport(topUpOrders) {
const report = {
generated_at: new Date().toISOString(),
total_top_ups: topUpOrders.length,
successful_count: 0,
failed_count: 0,
processing_count: 0,
total_amount_successful: 0,
total_amount_failed: 0,
total_amount_processing: 0,
details: []
};
for (const order of topUpOrders) {
try {
const response = await queryTopUpOrder(order.unique_order_id);
if (response.code === 'SUCCESS') {
const status = response.data.status;
const detail = {
unique_order_id: order.unique_order_id,
budget_name: order.budget_name,
budget_id: order.budget_id,
amount: order.amount,
currency: order.currency,
status: status,
initiated_at: order.initiated_at
};
if (status === 'SUCCESS') {
report.successful_count++;
report.total_amount_successful += order.amount;
} else if (status === 'FAILED') {
report.failed_count++;
report.total_amount_failed += order.amount;
} else if (status === 'PROCESSING') {
report.processing_count++;
report.total_amount_processing += order.amount;
}
report.details.push(detail);
}
} catch (error) {
console.error(`Error checking top-up ${order.unique_order_id}:`, error);
}
}
// Print report
console.log('\n=== Top-Up Reconciliation Report ===');
console.log(`Generated: ${report.generated_at}`);
console.log(`Total Top-Ups: ${report.total_top_ups}`);
console.log(`✓ Successful: ${report.successful_count} (${report.total_amount_successful.toFixed(2)} USD)`);
console.log(`✗ Failed: ${report.failed_count} (${report.total_amount_failed.toFixed(2)} USD)`);
console.log(`⏳ Processing: ${report.processing_count} (${report.total_amount_processing.toFixed(2)} USD)`);
console.log('\nDetails:');
report.details.forEach(detail => {
const statusIcon = detail.status === 'SUCCESS' ? '✓' :
detail.status === 'FAILED' ? '✗' : '⏳';
console.log(`${statusIcon} ${detail.unique_order_id}: ${detail.budget_name} (${detail.currency} ${detail.amount})`);
});
return report;
}
// Example usage
const topUps = [
{
unique_order_id: '1621924039',
budget_name: 'Marketing Budget',
budget_id: 'ci202507232016182661',
amount: 10000,
currency: 'USD',
initiated_at: '2026-02-07T10:30:00Z'
},
// ... more top-ups
];
const report = await generateTopUpReconciliationReport(topUps);
Automated Top-Up with Retry
Handle failed top-ups with automated retry:
def top_up_with_retry(budget_id, amount, max_retries=3):
"""
Initiate top-up with automatic retry on failure
"""
import time
import uuid
for attempt in range(max_retries):
# Generate unique order ID for this attempt
unique_order_id = f"topup_{int(time.time())}_{uuid.uuid4().hex[:8]}"
try:
# Initiate top-up
top_up_response = initiate_budget_top_up(
budget_id=budget_id,
amount=amount,
unique_order_id=unique_order_id
)
print(f"Top-up initiated (Attempt {attempt + 1}): {unique_order_id}")
# Poll for completion
for check_attempt in range(10):
time.sleep(3)
status_response = query_top_up_order(unique_order_id)
if status_response['code'] == 'SUCCESS':
status = status_response['data']['status']
if status == 'SUCCESS':
print(f"✓ Top-up successful on attempt {attempt + 1}")
return {
'success': True,
'unique_order_id': unique_order_id,
'attempts': attempt + 1
}
elif status == 'FAILED':
print(f"✗ Top-up failed on attempt {attempt + 1}")
if attempt < max_retries - 1:
print(f"Retrying... ({max_retries - attempt - 1} attempts remaining)")
time.sleep(5)
break # Exit polling loop to retry
elif status == 'PROCESSING':
print(f"⏳ Check {check_attempt + 1}/10: Still processing...")
continue
except Exception as e:
print(f"Error on attempt {attempt + 1}: {e}")
if attempt < max_retries - 1:
time.sleep(5)
return {
'success': False,
'attempts': max_retries,
'error': 'Max retries exceeded'
}
# Example usage
result = top_up_with_retry('ci202507232016182661', 10000.00)
Top-Up Monitoring Dashboard
Monitor ongoing top-ups in real-time:
class TopUpMonitor {
constructor() {
this.pendingTopUps = new Map();
}
async addTopUp(uniqueOrderId, metadata = {}) {
this.pendingTopUps.set(uniqueOrderId, {
...metadata,
added_at: new Date(),
last_checked: null,
status: 'PENDING'
});
console.log(`Added top-up to monitor: ${uniqueOrderId}`);
}
async checkAllTopUps() {
console.log(`\nChecking ${this.pendingTopUps.size} pending top-ups...`);
const completedTopUps = [];
for (const [orderId, info] of this.pendingTopUps.entries()) {
try {
const response = await queryTopUpOrder(orderId);
if (response.code === 'SUCCESS') {
const status = response.data.status;
info.last_checked = new Date();
info.status = status;
if (status === 'SUCCESS') {
console.log(` ✓ ${orderId}: Completed successfully`);
completedTopUps.push(orderId);
} else if (status === 'FAILED') {
console.log(` ✗ ${orderId}: Failed`);
completedTopUps.push(orderId);
} else if (status === 'PROCESSING') {
console.log(` ⏳ ${orderId}: Still processing`);
}
}
} catch (error) {
console.error(` Error checking ${orderId}:`, error.message);
}
}
// Remove completed top-ups
completedTopUps.forEach(id => {
console.log(`Removing completed top-up: ${id}`);
this.pendingTopUps.delete(id);
});
return {
checked: this.pendingTopUps.size + completedTopUps.length,
completed: completedTopUps.length,
pending: this.pendingTopUps.size
};
}
getPendingCount() {
return this.pendingTopUps.size;
}
getPendingTopUps() {
return Array.from(this.pendingTopUps.entries()).map(([id, info]) => ({
unique_order_id: id,
...info
}));
}
}
// Example usage
const monitor = new TopUpMonitor();
// Add top-ups to monitor
await monitor.addTopUp('1621924039', {
budget_name: 'Marketing Budget',
amount: 10000,
currency: 'USD'
});
// Check periodically
setInterval(async () => {
if (monitor.getPendingCount() > 0) {
const results = await monitor.checkAllTopUps();
console.log(`\nMonitoring Summary: ${results.pending} pending, ${results.completed} completed`);
}
}, 5000); // Check every 5 seconds
Budget Funding with Balance Verification
Top up and verify the new balance:
def fund_budget_with_verification(budget_id, amount):
"""
Top up a budget and verify the balance increased correctly
"""
import time
# Step 1: Get current balance
print("Getting current balance...")
balance_response = query_budget_balance(budget_id)
original_balance = balance_response['data']['balance']
print(f"Current balance: {original_balance}")
# Step 2: Initiate top-up
unique_order_id = f"topup_{int(time.time())}"
print(f"\nInitiating top-up of {amount}...")
top_up_response = initiate_budget_top_up(
budget_id=budget_id,
amount=amount,
unique_order_id=unique_order_id
)
# Step 3: Wait for top-up to complete
print("Waiting for top-up to complete...")
max_attempts = 10
for attempt in range(max_attempts):
time.sleep(3)
status_response = query_top_up_order(unique_order_id)
if status_response['code'] == 'SUCCESS':
status = status_response['data']['status']
if status == 'SUCCESS':
print("✓ Top-up completed successfully")
break
elif status == 'FAILED':
print("✗ Top-up failed")
return {
'success': False,
'error': 'Top-up failed'
}
elif status == 'PROCESSING':
print(f"⏳ Attempt {attempt + 1}/{max_attempts}: Still processing...")
# Step 4: Verify new balance
print("\nVerifying new balance...")
time.sleep(2) # Wait for balance to update
new_balance_response = query_budget_balance(budget_id)
new_balance = new_balance_response['data']['balance']
expected_balance = original_balance + amount
print(f"Original balance: {original_balance}")
print(f"Top-up amount: {amount}")
print(f"Expected balance: {expected_balance}")
print(f"Actual balance: {new_balance}")
if new_balance == expected_balance:
print("✓ Balance verification successful")
return {
'success': True,
'original_balance': original_balance,
'new_balance': new_balance,
'amount_added': amount
}
else:
print(f"⚠ Balance mismatch: expected {expected_balance}, got {new_balance}")
return {
'success': False,
'error': 'Balance verification failed',
'original_balance': original_balance,
'new_balance': new_balance,
'amount_added': amount
}
# Example usage
result = fund_budget_with_verification('ci202507232016182661', 10000.00)
Best Practices
- Always Verify: Check top-up status after initiating to ensure funds were added
- Use Unique IDs: Generate unique order IDs to avoid duplicates (e.g., timestamp + UUID)
- Implement Polling: Poll status periodically until SUCCESS or FAILED (not PROCESSING)
- Set Timeouts: Define maximum retry attempts to avoid infinite loops
- Balance Verification: Verify budget balance after successful top-up
- Error Handling: Handle all status values (SUCCESS, FAILED, PROCESSING)
- Audit Trail: Log all top-up attempts and results for compliance
Top-Up Workflow
Standard Top-Up Process
- Check Current Balance: Query existing budget balance
- Initiate Top-Up: Call top-up endpoint with unique_order_id
- Store Order ID: Save the unique_order_id for status tracking
- Poll Status: Use this endpoint to check status periodically
- Verify Completion: Wait for SUCCESS or FAILED status
- Verify Balance: Confirm budget balance increased by expected amount
- Update Records: Update your internal systems with the result
Related Endpoints
- Top-Up Budget Account - Initiate a top-up to add funds to a budget
- Query Budget Balance - Check balance before and after top-ups
- Create Budget Account - Create budget accounts to receive top-ups
- Query Budget Details - Get detailed information about budget accounts
Troubleshooting
Top-Up Order Not Found (404)
- Cause: Invalid
unique_order_idor top-up doesn't exist - Solution:
- Verify the
unique_order_idis correct and matches what you provided at initiation - Ensure the top-up was actually initiated
- Verify the
Top-Up Status Remains PROCESSING
- Cause: Top-up is taking longer than expected or stuck
- Solution:
- Continue polling - some top-ups may take several minutes
- Check with support if status doesn't update after 5-10 minutes
- Verify your payment source is valid
Top-Up Failed Status
- Cause: Payment declined, insufficient funds, invalid account, etc.
- Solution:
- Check your funding source has sufficient balance
- Verify payment method is valid and not expired
- Review budget account is active and not frozen
- Contact support for specific failure reason
Balance Not Updated After SUCCESS
- Cause: Delay in balance propagation
- Solution:
- Wait a few seconds and query balance again
- Verify you're checking the correct budget_id
- Contact support if balance still doesn't reflect top-up
Security Considerations
- Order ID Security: Treat unique order IDs as sensitive information
- Idempotency: Use the same unique_order_id to safely retry queries
- Rate Limiting: Implement reasonable polling intervals (3-5 seconds recommended)
- Audit Logging: Log all top-up status queries for audit purposes
- Data Retention: Maintain top-up records for compliance requirements