Top Up Dedicated Funds Card
Overview
Use this endpoint to add funds to a Dedicated Funds Card from your budget account. This endpoint transfers a specified amount from your budget balance to the card's independent balance, making the funds immediately available for spending on that card.
NOTE: This API is offered on a client-by-client approval basis. Speak to your account manager to check eligibility.
IMPORTANT: This endpoint only works for Dedicated Funds Cards. Shared Funds Cards do not require top-ups as they draw from budget accounts directly.
Resource Access
Production (api.ahrvo.network)
POST https://api.ahrvo.network/card/issuance/api/issuing/card/v2/funding/top-up
Staging (gateway.ahrvo.network)
POST https://gateway.ahrvo.network/card/issuance/api/issuing/card/v2/funding/top-up
Request Headers
| Header | Value | Required | Description |
|---|---|---|---|
Accept | application/json | Yes | Content type for the response |
Content-Type | application/json | Yes | Content type of the request body |
Authorization | Bearer {access_token} | Yes | Bearer token for authentication |
x-api-key | API Key | Yes | API key for authentication |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
unique_order_id | string | Yes | Top-up order ID provided by you for idempotency. Character limit: 36 |
card_id | string | Yes | A unique ID of the card to top up |
amount | string | Yes | Monetary amount expressed in USD (e.g., "10.45") |
Request Example
{
"card_id": "card2020092710410645531",
"amount": "10.45",
"unique_order_id": "1cc24f5b-5dda-4c2f-8811-df2047469f9f"
}
Response
Success Response (200 OK)
{
"code": "SUCCESS",
"data": {
"record_id": "coi202511211358115253"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
code | string | Status string indicating the result. "SUCCESS" refers to a successful top-up initiation |
data | object | Response data object |
data.record_id | string | A unique ID of the top-up record generated by PingPong |
Error Responses
- 400 Bad Request: Invalid parameters, insufficient budget balance, or duplicate
unique_order_id - 401 Unauthorized: Invalid or missing authentication token
- 403 Forbidden: Card issuance feature not enabled for this account
- 404 Not Found: Card does not exist
Code Examples
cURL
curl -X POST \
'https://gateway.ahrvo.network/card/issuance/api/issuing/card/v2/funding/top-up' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{
"card_id": "card2020092710410645531",
"amount": "100.00",
"unique_order_id": "1cc24f5b-5dda-4c2f-8811-df2047469f9f"
}'
Python
import requests
import uuid
url = "https://gateway.ahrvo.network/card/issuance/api/issuing/card/v2/funding/top-up"
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"x-api-key": "YOUR_API_KEY"
}
payload = {
"card_id": "card2020092710410645531",
"amount": "100.00",
"unique_order_id": str(uuid.uuid4())
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result['code'] == 'SUCCESS':
data = result['data']
print("Card Top-Up Successful!")
print(f" Record ID: {data['record_id']}")
print(f" Amount: ${payload['amount']}")
print(f" Card ID: {payload['card_id']}")
else:
print(f"Failed to top up card: {result}")
JavaScript (Node.js)
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');
const url = 'https://gateway.ahrvo.network/card/issuance/api/issuing/card/v2/funding/top-up';
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'x-api-key': 'YOUR_API_KEY'
};
const payload = {
card_id: 'card2020092710410645531',
amount: '100.00',
unique_order_id: uuidv4()
};
axios.post(url, payload, { headers })
.then(response => {
const result = response.data;
if (result.code === 'SUCCESS') {
const data = result.data;
console.log('Card Top-Up Successful!');
console.log(` Record ID: ${data.record_id}`);
console.log(` Amount: $${payload.amount}`);
console.log(` Card ID: ${payload.card_id}`);
}
})
.catch(error => {
console.error('Failed to top up card:', error.response.data);
});
Usage Notes
- Idempotency: Use unique
unique_order_idvalues to prevent duplicate top-ups. The sameunique_order_idcannot be used twice - Immediate Availability: Funds are typically available on the card within seconds
- Budget Balance: Ensure your budget account has sufficient balance before initiating a top-up
- USD Only: All amounts must be in USD with exactly 2 decimal places
- Record Tracking: Save the returned
record_idto track the top-up in funding orders - Dedicated Funds Only: This endpoint only works for Dedicated Funds Cards
Common Use Cases
Manual Card Top-Up
Top up a specific card with a fixed amount:
def top_up_card(card_id, amount):
"""
Top up a Dedicated Funds Card
Args:
card_id: Card ID to top up
amount: Amount in USD (e.g., 100.00)
"""
import uuid
print(f"\nTopping up card {card_id} with ${amount:.2f}...\n")
# Generate unique order ID for idempotency
unique_order_id = str(uuid.uuid4())
payload = {
"card_id": card_id,
"amount": f"{amount:.2f}",
"unique_order_id": unique_order_id
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result['code'] == 'SUCCESS':
data = result['data']
print("✓ Top-Up Successful!")
print(f" Record ID: {data['record_id']}")
print(f" Amount: ${amount:.2f}")
print(f" Order ID: {unique_order_id}")
# Query updated balance
balance_response = query_card_balance(card_id)
if balance_response['code'] == 'SUCCESS':
new_balance = balance_response['data']['available_balance']
print(f" New Balance: ${new_balance}")
return {
'success': True,
'record_id': data['record_id'],
'amount': amount,
'order_id': unique_order_id
}
else:
print(f"✗ Top-Up Failed: {result}")
return {
'success': False,
'error': result
}
# Example usage
result = top_up_card('card2020092710410645531', 500.00)
if result['success']:
print(f"\nCard topped up successfully. Record ID: {result['record_id']}")
else:
print(f"\nFailed to top up card")
Automated Low Balance Top-Up
Automatically top up cards when balance falls below threshold:
async function autoTopUpOnLowBalance(cardId, thresholdAmount, topUpAmount) {
console.log(`\n=== Automated Top-Up Check ===`);
console.log(`Card: ${cardId}`);
console.log(`Threshold: $${thresholdAmount.toFixed(2)}`);
console.log(`Top-Up Amount: $${topUpAmount.toFixed(2)}\n`);
try {
// Check current balance
const balanceResponse = await queryCardBalance(cardId);
if (balanceResponse.code === 'SUCCESS') {
const currentBalance = parseFloat(balanceResponse.data.available_balance);
const cardNumber = balanceResponse.data.card_number;
console.log(`Current Balance: $${currentBalance.toFixed(2)}`);
if (currentBalance < thresholdAmount) {
console.log(`⚠️ Balance below threshold ($${thresholdAmount.toFixed(2)})`);
console.log(`Initiating automatic top-up...\n`);
// Generate unique order ID
const { v4: uuidv4 } = require('uuid');
const uniqueOrderId = uuidv4();
// Execute top-up
const topUpPayload = {
card_id: cardId,
amount: topUpAmount.toFixed(2),
unique_order_id: uniqueOrderId
};
const topUpResponse = await topUpCard(topUpPayload);
if (topUpResponse.code === 'SUCCESS') {
const newBalance = currentBalance + topUpAmount;
console.log('✓ Automatic Top-Up Successful!');
console.log(` Card: ${cardNumber}`);
console.log(` Previous Balance: $${currentBalance.toFixed(2)}`);
console.log(` Top-Up Amount: $${topUpAmount.toFixed(2)}`);
console.log(` New Balance: $${newBalance.toFixed(2)}`);
console.log(` Record ID: ${topUpResponse.data.record_id}`);
// Send notification
await sendTopUpNotification(cardNumber, topUpAmount, newBalance);
return {
topped_up: true,
record_id: topUpResponse.data.record_id,
previous_balance: currentBalance,
new_balance: newBalance
};
} else {
console.log('✗ Top-Up Failed:', topUpResponse);
return {
topped_up: false,
error: topUpResponse
};
}
} else {
console.log('✓ Balance above threshold - no top-up needed');
return {
topped_up: false,
reason: 'balance_sufficient',
current_balance: currentBalance
};
}
} else {
console.log('✗ Failed to check balance:', balanceResponse);
return {
topped_up: false,
error: balanceResponse
};
}
} catch (error) {
console.error('Error in auto top-up:', error.message);
return {
topped_up: false,
error: error.message
};
}
}
async function sendTopUpNotification(cardNumber, amount, newBalance) {
console.log(` 📧 Notification sent: Card ${cardNumber} topped up with $${amount.toFixed(2)}`);
// Implement your notification logic (email, SMS, Slack, etc.)
}
// Example usage
const result = await autoTopUpOnLowBalance(
'card2020092710410645531',
100.00, // Threshold: $100
500.00 // Top-up amount: $500
);
Batch Top-Up Multiple Cards
Top up multiple cards in a single operation:
def batch_top_up_cards(top_up_list):
"""
Top up multiple cards
Args:
top_up_list: List of dicts with 'card_id' and 'amount'
"""
import uuid
from datetime import datetime
print("\n" + "=" * 70)
print("BATCH CARD TOP-UP".center(70))
print("=" * 70)
print(f"Started: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Total Cards: {len(top_up_list)}\n")
results = {
'successful': [],
'failed': [],
'total_amount': 0
}
for idx, item in enumerate(top_up_list, 1):
card_id = item['card_id']
amount = float(item['amount'])
print(f"[{idx}/{len(top_up_list)}] Processing {card_id}...")
print(f" Amount: ${amount:.2f}")
try:
payload = {
"card_id": card_id,
"amount": f"{amount:.2f}",
"unique_order_id": str(uuid.uuid4())
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result['code'] == 'SUCCESS':
data = result['data']
print(f" ✓ Success - Record ID: {data['record_id']}")
results['successful'].append({
'card_id': card_id,
'amount': amount,
'record_id': data['record_id']
})
results['total_amount'] += amount
else:
print(f" ✗ Failed: {result.get('message', 'Unknown error')}")
results['failed'].append({
'card_id': card_id,
'amount': amount,
'error': result
})
except Exception as e:
print(f" ✗ Exception: {e}")
results['failed'].append({
'card_id': card_id,
'amount': amount,
'error': str(e)
})
print()
# Summary
print("=" * 70)
print("BATCH TOP-UP SUMMARY".center(70))
print("=" * 70)
print(f"Total Cards: {len(top_up_list)}")
print(f"Successful: {len(results['successful'])} ✓")
print(f"Failed: {len(results['failed'])} ✗")
print(f"Total Amount Topped Up: ${results['total_amount']:,.2f}")
if results['failed']:
print(f"\n⚠️ Failed Top-Ups:")
for item in results['failed']:
print(f" • {item['card_id']}: ${item['amount']:.2f}")
print(f" Error: {item['error']}")
print("\n" + "=" * 70 + "\n")
return results
# Example usage
top_up_list = [
{'card_id': 'card2020092710410645531', 'amount': '500.00'},
{'card_id': 'card2020092710410645532', 'amount': '250.00'},
{'card_id': 'card2020092710410645533', 'amount': '1000.00'},
{'card_id': 'card2020092710410645534', 'amount': '750.00'}
]
results = batch_top_up_cards(top_up_list)
print(f"Batch complete: {len(results['successful'])}/{len(top_up_list)} successful")
Scheduled Recurring Top-Up
Set up recurring top-ups on a schedule:
const cron = require('node-cron');
const { v4: uuidv4 } = require('uuid');
class ScheduledTopUpManager {
constructor() {
this.schedules = new Map();
}
/**
* Schedule recurring top-ups for a card
*
* @param {string} cardId - Card ID to top up
* @param {number} amount - Amount to top up each time
* @param {string} cronExpression - Cron expression (e.g., '0 9 * * 1' for every Monday at 9 AM)
* @param {string} description - Description of the schedule
*/
scheduleRecurringTopUp(cardId, amount, cronExpression, description) {
console.log(`\n📅 Scheduling Recurring Top-Up`);
console.log(` Card: ${cardId}`);
console.log(` Amount: $${amount.toFixed(2)}`);
console.log(` Schedule: ${description}`);
console.log(` Cron: ${cronExpression}\n`);
const task = cron.schedule(cronExpression, async () => {
console.log(`\n⏰ Scheduled Top-Up Triggered: ${description}`);
console.log(` Time: ${new Date().toISOString()}`);
try {
const payload = {
card_id: cardId,
amount: amount.toFixed(2),
unique_order_id: uuidv4()
};
const response = await topUpCard(payload);
if (response.code === 'SUCCESS') {
console.log(` ✓ Top-Up Successful`);
console.log(` Record ID: ${response.data.record_id}`);
console.log(` Amount: $${amount.toFixed(2)}`);
// Log to database/file
await logTopUpEvent({
card_id: cardId,
amount: amount,
record_id: response.data.record_id,
scheduled: true,
timestamp: new Date()
});
// Send success notification
await sendNotification(
`Scheduled top-up completed for card ${cardId}: $${amount.toFixed(2)}`
);
} else {
console.log(` ✗ Top-Up Failed:`, response);
// Send failure alert
await sendAlert(
`Scheduled top-up failed for card ${cardId}`,
response
);
}
} catch (error) {
console.error(` ✗ Error:`, error.message);
await sendAlert(
`Scheduled top-up error for card ${cardId}`,
error
);
}
});
// Store the schedule
const scheduleId = uuidv4();
this.schedules.set(scheduleId, {
task: task,
cardId: cardId,
amount: amount,
cronExpression: cronExpression,
description: description,
createdAt: new Date()
});
console.log(`✓ Schedule created with ID: ${scheduleId}`);
return scheduleId;
}
/**
* Cancel a scheduled top-up
*/
cancelSchedule(scheduleId) {
const schedule = this.schedules.get(scheduleId);
if (schedule) {
schedule.task.stop();
this.schedules.delete(scheduleId);
console.log(`\n🗑️ Schedule Cancelled: ${schedule.description}`);
console.log(` Card: ${schedule.cardId}`);
return true;
} else {
console.log(`\n⚠️ Schedule not found: ${scheduleId}`);
return false;
}
}
/**
* List all active schedules
*/
listSchedules() {
console.log(`\n📋 Active Scheduled Top-Ups: ${this.schedules.size}\n`);
this.schedules.forEach((schedule, scheduleId) => {
console.log(`Schedule ID: ${scheduleId}`);
console.log(` Card: ${schedule.cardId}`);
console.log(` Amount: $${schedule.amount.toFixed(2)}`);
console.log(` Description: ${schedule.description}`);
console.log(` Cron: ${schedule.cronExpression}`);
console.log(` Created: ${schedule.createdAt.toISOString()}\n`);
});
}
}
// Example usage
const topUpManager = new ScheduledTopUpManager();
// Schedule weekly top-up every Monday at 9 AM
const weeklyScheduleId = topUpManager.scheduleRecurringTopUp(
'card2020092710410645531',
500.00,
'0 9 * * 1',
'Weekly Monday top-up'
);
// Schedule bi-weekly top-up (1st and 15th of month at 8 AM)
const biweeklyScheduleId = topUpManager.scheduleRecurringTopUp(
'card2020092710410645532',
1000.00,
'0 8 1,15 * *',
'Bi-weekly top-up (1st and 15th)'
);
// Schedule monthly top-up (first day of month at 7 AM)
const monthlyScheduleId = topUpManager.scheduleRecurringTopUp(
'card2020092710410645533',
2000.00,
'0 7 1 * *',
'Monthly top-up (1st of month)'
);
// List all schedules
topUpManager.listSchedules();
// Cancel a schedule later
// topUpManager.cancelSchedule(weeklyScheduleId);
Top-Up with Balance Verification
Top up and verify the new balance:
def top_up_and_verify(card_id, amount, max_retries=3):
"""
Top up card and verify the balance was updated correctly
Args:
card_id: Card ID to top up
amount: Amount to top up
max_retries: Number of verification retries
"""
import time
import uuid
print(f"\n=== Top-Up with Verification ===")
print(f"Card: {card_id}")
print(f"Amount: ${amount:.2f}\n")
# Get initial balance
print("Step 1: Checking initial balance...")
initial_response = query_card_balance(card_id)
if initial_response['code'] != 'SUCCESS':
print(f"✗ Failed to get initial balance: {initial_response}")
return {'success': False, 'error': 'Failed to get initial balance'}
initial_balance = float(initial_response['data']['available_balance'])
expected_balance = initial_balance + amount
print(f" Initial Balance: ${initial_balance:.2f}")
print(f" Expected Balance after top-up: ${expected_balance:.2f}\n")
# Execute top-up
print("Step 2: Executing top-up...")
payload = {
"card_id": card_id,
"amount": f"{amount:.2f}",
"unique_order_id": str(uuid.uuid4())
}
top_up_response = requests.post(url, headers=headers, json=payload)
result = top_up_response.json()
if result['code'] != 'SUCCESS':
print(f"✗ Top-up failed: {result}")
return {'success': False, 'error': result}
record_id = result['data']['record_id']
print(f" ✓ Top-up initiated - Record ID: {record_id}\n")
# Verify balance update
print("Step 3: Verifying balance update...")
for attempt in range(1, max_retries + 1):
print(f" Verification attempt {attempt}/{max_retries}...")
# Wait a moment for balance to update
time.sleep(2)
verify_response = query_card_balance(card_id)
if verify_response['code'] == 'SUCCESS':
current_balance = float(verify_response['data']['available_balance'])
print(f" Current Balance: ${current_balance:.2f}")
if abs(current_balance - expected_balance) < 0.01: # Allow 1 cent tolerance
print(f"\n✓ Verification Successful!")
print(f" Initial Balance: ${initial_balance:.2f}")
print(f" Top-Up Amount: ${amount:.2f}")
print(f" Final Balance: ${current_balance:.2f}")
print(f" Record ID: {record_id}")
return {
'success': True,
'record_id': record_id,
'initial_balance': initial_balance,
'top_up_amount': amount,
'final_balance': current_balance,
'verified': True
}
else:
difference = current_balance - expected_balance
print(f" ⚠️ Balance mismatch: ${difference:.2f} difference")
if attempt < max_retries:
print(f" Retrying...")
else:
print(f"\n⚠️ Balance verification failed after {max_retries} attempts")
print(f" Expected: ${expected_balance:.2f}")
print(f" Actual: ${current_balance:.2f}")
print(f" Difference: ${difference:.2f}")
return {
'success': True,
'record_id': record_id,
'initial_balance': initial_balance,
'top_up_amount': amount,
'final_balance': current_balance,
'verified': False,
'warning': 'Balance mismatch'
}
else:
print(f" ✗ Failed to verify balance")
if attempt == max_retries:
return {
'success': True,
'record_id': record_id,
'verified': False,
'error': 'Could not verify balance'
}
return {'success': False, 'error': 'Verification failed'}
# Example usage
result = top_up_and_verify('card2020092710410645531', 250.00)
if result['success'] and result.get('verified'):
print("\n✅ Top-up completed and verified successfully!")
elif result['success']:
print("\n⚠️ Top-up completed but verification inconclusive")
else:
print("\n❌ Top-up failed")
Dynamic Top-Up Based on Spending Pattern
Analyze spending and top up proactively:
async function intelligentTopUp(cardId) {
console.log('\n=== Intelligent Top-Up System ===\n');
try {
// Step 1: Get current balance
const balanceResponse = await queryCardBalance(cardId);
const currentBalance = parseFloat(balanceResponse.data.available_balance);
console.log(`Current Balance: $${currentBalance.toFixed(2)}`);
// Step 2: Analyze recent spending
const fundingOrders = await queryCardFundingOrders(cardId);
const spendingAnalysis = analyzeSpendingPattern(fundingOrders);
console.log('\nSpending Analysis:');
console.log(` Average Daily Spend: $${spendingAnalysis.avgDailySpend.toFixed(2)}`);
console.log(` Days Remaining at Current Rate: ${spendingAnalysis.daysRemaining.toFixed(1)}`);
console.log(` Recommended Top-Up: $${spendingAnalysis.recommendedTopUp.toFixed(2)}`);
// Step 3: Decide if top-up is needed
const daysThreshold = 3; // Top up if less than 3 days remaining
if (spendingAnalysis.daysRemaining < daysThreshold) {
console.log(`\n⚠️ Low balance warning: Only ${spendingAnalysis.daysRemaining.toFixed(1)} days remaining`);
console.log('Initiating intelligent top-up...\n');
const { v4: uuidv4 } = require('uuid');
const topUpAmount = spendingAnalysis.recommendedTopUp;
const payload = {
card_id: cardId,
amount: topUpAmount.toFixed(2),
unique_order_id: uuidv4()
};
const topUpResponse = await topUpCard(payload);
if (topUpResponse.code === 'SUCCESS') {
const newBalance = currentBalance + topUpAmount;
const newDaysRemaining = newBalance / spendingAnalysis.avgDailySpend;
console.log('✓ Intelligent Top-Up Successful!');
console.log(` Amount: $${topUpAmount.toFixed(2)}`);
console.log(` New Balance: $${newBalance.toFixed(2)}`);
console.log(` New Days Remaining: ${newDaysRemaining.toFixed(1)} days`);
console.log(` Record ID: ${topUpResponse.data.record_id}`);
return {
topped_up: true,
amount: topUpAmount,
new_balance: newBalance,
record_id: topUpResponse.data.record_id
};
}
} else {
console.log(`\n✓ Balance sufficient (${spendingAnalysis.daysRemaining.toFixed(1)} days remaining)`);
console.log('No top-up needed at this time.');
return {
topped_up: false,
reason: 'balance_sufficient'
};
}
} catch (error) {
console.error('Error in intelligent top-up:', error.message);
return {
topped_up: false,
error: error.message
};
}
}
function analyzeSpendingPattern(fundingOrders) {
// Calculate average daily spending from recent funding history
const withdrawals = fundingOrders.filter(o => o.operate_type === 'card_out');
if (withdrawals.length === 0) {
return {
avgDailySpend: 50.00, // Default if no history
daysRemaining: 999,
recommendedTopUp: 500.00
};
}
const totalSpent = withdrawals.reduce((sum, o) => sum + parseFloat(o.amount), 0);
const avgDailySpend = totalSpent / 30; // Assuming 30-day history
const currentBalance = parseFloat(balanceResponse.data.available_balance);
const daysRemaining = currentBalance / avgDailySpend;
// Recommend enough to last 14 days
const recommendedTopUp = Math.max(
(avgDailySpend * 14) - currentBalance,
100.00 // Minimum top-up
);
return {
avgDailySpend,
daysRemaining,
recommendedTopUp
};
}
// Example usage
const result = await intelligentTopUp('card2020092710410645531');
Best Practices
- Idempotency: Always use unique
unique_order_idvalues (UUID recommended) - Balance Verification: Query balance after top-up to confirm successful update
- Budget Check: Verify budget account has sufficient balance before initiating top-up
- Amount Precision: Always use exactly 2 decimal places for USD amounts
- Record Tracking: Store
record_idvalues for reconciliation and audit purposes - Error Handling: Implement retry logic with exponential backoff for network errors
- Monitoring: Set up alerts for failed top-ups
- Automation: Consider automated top-ups for frequently used cards
Understanding Card Funding
Top-Up Flow
- Initiate: Call this endpoint with card ID and amount
- Debit Budget: Amount is deducted from your budget account
- Credit Card: Amount is added to the card's balance
- Immediate: Funds are typically available within seconds
- Track: Use the returned
record_idto track the funding order
Funding Operations
| Operation | Description | Amount Direction |
|---|---|---|
| Top-Up (card_in) | Add funds to card | Budget → Card |
| Withdrawal (card_out) | Remove funds from card | Card → Budget |
Related Endpoints
- Withdraw Funds - Remove funds from a Dedicated Funds Card
- Query Dedicated Funds Card Balance - Check current card balance
- Query Card Funding Orders - View top-up and withdrawal history
- Query Budget Balance - Check budget account balance before top-up
- Top-Up Budget Account - Add funds to budget account
Troubleshooting
Insufficient Budget Balance (400)
- Cause: Budget account doesn't have enough funds
- Solution:
- Query budget balance first
- Top up budget account if needed
- Retry the card top-up
Duplicate Order ID (400)
- Cause: The
unique_order_idwas used in a previous request - Solution:
- Generate a new UUID for each top-up attempt
- Don't retry with the same
unique_order_id
Card Not Found (404)
- Cause: Invalid
card_idor card doesn't exist - Solution:
- Verify the card ID is correct
- Use Query All Cards to list available cards
- Check if card was deleted or cancelled
Wrong Card Type (400)
- Cause: Attempting to top up a Shared Funds Card
- Solution:
- This endpoint only works for Dedicated Funds Cards
- Shared Funds Cards draw from budget accounts directly
Top-Up Not Reflected
- Cause: Balance query timing or processing delay
- Solution:
- Wait 2-5 seconds and query balance again
- Use the
record_idto verify the funding order status - Check Query Card Funding Orders for the transaction
Security Considerations
- Access Control: Restrict top-up operations to authorized users only
- Amount Validation: Implement maximum top-up limits in your application
- Budget Monitoring: Monitor budget account balance to prevent overdrafts
- Audit Logging: Log all top-up operations for security auditing
- Idempotency Protection: Store used
unique_order_idvalues to prevent duplicates - Rate Limiting: Implement reasonable limits on top-up frequency