Transfer Between Budget Accounts
Overview
Use this endpoint to transfer funds between two budget accounts. This enables flexible budget management, allowing you to reallocate funds between departments, projects, or card programs as business needs change.
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)
POST https://api.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer
Staging (gateway.ahrvo.network)
POST https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer
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 |
|---|---|---|---|
source_budget_id | string | Yes | The unique ID of the budget account from which funds are transferred (debited) |
target_budget_id | string | Yes | The unique ID of the budget account to which funds are transferred (credited) |
transfer_amount | string | Yes | The amount of funds to be transferred. Must be a positive number with up to 2 decimal places |
source_currency | string | Yes | Currency in which the source budget will be debited. Must follow ISO 4217 standard (e.g., USD, EUR, GBP) |
target_currency | string | Yes | Currency in which the target budget will be credited. Must follow ISO 4217 standard. Can differ from source for currency conversion |
Request Example
{
"source_budget_id": "ci202008281528472924",
"target_budget_id": "ci202105241445228411",
"transfer_amount": "802.90",
"source_currency": "USD",
"target_currency": "USD"
}
Response
Success Response (200 OK)
{
"code": "SUCCESS",
"data": {
"transfer_order_id": "toi202311021736413952",
"in_amount": "802.90"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
code | string | Status string indicating the result of the request. "SUCCESS" refers to a successful initiation |
data | object | Response data object |
data.transfer_order_id | string | A unique ID for the fund transfer order generated by the system. Use this to query the transfer status |
data.in_amount | string | The amount of funds transferred, denominated in the target_currency (after any currency conversion if applicable) |
Error Responses
- 400 Bad Request: Invalid parameters, insufficient funds in source budget, or invalid amount format
- 401 Unauthorized: Invalid or missing authentication token
- 403 Forbidden: Card issuance feature not enabled for this account
- 404 Not Found: One or both budget accounts do not exist
Code Examples
cURL
curl -X POST \
https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{
"source_budget_id": "ci202008281528472924",
"target_budget_id": "ci202105241445228411",
"transfer_amount": "802.90",
"source_currency": "USD",
"target_currency": "USD"
}'
Python
import requests
import time
url = "https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer"
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"x-api-key": "YOUR_API_KEY"
}
payload = {
"source_budget_id": "ci202008281528472924",
"target_budget_id": "ci202105241445228411",
"transfer_amount": "802.90",
"source_currency": "USD",
"target_currency": "USD"
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result['code'] == 'SUCCESS':
transfer_order_id = result['data']['transfer_order_id']
in_amount = result['data']['in_amount']
print(f"✓ Transfer initiated successfully")
print(f" Transfer Order ID: {transfer_order_id}")
print(f" Amount (Target Currency): {in_amount}")
print(f"\nUse the transfer order ID to check status with Query Transfer Order endpoint")
else:
print(f"Failed to initiate transfer: {result}")
JavaScript (Node.js)
const axios = require('axios');
const url = 'https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer';
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'x-api-key': 'YOUR_API_KEY'
};
const payload = {
source_budget_id: 'ci202008281528472924',
target_budget_id: 'ci202105241445228411',
transfer_amount: '802.90',
source_currency: 'USD',
target_currency: 'USD'
};
axios.post(url, payload, { headers })
.then(response => {
const result = response.data;
if (result.code === 'SUCCESS') {
console.log('✓ Transfer initiated successfully');
console.log(` Transfer Order ID: ${result.data.transfer_order_id}`);
console.log(` Amount (Target Currency): ${result.data.in_amount}`);
console.log('\nUse the transfer order ID to check status with Query Transfer Order endpoint');
}
})
.catch(error => {
console.error('Failed to initiate transfer:', error.response.data);
});
Usage Notes
- Asynchronous Processing: Transfers are processed asynchronously. The successful response means the request was accepted, not that funds have been transferred
- Status Verification: Use the Query Budget Transfer Order endpoint with
transfer_order_idto check if the transfer succeeded - Sufficient Balance: Ensure the source budget has sufficient funds before initiating transfer
- Amount Format: Provide amounts as strings with up to 2 decimal places (e.g., "802.90" not 802.90)
- Currency Conversion: If source and target currencies differ, conversion will be applied automatically
- Same Account: Cannot transfer between the same budget account (source and target must differ)
Common Use Cases
Basic Transfer with Status Verification
Transfer funds and verify completion:
def transfer_with_verification(source_id, target_id, amount, currency='USD'):
"""
Transfer funds between budgets and verify completion
"""
import time
# Initiate transfer
print(f"Initiating transfer of {currency} {amount}...")
response = initiate_budget_transfer(
source_budget_id=source_id,
target_budget_id=target_id,
transfer_amount=str(amount),
source_currency=currency,
target_currency=currency
)
if response['code'] == 'SUCCESS':
transfer_order_id = response['data']['transfer_order_id']
in_amount = response['data']['in_amount']
print(f"✓ Transfer initiated")
print(f" Transfer Order ID: {transfer_order_id}")
print(f" Target Amount: {currency} {in_amount}")
# Poll for completion
print("\nChecking transfer status...")
max_attempts = 10
for attempt in range(max_attempts):
time.sleep(3)
status_response = query_budget_transfer_order(transfer_order_id)
if status_response['code'] == 'SUCCESS':
fund_result = status_response['data']['fund_result']
if fund_result == 'SUCCESS':
print(f"✓ Transfer completed successfully")
return {
'success': True,
'transfer_order_id': transfer_order_id,
'amount': in_amount
}
elif fund_result == 'FAILED':
print(f"✗ Transfer failed")
return {
'success': False,
'transfer_order_id': transfer_order_id
}
print(f"⏳ Attempt {attempt + 1}/{max_attempts}: Still processing...")
print("⚠ Transfer status check timed out")
return {
'success': None,
'transfer_order_id': transfer_order_id,
'error': 'Timeout'
}
else:
print(f"✗ Failed to initiate transfer: {response}")
return {'success': False, 'error': response}
# Example usage
result = transfer_with_verification(
'ci202008281528472924',
'ci202105241445228411',
802.90
)
Budget Rebalancing
Automatically rebalance budgets to maintain target allocations:
async function rebalanceBudgets(budgets, targetAllocations) {
const transfers = [];
console.log('\n=== Budget Rebalancing ===');
// Calculate current total
let totalBalance = 0;
for (const budget of budgets) {
const balanceResponse = await queryBudgetBalance(budget.budget_id);
budget.current_balance = parseFloat(balanceResponse.data.balance);
totalBalance += budget.current_balance;
console.log(`${budget.name}: ${budget.currency} ${budget.current_balance}`);
}
console.log(`\nTotal Balance: USD ${totalBalance.toFixed(2)}`);
// Calculate target amounts
const rebalancing = [];
for (const budget of budgets) {
const targetPercentage = targetAllocations[budget.budget_id] || 0;
const targetAmount = totalBalance * (targetPercentage / 100);
const difference = targetAmount - budget.current_balance;
rebalancing.push({
...budget,
target_percentage: targetPercentage,
target_amount: targetAmount,
difference: difference
});
console.log(`${budget.name}: Target ${targetPercentage}% (${budget.currency} ${targetAmount.toFixed(2)}), Diff: ${difference.toFixed(2)}`);
}
// Sort by difference (negative first = needs funds)
rebalancing.sort((a, b) => a.difference - b.difference);
// Execute transfers
console.log('\n=== Executing Transfers ===');
for (const target of rebalancing) {
if (target.difference > 0) {
// This budget needs funds - find source with surplus
for (const source of rebalancing) {
if (source.difference < 0 && Math.abs(source.difference) >= target.difference) {
const transferAmount = Math.min(target.difference, Math.abs(source.difference));
console.log(`\nTransferring ${target.currency} ${transferAmount.toFixed(2)}`);
console.log(` From: ${source.name}`);
console.log(` To: ${target.name}`);
const transferResponse = await transferBetweenBudgets({
source_budget_id: source.budget_id,
target_budget_id: target.budget_id,
transfer_amount: transferAmount.toFixed(2),
source_currency: source.currency,
target_currency: target.currency
});
if (transferResponse.code === 'SUCCESS') {
console.log(` ✓ Transfer initiated: ${transferResponse.data.transfer_order_id}`);
transfers.push({
from: source.name,
to: target.name,
amount: transferAmount,
transfer_order_id: transferResponse.data.transfer_order_id
});
// Update differences
source.difference += transferAmount;
target.difference -= transferAmount;
} else {
console.log(` ✗ Transfer failed`);
}
break;
}
}
}
}
console.log(`\n=== Rebalancing Summary ===`);
console.log(`Total Transfers: ${transfers.length}`);
return transfers;
}
// Example usage
const budgets = [
{ budget_id: 'ci202008281528472924', name: 'Marketing', currency: 'USD' },
{ budget_id: 'ci202105241445228411', name: 'Operations', currency: 'USD' },
{ budget_id: 'ci202105241445228412', name: 'Sales', currency: 'USD' }
];
const targetAllocations = {
'ci202008281528472924': 40, // Marketing: 40%
'ci202105241445228411': 35, // Operations: 35%
'ci202105241445228412': 25 // Sales: 25%
};
const transfers = await rebalanceBudgets(budgets, targetAllocations);
Department Budget Allocation
Distribute funds from a master budget to department budgets:
def allocate_to_departments(master_budget_id, department_allocations):
"""
Distribute funds from master budget to department budgets
Args:
master_budget_id: Source budget ID
department_allocations: List of dicts with budget_id, name, amount, currency
"""
import time
print("\n=== Department Budget Allocation ===")
# Check master budget balance
master_balance_response = query_budget_balance(master_budget_id)
master_balance = float(master_balance_response['data']['balance'])
master_currency = master_balance_response['data']['currency']
total_allocation = sum(dept['amount'] for dept in department_allocations)
print(f"Master Budget Balance: {master_currency} {master_balance}")
print(f"Total Allocation Requested: {master_currency} {total_allocation}")
if master_balance < total_allocation:
print(f"\n✗ Insufficient funds in master budget")
print(f" Available: {master_currency} {master_balance}")
print(f" Required: {master_currency} {total_allocation}")
return {'success': False, 'error': 'Insufficient funds'}
results = {
'successful': [],
'failed': []
}
# Execute transfers
print(f"\nAllocating to {len(department_allocations)} departments...")
for dept in department_allocations:
dept_name = dept['name']
dept_budget_id = dept['budget_id']
amount = dept['amount']
currency = dept.get('currency', master_currency)
print(f"\n{dept_name}: {currency} {amount}")
try:
response = initiate_budget_transfer(
source_budget_id=master_budget_id,
target_budget_id=dept_budget_id,
transfer_amount=str(amount),
source_currency=master_currency,
target_currency=currency
)
if response['code'] == 'SUCCESS':
transfer_order_id = response['data']['transfer_order_id']
print(f" ✓ Transfer initiated: {transfer_order_id}")
results['successful'].append({
'department': dept_name,
'budget_id': dept_budget_id,
'amount': amount,
'currency': currency,
'transfer_order_id': transfer_order_id
})
else:
print(f" ✗ Transfer failed: {response}")
results['failed'].append({
'department': dept_name,
'error': response
})
time.sleep(1) # Rate limiting
except Exception as e:
print(f" ✗ Error: {e}")
results['failed'].append({
'department': dept_name,
'error': str(e)
})
# Summary
print(f"\n=== Allocation Summary ===")
print(f"Successful: {len(results['successful'])}")
print(f"Failed: {len(results['failed'])}")
# Verify transfers
if results['successful']:
print("\nVerifying transfer statuses...")
time.sleep(5)
for item in results['successful']:
status_response = query_budget_transfer_order(item['transfer_order_id'])
status = status_response['data']['fund_result']
status_icon = '✓' if status == 'SUCCESS' else '✗'
print(f" {status_icon} {item['department']}: {status}")
return results
# Example usage
allocations = [
{
'budget_id': 'ci202105241445228411',
'name': 'Engineering',
'amount': 50000.00,
'currency': 'USD'
},
{
'budget_id': 'ci202105241445228412',
'name': 'Marketing',
'amount': 30000.00,
'currency': 'USD'
},
{
'budget_id': 'ci202105241445228413',
'name': 'Sales',
'amount': 20000.00,
'currency': 'USD'
}
]
results = allocate_to_departments('ci202008281528472924', allocations)
Emergency Budget Transfer
Quickly transfer funds to cover urgent expenses:
async function emergencyTransfer(sourceBudgetId, targetBudgetId, amount, reason) {
console.log('\n🚨 EMERGENCY TRANSFER INITIATED 🚨');
console.log(`Reason: ${reason}`);
console.log(`Amount: USD ${amount}`);
try {
// Check source budget balance
const sourceBalance = await queryBudgetBalance(sourceBudgetId);
const availableBalance = parseFloat(sourceBalance.data.balance);
console.log(`\nSource Budget Balance: USD ${availableBalance}`);
if (availableBalance < amount) {
console.log('✗ Insufficient funds for emergency transfer');
return {
success: false,
error: 'Insufficient funds',
available: availableBalance,
required: amount
};
}
// Initiate transfer
console.log('\nInitiating emergency transfer...');
const transferResponse = await transferBetweenBudgets({
source_budget_id: sourceBudgetId,
target_budget_id: targetBudgetId,
transfer_amount: amount.toFixed(2),
source_currency: 'USD',
target_currency: 'USD'
});
if (transferResponse.code === 'SUCCESS') {
const transferOrderId = transferResponse.data.transfer_order_id;
console.log(`✓ Transfer initiated: ${transferOrderId}`);
// Rapid status checking
console.log('\nMonitoring transfer status...');
let attempts = 0;
const maxAttempts = 20; // More attempts for emergency
while (attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 2000)); // Check every 2 seconds
attempts++;
const statusResponse = await queryBudgetTransferOrder(transferOrderId);
const status = statusResponse.data.fund_result;
if (status === 'SUCCESS') {
console.log('\n✓ EMERGENCY TRANSFER COMPLETED');
// Verify target balance updated
const targetBalance = await queryBudgetBalance(targetBudgetId);
console.log(`Target Budget New Balance: USD ${targetBalance.data.balance}`);
// Send alert
await sendAlert({
type: 'emergency_transfer_success',
source_budget: sourceBudgetId,
target_budget: targetBudgetId,
amount: amount,
reason: reason,
transfer_order_id: transferOrderId
});
return {
success: true,
transfer_order_id: transferOrderId,
amount: amount,
completed_in_seconds: attempts * 2
};
} else if (status === 'FAILED') {
console.log('\n✗ EMERGENCY TRANSFER FAILED');
await sendAlert({
type: 'emergency_transfer_failed',
source_budget: sourceBudgetId,
target_budget: targetBudgetId,
amount: amount,
reason: reason,
transfer_order_id: transferOrderId
});
return {
success: false,
error: 'Transfer failed',
transfer_order_id: transferOrderId
};
}
console.log(`⏳ Attempt ${attempts}/${maxAttempts}: Status ${status}`);
}
console.log('\n⚠ Transfer status check timed out');
return {
success: null,
error: 'Timeout',
transfer_order_id: transferOrderId
};
} else {
console.log('✗ Failed to initiate emergency transfer');
return {
success: false,
error: transferResponse
};
}
} catch (error) {
console.error('Emergency transfer error:', error);
throw error;
}
}
// Example usage
const result = await emergencyTransfer(
'ci202008281528472924', // Reserve budget
'ci202105241445228411', // Operations budget
5000.00,
'Critical server infrastructure payment'
);
Scheduled Inter-Budget Transfers
Automate recurring transfers between budgets:
def scheduled_inter_budget_transfers(transfer_schedules):
"""
Execute scheduled transfers between budgets
Args:
transfer_schedules: List of scheduled transfer configs
"""
from datetime import datetime
import time
print(f"\n=== Scheduled Transfers - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===")
results = {
'executed': [],
'skipped': [],
'failed': []
}
for schedule in transfer_schedules:
schedule_name = schedule['name']
source_id = schedule['source_budget_id']
target_id = schedule['target_budget_id']
amount = schedule['amount']
currency = schedule['currency']
condition = schedule.get('condition', 'always') # always, if_source_above_threshold, etc.
print(f"\n{schedule_name}")
print(f" From: {source_id}")
print(f" To: {target_id}")
print(f" Amount: {currency} {amount}")
print(f" Condition: {condition}")
try:
# Check condition
should_execute = True
if condition == 'if_source_above_threshold':
threshold = schedule.get('threshold', 0)
source_balance_response = query_budget_balance(source_id)
source_balance = float(source_balance_response['data']['balance'])
print(f" Source Balance: {currency} {source_balance} (Threshold: {threshold})")
if source_balance <= threshold:
print(f" ⊘ Skipped: Balance below threshold")
results['skipped'].append({
'name': schedule_name,
'reason': 'Balance below threshold'
})
should_execute = False
elif condition == 'if_target_below_threshold':
threshold = schedule.get('threshold', 0)
target_balance_response = query_budget_balance(target_id)
target_balance = float(target_balance_response['data']['balance'])
print(f" Target Balance: {currency} {target_balance} (Threshold: {threshold})")
if target_balance >= threshold:
print(f" ⊘ Skipped: Target already above threshold")
results['skipped'].append({
'name': schedule_name,
'reason': 'Target above threshold'
})
should_execute = False
if should_execute:
# Execute transfer
response = initiate_budget_transfer(
source_budget_id=source_id,
target_budget_id=target_id,
transfer_amount=str(amount),
source_currency=currency,
target_currency=currency
)
if response['code'] == 'SUCCESS':
transfer_order_id = response['data']['transfer_order_id']
print(f" ✓ Executed: {transfer_order_id}")
results['executed'].append({
'name': schedule_name,
'transfer_order_id': transfer_order_id,
'amount': amount,
'currency': currency
})
else:
print(f" ✗ Failed: {response}")
results['failed'].append({
'name': schedule_name,
'error': response
})
time.sleep(1)
except Exception as e:
print(f" ✗ Error: {e}")
results['failed'].append({
'name': schedule_name,
'error': str(e)
})
# Summary
print(f"\n=== Execution Summary ===")
print(f"Executed: {len(results['executed'])}")
print(f"Skipped: {len(results['skipped'])}")
print(f"Failed: {len(results['failed'])}")
return results
# Example usage - Daily scheduled transfers
schedules = [
{
'name': 'Daily Marketing Allocation',
'source_budget_id': 'ci202008281528472924', # Master budget
'target_budget_id': 'ci202105241445228411', # Marketing budget
'amount': 1000.00,
'currency': 'USD',
'condition': 'if_source_above_threshold',
'threshold': 10000.00
},
{
'name': 'Low Balance Top-Up - Operations',
'source_budget_id': 'ci202008281528472924', # Master budget
'target_budget_id': 'ci202105241445228412', # Operations budget
'amount': 5000.00,
'currency': 'USD',
'condition': 'if_target_below_threshold',
'threshold': 2000.00
}
]
results = scheduled_inter_budget_transfers(schedules)
Cross-Currency Budget Transfer
Transfer funds with currency conversion:
async function crossCurrencyTransfer(sourceBudgetId, targetBudgetId, amount, sourceCurrency, targetCurrency) {
console.log('\n=== Cross-Currency Transfer ===');
console.log(`Amount: ${sourceCurrency} ${amount}`);
console.log(`From Currency: ${sourceCurrency}`);
console.log(`To Currency: ${targetCurrency}`);
try {
// Initiate transfer
const transferResponse = await transferBetweenBudgets({
source_budget_id: sourceBudgetId,
target_budget_id: targetBudgetId,
transfer_amount: amount.toFixed(2),
source_currency: sourceCurrency,
target_currency: targetCurrency
});
if (transferResponse.code === 'SUCCESS') {
const transferOrderId = transferResponse.data.transfer_order_id;
const inAmount = parseFloat(transferResponse.data.in_amount);
console.log(`\n✓ Transfer initiated: ${transferOrderId}`);
console.log(`Source Amount: ${sourceCurrency} ${amount}`);
console.log(`Target Amount: ${targetCurrency} ${inAmount}`);
// Calculate exchange rate
const exchangeRate = inAmount / amount;
console.log(`Effective Exchange Rate: ${exchangeRate.toFixed(4)}`);
// Wait for completion
console.log('\nWaiting for transfer to complete...');
let attempts = 0;
const maxAttempts = 10;
while (attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 3000));
attempts++;
const statusResponse = await queryBudgetTransferOrder(transferOrderId);
const status = statusResponse.data.fund_result;
if (status === 'SUCCESS') {
console.log('\n✓ Cross-currency transfer completed successfully');
return {
success: true,
transfer_order_id: transferOrderId,
source_amount: amount,
source_currency: sourceCurrency,
target_amount: inAmount,
target_currency: targetCurrency,
exchange_rate: exchangeRate
};
} else if (status === 'FAILED') {
console.log('\n✗ Cross-currency transfer failed');
return {
success: false,
transfer_order_id: transferOrderId,
error: 'Transfer failed'
};
}
console.log(`⏳ Attempt ${attempts}/${maxAttempts}: Still processing...`);
}
console.log('\n⚠ Transfer status check timed out');
return {
success: null,
transfer_order_id: transferOrderId,
error: 'Timeout'
};
} else {
console.log('✗ Failed to initiate transfer');
return {
success: false,
error: transferResponse
};
}
} catch (error) {
console.error('Cross-currency transfer error:', error);
throw error;
}
}
// Example usage
const result = await crossCurrencyTransfer(
'ci202008281528472924', // USD budget
'ci202105241445228411', // EUR budget
1000.00,
'USD',
'EUR'
);
Best Practices
- Check Balances First: Always verify source budget has sufficient funds before initiating transfer
- Verify Status: Use Query Budget Transfer Order endpoint to confirm transfer completed successfully
- Atomic Operations: Transfers are atomic - either fully succeed or fully fail, no partial transfers
- Amount Validation: Validate amounts are positive and properly formatted before submission
- Currency Matching: Be aware of currency conversion when source and target currencies differ
- Error Handling: Handle insufficient funds, invalid budgets, and network errors gracefully
- Audit Trail: Log all transfers for financial reconciliation and compliance
- Rate Limiting: Add delays between batch transfers to avoid rate limits
Transfer Workflow
Standard Process
- Validate Budgets: Confirm both source and target budget accounts exist
- Check Source Balance: Verify source budget has sufficient funds
- Initiate Transfer: Call this endpoint with transfer details
- Store Transfer ID: Save
transfer_order_idfor tracking - Poll Status: Use Query Budget Transfer Order endpoint to check status
- Wait for Completion: Continue polling until SUCCESS or FAILED
- Verify Balances: Confirm both budgets reflect the transfer
- Update Records: Update your financial systems with completed transfer
Related Endpoints
- Query Budget Transfer Order - Check the status of a transfer using
transfer_order_id - Query Budget Balance - View budget balances before and after transfers
- Create Budget Account - Create budget accounts for transfers
- Top Up Budget Account - Add funds to budgets from external sources
Troubleshooting
Insufficient Funds (400)
- Cause: Source budget doesn't have enough balance
- Solution:
- Check source budget balance with Query Budget Balance
- Top up source budget first if needed
- Reduce transfer amount
Budget Not Found (404)
- Cause: One or both budget IDs don't exist
- Solution:
- Verify both budget IDs are correct
- Ensure budgets were created successfully
- Check if budgets were deleted
Same Source and Target (400)
- Cause: Attempting to transfer to the same budget
- Solution:
- Verify source and target IDs are different
- Check for copy-paste errors
Transfer Stuck in Processing
- Cause: Transfer processing is delayed
- Solution:
- Continue polling for up to 5-10 minutes
- Check if source budget is frozen or locked
- Contact support if status doesn't update
Currency Conversion Issues
- Cause: Invalid currency codes or conversion not supported
- Solution:
- Use valid ISO 4217 currency codes
- Verify currency conversion is supported
- Contact support for currency availability
Security Considerations
- Authorization: Ensure proper authorization before allowing budget transfers
- Balance Validation: Always validate sufficient funds before transfer
- Transfer Limits: Consider implementing transfer limits for security
- Audit Logging: Maintain comprehensive logs of all transfer operations
- Fraud Detection: Monitor for unusual transfer patterns
- Access Control: Restrict transfer permissions to authorized personnel only