Fetch a Balance Transfer
Retrieve the details of a specific balance_transfer resource. This endpoint is essential for checking the status of a transfer, verifying completion, and retrieving transfer details for reconciliation.
Use Cases
1. Check Transfer Status
Verify if a balance transfer completed successfully:
curl https://api.ahrvo.network/payments/na/balance_transfers/BT_nRWVzeXvbou13Zg7UBNnYr \
-u username:password \
-H "Content-Type: application/json"
2. Poll Transfer Until Complete
Monitor a transfer until it reaches a final state:
async function waitForTransferCompletion(transferId, maxAttempts = 20) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
console.log(`Transfer ${transferId} status: ${transfer.state} (attempt ${attempt + 1})`);
if (transfer.state === 'SUCCEEDED') {
console.log('Transfer completed successfully');
return transfer;
}
if (transfer.state === 'FAILED') {
console.error('Transfer failed');
return transfer;
}
// Still pending, wait before next check
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
}
console.warn(`Transfer still pending after ${maxAttempts} attempts`);
return null;
}
3. Verify Transfer Details
Retrieve and verify specific transfer information:
async function verifyTransfer(transferId, expectedAmount, expectedDestination) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
// Verify amount
if (transfer.amount !== expectedAmount) {
throw new Error(
`Amount mismatch: expected ${expectedAmount}, got ${transfer.amount}`
);
}
// Verify destination
if (transfer.destination !== expectedDestination) {
throw new Error(
`Destination mismatch: expected ${expectedDestination}, got ${transfer.destination}`
);
}
// Verify state
if (transfer.state !== 'SUCCEEDED') {
throw new Error(`Transfer not successful: ${transfer.state}`);
}
console.log('Transfer verification passed:', transferId);
return transfer;
}
4. Get Transfer for Reconciliation
Fetch transfer details for accounting reconciliation:
async function getTransferForReconciliation(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
// Extract reconciliation data
const reconciliationRecord = {
transfer_id: transfer.id,
date: transfer.created_at.split('T')[0],
amount: transfer.amount / 100, // Convert to dollars
source: transfer.source,
destination: transfer.destination,
state: transfer.state,
reference_id: transfer.reference_id,
description: transfer.description,
tags: transfer.tags
};
console.log('Reconciliation record:', reconciliationRecord);
return reconciliationRecord;
}
5. Check Failed Transfer
Investigate a failed transfer:
async function investigateFailedTransfer(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
if (transfer.state !== 'FAILED') {
console.log(`Transfer ${transferId} is not failed (state: ${transfer.state})`);
return transfer;
}
// Analyze failure
console.error('Failed Transfer Analysis:', {
id: transfer.id,
amount: transfer.amount / 100,
source: transfer.source,
destination: transfer.destination,
created_at: transfer.created_at,
updated_at: transfer.updated_at,
description: transfer.description,
reference_id: transfer.reference_id,
processor_type: transfer.processor_type,
tags: transfer.tags
});
// Create incident report
await createIncidentReport('balance_transfer_failure', {
transfer_id: transferId,
amount: transfer.amount,
timestamp: transfer.created_at,
details: transfer
});
return transfer;
}
6. Retrieve Transfer with Retry Logic
Implement robust retrieval with automatic retries:
async function fetchTransferWithRetry(transferId, maxRetries = 3) {
let lastError;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
if (response.status === 404) {
throw new Error(`Transfer ${transferId} not found`);
}
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const transfer = await response.json();
return transfer;
} catch (error) {
lastError = error;
console.warn(`Attempt ${attempt + 1} failed:`, error.message);
if (attempt < maxRetries - 1) {
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
console.log(`Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw new Error(`Failed to fetch transfer after ${maxRetries} attempts: ${lastError.message}`);
}
7. Get Transfer Age
Calculate how long ago a transfer was created:
async function getTransferAge(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
const createdAt = new Date(transfer.created_at);
const now = new Date();
const ageMs = now - createdAt;
const ageMinutes = Math.floor(ageMs / 60000);
const ageHours = Math.floor(ageMinutes / 60);
const ageDays = Math.floor(ageHours / 24);
let ageString;
if (ageDays > 0) {
ageString = `${ageDays} day${ageDays > 1 ? 's' : ''} ago`;
} else if (ageHours > 0) {
ageString = `${ageHours} hour${ageHours > 1 ? 's' : ''} ago`;
} else {
ageString = `${ageMinutes} minute${ageMinutes > 1 ? 's' : ''} ago`;
}
return {
transfer_id: transferId,
created_at: transfer.created_at,
age_ms: ageMs,
age_minutes: ageMinutes,
age_hours: ageHours,
age_days: ageDays,
age_string: ageString,
state: transfer.state
};
}
8. Build Transfer Timeline
Create a timeline view of transfer events:
async function buildTransferTimeline(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
const timeline = [
{
timestamp: transfer.created_at,
event: 'Transfer Created',
details: {
amount: transfer.amount,
source: transfer.source,
destination: transfer.destination,
description: transfer.description
}
}
];
// If updated_at is different from created_at, add update event
if (transfer.updated_at !== transfer.created_at) {
timeline.push({
timestamp: transfer.updated_at,
event: `Transfer ${transfer.state}`,
details: {
state: transfer.state,
reference_id: transfer.reference_id
}
});
}
// Sort by timestamp
timeline.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
return {
transfer_id: transferId,
current_state: transfer.state,
timeline: timeline
};
}
9. Compare Transfer with Expected Values
Validate transfer matches expected parameters:
async function validateTransfer(transferId, expectedValues) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
const validationResults = {
transfer_id: transferId,
valid: true,
errors: []
};
// Check amount
if (expectedValues.amount && transfer.amount !== expectedValues.amount) {
validationResults.valid = false;
validationResults.errors.push({
field: 'amount',
expected: expectedValues.amount,
actual: transfer.amount
});
}
// Check source
if (expectedValues.source && transfer.source !== expectedValues.source) {
validationResults.valid = false;
validationResults.errors.push({
field: 'source',
expected: expectedValues.source,
actual: transfer.source
});
}
// Check destination
if (expectedValues.destination && transfer.destination !== expectedValues.destination) {
validationResults.valid = false;
validationResults.errors.push({
field: 'destination',
expected: expectedValues.destination,
actual: transfer.destination
});
}
// Check state
if (expectedValues.state && transfer.state !== expectedValues.state) {
validationResults.valid = false;
validationResults.errors.push({
field: 'state',
expected: expectedValues.state,
actual: transfer.state
});
}
if (!validationResults.valid) {
console.error('Transfer validation failed:', validationResults.errors);
}
return validationResults;
}
10. Export Transfer Details
Generate a detailed report of a specific transfer:
async function exportTransferDetails(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
}
}
);
const transfer = await response.json();
// Create detailed report
const report = {
'Transfer ID': transfer.id,
'Created At': new Date(transfer.created_at).toLocaleString(),
'Updated At': new Date(transfer.updated_at).toLocaleString(),
'Amount': `$${(transfer.amount / 100).toFixed(2)} ${transfer.currency}`,
'Source Account': transfer.source,
'Destination Account': transfer.destination,
'State': transfer.state,
'Description': transfer.description || 'N/A',
'Processor Type': transfer.processor_type,
'Reference ID': transfer.reference_id,
'External Reference ID': transfer.external_reference_id || 'N/A',
'Tags': JSON.stringify(transfer.tags || {}, null, 2)
};
// Format as readable text
const reportText = Object.entries(report)
.map(([key, value]) => `${key}: ${value}`)
.join('\n');
console.log('Transfer Report:\n', reportText);
return report;
}
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
balance_transfer_id | string | Yes | The unique ID of the balance transfer to retrieve |
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the balance transfer |
created_at | string | ISO 8601 timestamp of when transfer was created |
updated_at | string | ISO 8601 timestamp of last update |
amount | integer | Amount transferred in cents |
currency | string | 3-letter ISO 4217 currency code (e.g., "USD") |
description | string | Human-readable description of the transfer |
source | string | Source account type (OPERATING_ACCOUNT or FOR_BENEFIT_OF_ACCOUNT) |
destination | string | Destination account type (FOR_BENEFIT_OF_ACCOUNT or OPERATING_ACCOUNT) |
state | string | Transfer state: SUCCEEDED, FAILED, or PENDING |
processor_type | string | Processor used for the transfer (e.g., "LITLE_V1") |
reference_id | string | Internal reference ID for tracking |
external_reference_id | string | External reference ID (if provided) |
tags | object | Custom metadata key-value pairs |
Transfer States
SUCCEEDED
The transfer completed successfully and funds have been moved between accounts.
if (transfer.state === 'SUCCEEDED') {
console.log(`Transfer ${transfer.id} completed successfully`);
// Proceed with dependent operations
await updateAccountBalances();
await recordSuccessfulTransfer(transfer);
}
FAILED
The transfer failed and no funds were moved.
if (transfer.state === 'FAILED') {
console.error(`Transfer ${transfer.id} failed`);
// Investigate failure
await investigateFailedTransfer(transfer.id);
// Notify administrators
await notifyAdmins('Balance transfer failed', transfer);
// May need to retry or take corrective action
}
PENDING
The transfer is still being processed.
if (transfer.state === 'PENDING') {
console.log(`Transfer ${transfer.id} is pending`);
// Wait and check again
await new Promise(resolve => setTimeout(resolve, 5000));
await checkTransferStatus(transfer.id);
}
Best Practices
1. Check Transfer State
Always verify the transfer state before taking action:
async function processTransferResult(transferId) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
const transfer = await response.json();
switch (transfer.state) {
case 'SUCCEEDED':
console.log('Transfer succeeded, updating records...');
await updateAccountingRecords(transfer);
break;
case 'FAILED':
console.error('Transfer failed, initiating recovery...');
await handleTransferFailure(transfer);
break;
case 'PENDING':
console.log('Transfer pending, will check again...');
await scheduleFutureCheck(transferId);
break;
default:
console.warn('Unknown transfer state:', transfer.state);
}
}
2. Handle 404 Errors
Handle cases where transfer doesn't exist:
async function safeGetTransfer(transferId) {
try {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
if (response.status === 404) {
console.error(`Transfer ${transferId} not found`);
return null;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('Error fetching transfer:', error);
throw error;
}
}
3. Use Transfer Details for Audit
Store complete transfer details for auditing:
async function auditTransfer(transferId) {
const transfer = await fetchTransferWithRetry(transferId);
const auditRecord = {
audit_timestamp: new Date().toISOString(),
transfer_id: transfer.id,
transfer_created_at: transfer.created_at,
transfer_updated_at: transfer.updated_at,
amount: transfer.amount,
currency: transfer.currency,
source: transfer.source,
destination: transfer.destination,
state: transfer.state,
description: transfer.description,
reference_id: transfer.reference_id,
processor_type: transfer.processor_type,
tags: transfer.tags
};
// Store in audit log
await storeAuditRecord('balance_transfer', auditRecord);
return auditRecord;
}
4. Monitor Transfer Timing
Track how long transfers take to complete:
async function monitorTransferTiming(transferId) {
const transfer = await fetchTransferWithRetry(transferId);
const createdAt = new Date(transfer.created_at);
const updatedAt = new Date(transfer.updated_at);
const processingTime = updatedAt - createdAt;
const metrics = {
transfer_id: transferId,
created_at: createdAt.toISOString(),
updated_at: updatedAt.toISOString(),
processing_time_ms: processingTime,
processing_time_seconds: (processingTime / 1000).toFixed(2),
state: transfer.state
};
// Track metrics
if (processingTime > 30000) { // More than 30 seconds
console.warn('Slow transfer detected:', metrics);
await alertSlowTransfer(metrics);
}
return metrics;
}
5. Cache Transfer Details
Cache frequently accessed transfers:
class TransferDetailsCache {
constructor(ttl = 60000) { // 1 minute default TTL
this.cache = new Map();
this.ttl = ttl;
}
async get(transferId) {
const cached = this.cache.get(transferId);
if (cached && (Date.now() - cached.timestamp) < this.ttl) {
console.log(`Using cached transfer ${transferId}`);
return cached.transfer;
}
console.log(`Fetching fresh transfer ${transferId}`);
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${transferId}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
const transfer = await response.json();
// Only cache completed transfers (won't change)
if (transfer.state === 'SUCCEEDED' || transfer.state === 'FAILED') {
this.cache.set(transferId, {
transfer,
timestamp: Date.now()
});
}
return transfer;
}
invalidate(transferId) {
this.cache.delete(transferId);
}
clear() {
this.cache.clear();
}
}
const transferCache = new TransferDetailsCache();
6. Store Transfer Reference
Keep transfer IDs for future reference:
async function createAndStoreTransfer(transferData) {
// Create transfer
const createResponse = await fetch(
'https://api.ahrvo.network/payments/na/balance_transfers',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(transferData)
}
);
const transfer = await createResponse.json();
// Store reference for later retrieval
await storeTransferReference({
transfer_id: transfer.id,
created_at: transfer.created_at,
amount: transfer.amount,
purpose: transferData.description,
tags: transferData.tags
});
return transfer;
}
async function retrieveStoredTransfer(transferId) {
// Get stored reference
const reference = await getTransferReference(transferId);
if (!reference) {
throw new Error(`No stored reference found for transfer ${transferId}`);
}
// Fetch current state
const transfer = await fetchTransferWithRetry(transferId);
return {
reference,
current: transfer
};
}
Common Workflows
Post-Creation Status Check
async function createAndVerifyTransfer(transferData) {
// 1. Create transfer
const createResponse = await fetch(
'https://api.ahrvo.network/payments/na/balance_transfers',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(transferData)
}
);
const transfer = await createResponse.json();
console.log('Transfer created:', transfer.id);
// 2. Wait for completion
const completedTransfer = await waitForTransferCompletion(transfer.id);
// 3. Verify final state
if (completedTransfer.state === 'SUCCEEDED') {
console.log('Transfer verified successful');
return completedTransfer;
} else {
throw new Error(`Transfer failed: ${completedTransfer.id}`);
}
}
Periodic Status Monitoring
async function monitorPendingTransfers(transferIds) {
const results = await Promise.all(
transferIds.map(async (id) => {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_transfers/${id}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);
return await response.json();
})
);
const pending = results.filter(t => t.state === 'PENDING');
const succeeded = results.filter(t => t.state === 'SUCCEEDED');
const failed = results.filter(t => t.state === 'FAILED');
console.log('Transfer Status Summary:', {
pending: pending.length,
succeeded: succeeded.length,
failed: failed.length
});
return { pending, succeeded, failed };
}