Skip to main content

Query Budget Transfer Order

Overview

Use this endpoint to query the status of a specific transfer between two budget accounts. This allows you to verify whether a transfer was successful or failed, which is essential for reconciliation and error handling in your budget management 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/transfer/order

Staging (gateway.ahrvo.network)

GET https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer/order

Request Headers

HeaderValueRequiredDescription
Acceptapplication/jsonYesContent type for the response
AuthorizationBearer {access_token}YesBearer token for authentication
x-api-keyAPI KeyYesAPI key for authentication

Query Parameters

ParameterTypeRequiredDescription
transfer_order_idstringYesA unique ID for the fund transfer order (received from the transfer initiation response)

Response

Success Response (200 OK)

{
"code": "SUCCESS",
"data": {
"fund_result": "SUCCESS"
}
}

Response Fields

FieldTypeDescription
codestringStatus string indicating the result of the query. "SUCCESS" refers to a successful query
dataobjectResponse data object
data.fund_resultstringThe processing status of the transfer order. "SUCCESS" indicates the transfer was successful, "FAILED" indicates it failed

Transfer Status Values

StatusDescription
SUCCESSThe transfer was completed successfully
FAILEDThe transfer failed (insufficient funds, invalid accounts, etc.)

Error Responses

  • 400 Bad Request: Invalid or missing transfer_order_id
  • 401 Unauthorized: Invalid or missing authentication token
  • 403 Forbidden: Card issuance feature not enabled for this account
  • 404 Not Found: Transfer order does not exist

Code Examples

cURL

curl -X GET \
'https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer/order?transfer_order_id=toi202311021736413952' \
-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/transfer/order"
headers = {
"Accept": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"x-api-key": "YOUR_API_KEY"
}
params = {
"transfer_order_id": "toi202311021736413952"
}

response = requests.get(url, headers=headers, params=params)
result = response.json()

if result['code'] == 'SUCCESS':
transfer_status = result['data']['fund_result']

if transfer_status == 'SUCCESS':
print("✓ Transfer completed successfully")
elif transfer_status == 'FAILED':
print("✗ Transfer failed")
else:
print(f"Transfer status: {transfer_status}")
else:
print(f"Failed to query transfer order: {result}")

JavaScript (Node.js)

const axios = require('axios');

const url = 'https://gateway.ahrvo.network/card/issuance/api/issuing/budget/v2/transfer/order';
const headers = {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'x-api-key': 'YOUR_API_KEY'
};
const params = {
transfer_order_id: 'toi202311021736413952'
};

axios.get(url, { headers, params })
.then(response => {
const result = response.data;

if (result.code === 'SUCCESS') {
const transferStatus = result.data.fund_result;

if (transferStatus === 'SUCCESS') {
console.log('✓ Transfer completed successfully');
} else if (transferStatus === 'FAILED') {
console.log('✗ Transfer failed');
} else {
console.log(`Transfer status: ${transferStatus}`);
}
}
})
.catch(error => {
console.error('Failed to query transfer order:', error.response.data);
});

Usage Notes

  • Transfer Order ID: You receive this ID when you initiate a transfer between budget accounts
  • Asynchronous Processing: Transfers may be processed asynchronously, so query the status to confirm completion
  • Status Check: Always verify the transfer status before proceeding with dependent operations
  • Idempotent: You can query the same transfer order multiple times safely
  • Reconciliation: Use this endpoint for reconciliation and audit purposes

Common Use Cases

Verify Transfer After Initiation

Check if a transfer completed successfully after initiating it:

def verify_transfer_completion(transfer_order_id, max_attempts=5, wait_seconds=2):
"""
Verify a transfer has completed successfully with retry logic
"""
import time

for attempt in range(max_attempts):
try:
response = query_budget_transfer_order(transfer_order_id)

if response['code'] == 'SUCCESS':
fund_result = response['data']['fund_result']

if fund_result == 'SUCCESS':
print(f"✓ Transfer {transfer_order_id} completed successfully")
return True
elif fund_result == 'FAILED':
print(f"✗ Transfer {transfer_order_id} failed")
return False

# Wait before retrying
if attempt < max_attempts - 1:
print(f"Attempt {attempt + 1}/{max_attempts}: Transfer still processing, waiting {wait_seconds}s...")
time.sleep(wait_seconds)

except Exception as e:
print(f"Error checking transfer status: {e}")
if attempt < max_attempts - 1:
time.sleep(wait_seconds)

print(f"⚠ Could not verify transfer status after {max_attempts} attempts")
return None

# Example usage
transfer_order_id = "toi202311021736413952"
success = verify_transfer_completion(transfer_order_id)

Transfer with Confirmation

Initiate a transfer and wait for confirmation:

async function transferWithConfirmation(fromBudgetId, toBudgetId, amount) {
try {
// Step 1: Initiate transfer
console.log('Initiating transfer...');
const transferResponse = await initiateTransfer({
from_budget_id: fromBudgetId,
to_budget_id: toBudgetId,
amount: amount
});

const transferOrderId = transferResponse.data.transfer_order_id;
console.log(`Transfer initiated: ${transferOrderId}`);

// Step 2: Wait and verify completion
console.log('Verifying transfer completion...');
const maxAttempts = 5;
const delayMs = 2000;

for (let attempt = 1; attempt <= maxAttempts; attempt++) {
await new Promise(resolve => setTimeout(resolve, delayMs));

const statusResponse = await queryBudgetTransferOrder(transferOrderId);

if (statusResponse.code === 'SUCCESS') {
const fundResult = statusResponse.data.fund_result;

if (fundResult === 'SUCCESS') {
console.log('✓ Transfer completed successfully');
return {
success: true,
transfer_order_id: transferOrderId
};
} else if (fundResult === 'FAILED') {
console.log('✗ Transfer failed');
return {
success: false,
transfer_order_id: transferOrderId,
error: 'Transfer failed'
};
}
}

console.log(`Attempt ${attempt}/${maxAttempts}: Still processing...`);
}

console.log('⚠ Transfer status could not be confirmed');
return {
success: null,
transfer_order_id: transferOrderId,
error: 'Status verification timeout'
};
} catch (error) {
console.error('Transfer with confirmation failed:', error);
throw error;
}
}

// Example usage
const result = await transferWithConfirmation(
'ci202507232016182661',
'ci202507232016182662',
5000.00
);

Batch Transfer Verification

Verify multiple transfers at once:

def verify_batch_transfers(transfer_order_ids):
"""
Verify the status of multiple transfers
"""
results = {
'successful': [],
'failed': [],
'pending': []
}

for transfer_id in transfer_order_ids:
try:
response = query_budget_transfer_order(transfer_id)

if response['code'] == 'SUCCESS':
fund_result = response['data']['fund_result']

if fund_result == 'SUCCESS':
results['successful'].append(transfer_id)
elif fund_result == 'FAILED':
results['failed'].append(transfer_id)
else:
results['pending'].append(transfer_id)
except Exception as e:
print(f"Error checking transfer {transfer_id}: {e}")
results['pending'].append(transfer_id)

# Print summary
print("\n=== Transfer Verification Summary ===")
print(f"Total Transfers: {len(transfer_order_ids)}")
print(f"Successful: {len(results['successful'])}")
print(f"Failed: {len(results['failed'])}")
print(f"Pending/Unknown: {len(results['pending'])}")

return results

# Example usage
transfer_ids = [
"toi202311021736413952",
"toi202311021736413953",
"toi202311021736413954"
]
verification_results = verify_batch_transfers(transfer_ids)

Reconciliation Report

Generate a reconciliation report for transfers:

async function generateTransferReconciliationReport(transferOrders) {
const report = {
generated_at: new Date().toISOString(),
total_transfers: transferOrders.length,
successful_count: 0,
failed_count: 0,
total_amount_successful: 0,
total_amount_failed: 0,
details: []
};

for (const order of transferOrders) {
try {
const response = await queryBudgetTransferOrder(order.transfer_order_id);

if (response.code === 'SUCCESS') {
const status = response.data.fund_result;
const detail = {
transfer_order_id: order.transfer_order_id,
from_budget: order.from_budget_name,
to_budget: order.to_budget_name,
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;
}

report.details.push(detail);
}
} catch (error) {
console.error(`Error checking transfer ${order.transfer_order_id}:`, error);
}
}

// Print report
console.log('\n=== Transfer Reconciliation Report ===');
console.log(`Generated: ${report.generated_at}`);
console.log(`Total Transfers: ${report.total_transfers}`);
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('\nDetails:');

report.details.forEach(detail => {
const statusIcon = detail.status === 'SUCCESS' ? '✓' : '✗';
console.log(`${statusIcon} ${detail.transfer_order_id}: ${detail.from_budget}${detail.to_budget} (${detail.currency} ${detail.amount})`);
});

return report;
}

// Example usage
const transfers = [
{
transfer_order_id: 'toi202311021736413952',
from_budget_name: 'Marketing',
to_budget_name: 'Operations',
amount: 5000,
currency: 'USD',
initiated_at: '2026-02-07T10:30:00Z'
},
// ... more transfers
];

const report = await generateTransferReconciliationReport(transfers);

Automated Retry on Failed Transfer

Handle failed transfers with automated retry:

def transfer_with_retry(from_budget_id, to_budget_id, amount, max_retries=3):
"""
Initiate transfer with automatic retry on failure
"""
for attempt in range(max_retries):
try:
# Initiate transfer
transfer_response = initiate_budget_transfer(
from_budget_id,
to_budget_id,
amount
)

transfer_order_id = transfer_response['data']['transfer_order_id']
print(f"Transfer initiated (Attempt {attempt + 1}): {transfer_order_id}")

# Wait for processing
time.sleep(3)

# Check status
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 successful on attempt {attempt + 1}")
return {
'success': True,
'transfer_order_id': transfer_order_id,
'attempts': attempt + 1
}
elif fund_result == 'FAILED':
print(f"✗ Transfer failed on attempt {attempt + 1}")

if attempt < max_retries - 1:
print(f"Retrying... ({max_retries - attempt - 1} attempts remaining)")
time.sleep(5) # Wait longer before retry
else:
return {
'success': False,
'transfer_order_id': transfer_order_id,
'attempts': attempt + 1,
'error': 'Transfer failed after all retries'
}

except Exception as e:
print(f"Error on attempt {attempt + 1}: {e}")
if attempt < max_retries - 1:
time.sleep(5)
else:
return {
'success': False,
'attempts': attempt + 1,
'error': str(e)
}

return {
'success': False,
'attempts': max_retries,
'error': 'Max retries exceeded'
}

# Example usage
result = transfer_with_retry('ci202507232016182661', 'ci202507232016182662', 5000.00)

Transfer Monitoring Dashboard

Monitor ongoing transfers:

class TransferMonitor {
constructor() {
this.pendingTransfers = new Map();
}

async addTransfer(transferOrderId, metadata = {}) {
this.pendingTransfers.set(transferOrderId, {
...metadata,
added_at: new Date(),
last_checked: null,
status: 'PENDING'
});

console.log(`Added transfer to monitor: ${transferOrderId}`);
}

async checkAllTransfers() {
console.log(`\nChecking ${this.pendingTransfers.size} pending transfers...`);

const completedTransfers = [];

for (const [transferId, info] of this.pendingTransfers.entries()) {
try {
const response = await queryBudgetTransferOrder(transferId);

if (response.code === 'SUCCESS') {
const status = response.data.fund_result;
info.last_checked = new Date();
info.status = status;

if (status === 'SUCCESS' || status === 'FAILED') {
console.log(` ${status === 'SUCCESS' ? '✓' : '✗'} ${transferId}: ${status}`);
completedTransfers.push(transferId);
} else {
console.log(`${transferId}: Still processing`);
}
}
} catch (error) {
console.error(` Error checking ${transferId}:`, error.message);
}
}

// Remove completed transfers
completedTransfers.forEach(id => {
console.log(`Removing completed transfer: ${id}`);
this.pendingTransfers.delete(id);
});

return {
checked: this.pendingTransfers.size + completedTransfers.length,
completed: completedTransfers.length,
pending: this.pendingTransfers.size
};
}

getPendingCount() {
return this.pendingTransfers.size;
}

getPendingTransfers() {
return Array.from(this.pendingTransfers.entries()).map(([id, info]) => ({
transfer_order_id: id,
...info
}));
}
}

// Example usage
const monitor = new TransferMonitor();

// Add transfers to monitor
await monitor.addTransfer('toi202311021736413952', {
amount: 5000,
from: 'Marketing',
to: 'Operations'
});

// Check periodically
setInterval(async () => {
if (monitor.getPendingCount() > 0) {
const results = await monitor.checkAllTransfers();
console.log(`\nMonitoring Summary: ${results.pending} pending, ${results.completed} completed`);
}
}, 5000); // Check every 5 seconds

Best Practices

  • Always Verify: Check transfer status after initiating a transfer
  • Retry Logic: Implement retry logic with exponential backoff for queries
  • Store Transfer IDs: Save transfer order IDs for reconciliation and audit purposes
  • Timeout Handling: Set reasonable timeouts for status verification
  • Error Handling: Handle all possible status values and error cases
  • Reconciliation: Regularly reconcile transfers with your internal records

Transfer Workflow

Standard Transfer Process

  1. Initiate Transfer: Call the transfer endpoint to move funds between budgets
  2. Receive Transfer Order ID: Store the returned transfer_order_id
  3. Wait for Processing: Allow time for the transfer to process (typically seconds)
  4. Query Status: Use this endpoint to check the transfer status
  5. Handle Result: Take appropriate action based on SUCCESS or FAILED status
  6. Update Records: Update your internal systems with the final status
  • Transfer Between Budgets - Initiate a transfer between two budget accounts
  • Query Budget Balance - Check available balance before and after transfers
  • Create Budget Account - Create budget accounts for transfers
  • Query Budget Details - Get detailed information about budget accounts

Troubleshooting

Transfer Order Not Found (404)

  • Cause: Invalid transfer_order_id or transfer doesn't exist
  • Solution:
    • Verify the transfer_order_id is correct
    • Ensure you're using the ID from a valid transfer initiation

Transfer Status Remains Pending

  • Cause: Transfer is still processing or stuck
  • Solution:
    • Wait longer and retry the query
    • Check with support if status doesn't update after several minutes
    • Verify source budget has sufficient funds

Failed Transfer Status

  • Cause: Transfer failed due to insufficient funds, invalid budgets, or other issues
  • Solution:
    • Check source budget balance
    • Verify both budget IDs exist
    • Review transfer amount and currency
    • Contact support if issue persists

Security Considerations

  • Transfer Order ID Security: Treat transfer order IDs as sensitive information
  • Audit Logging: Log all transfer status queries for audit purposes
  • Access Control: Implement proper authorization before allowing status queries
  • Data Retention: Maintain transfer records for compliance requirements

Interactive API Explorer