Skip to main content

List Balance Adjustments

Overview

Retrieve a list of balance adjustments for your application. View all top-ups and deductions to track balance changes, monitor adjustment history, and reconcile account activity.

Resource Access

  • User Permissions: ROLE_PARTNER or ROLE_PLATFORM credentials only
  • Endpoint: GET /balance_adjustments

Query Parameters

ParameterTypeRequiredDescription
limitintegerNoNumber of items to return (default: 10)
after_cursorstringNoReturn items created after this cursor
before_cursorstringNoReturn items created before this cursor

Example Requests

List All Balance Adjustments

curl -X GET \
'https://api.ahrvo.network/payments/na/balance_adjustments' \
-u username:password

Paginate with Limit

curl -X GET \
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=50' \
-u username:password

Use Cursor Pagination

curl -X GET \
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100&after_cursor=balance_adjustment_jfR7V18CMWaGBmRYAto8Lw' \
-u username:password

Example Response

{
"_embedded": {
"balance_adjustments": [
{
"id": "balance_adjustment_jfR7V18CMWaGBmRYAto8Lw",
"created_at": "2024-05-22T17:13:15.810963Z",
"updated_at": "2024-05-22T17:13:16.05664Z",
"amount": 10000,
"balance_entry_id": "balance_entry_4Zsrw3ccS64vjpzZmNMdUi",
"currency": "USD",
"failure_code": null,
"failure_message": null,
"description": "Weekly balance top-up",
"rail": "ACH",
"instrument_id": "PIwyL8J2KRu8qnvGF7EDeviQ",
"state": "SUCCEEDED",
"type": "TOP_UP",
"tags": {
"purpose": "weekly_topup"
},
"trace_id": "872d2e13-2e56-47b6-94a3-64ec06a1f982",
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/balance_adjustments/balance_adjustment_jfR7V18CMWaGBmRYAto8Lw"
}
}
},
{
"id": "balance_adjustment_nvc873btpDtA7KbPySdCny",
"created_at": "2024-05-22T17:13:15.810963Z",
"updated_at": "2024-05-22T17:13:16.05664Z",
"amount": 5000,
"balance_entry_id": "balance_entry_xyz789",
"currency": "USD",
"failure_code": null,
"failure_message": null,
"description": "Platform fee deduction",
"rail": "ACH",
"instrument_id": "PIwyL8J2KRu8qnvGF7EDeviQ",
"state": "SUCCEEDED",
"type": "DEDUCTION",
"tags": {
"fee_type": "platform"
},
"trace_id": "872d2e13-2e56-47b6-94a3-64ec06a1f982",
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/balance_adjustments/balance_adjustment_nvc873btpDtA7KbPySdCny"
}
}
}
]
},
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/balance_adjustments"
}
},
"page": {
"limit": 100,
"next_cursor": null,
"offset": 0
}
}

Response Fields

FieldTypeDescription
_embedded.balance_adjustmentsarrayArray of balance adjustment objects
_linksobjectNavigation links
pageobjectPagination information

Balance Adjustment Object Fields

FieldTypeDescription
idstringUnique adjustment ID
created_atstringTimestamp when created
updated_atstringTimestamp when last updated
amountintegerAdjustment amount in cents
balance_entry_idstringAssociated balance entry ID
currencystringCurrency code
failure_codestringFailure code (if failed)
failure_messagestringFailure message (if failed)
descriptionstringAdjustment description
railstringPayment rail (ACH, WIRE)
instrument_idstringPayment instrument ID
statestringState (SUCCEEDED, FAILED, PENDING)
typestringType (TOP_UP, DEDUCTION)
tagsobjectMetadata tags
trace_idstringTrace ID for tracking

Additional Information

  • Pagination: Use cursor-based pagination

    • Default limit is 10
    • Adjust limit based on needs
    • Use next_cursor for next page
    • More efficient than offset pagination
  • Filtering: Currently limited

    • No built-in filter parameters
    • Retrieve all and filter client-side
    • Use tags for categorization
    • Consider date range filtering in code
  • Access Control: Platform/Partner only

    • Only ROLE_PARTNER or ROLE_PLATFORM credentials
    • Not accessible to merchant users
    • Verify permissions before querying
  • Performance: Optimize queries

    • Request appropriate page size
    • Cache results when suitable
    • Don't retrieve more than needed

Use Cases

List Recent Adjustments

// Get the most recent balance adjustments
async function getRecentAdjustments(limit = 20) {
const response = await fetch(
`https://api.ahrvo.network/payments/na/balance_adjustments?limit=${limit}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const data = await response.json();

console.log(`Found ${data._embedded.balance_adjustments.length} recent adjustments\n`);

data._embedded.balance_adjustments.forEach(adj => {
const sign = adj.type === 'TOP_UP' ? '+' : '-';
console.log(`${adj.id}:`);
console.log(` ${sign}$${adj.amount / 100} (${adj.type})`);
console.log(` State: ${adj.state}`);
console.log(` Created: ${adj.created_at}`);
console.log(` Description: ${adj.description}`);
});

return data._embedded.balance_adjustments;
}

Calculate Total Top-Ups

// Calculate total amount topped up
async function calculateTotalTopUps() {
let allAdjustments = [];
let cursor = null;

// Fetch all pages
do {
const url = cursor
? `https://api.ahrvo.network/payments/na/balance_adjustments?limit=100&after_cursor=${cursor}`
: 'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100';

const response = await fetch(url, {
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
});

const data = await response.json();
allAdjustments.push(...data._embedded.balance_adjustments);
cursor = data.page.next_cursor;

} while (cursor);

// Calculate totals
const topUps = allAdjustments.filter(adj => adj.type === 'TOP_UP' && adj.state === 'SUCCEEDED');
const totalTopUps = topUps.reduce((sum, adj) => sum + adj.amount, 0);

console.log('=== Top-Up Summary ===');
console.log(`Total Top-Ups: ${topUps.length}`);
console.log(`Total Amount: $${totalTopUps / 100}`);
console.log(`Average: $${(totalTopUps / topUps.length / 100).toFixed(2)}`);

return {
count: topUps.length,
total: totalTopUps,
average: totalTopUps / topUps.length
};
}

Filter by Type

// Get adjustments of specific type
async function getAdjustmentsByType(type) {
const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const data = await response.json();

const filtered = data._embedded.balance_adjustments.filter(
adj => adj.type === type
);

console.log(`Found ${filtered.length} ${type} adjustments:`);

filtered.forEach(adj => {
console.log(` ${adj.id}: $${adj.amount / 100} - ${adj.description}`);
});

return filtered;
}

// Usage
await getAdjustmentsByType('TOP_UP');
await getAdjustmentsByType('DEDUCTION');

Find Failed Adjustments

// Identify and analyze failed adjustments
async function findFailedAdjustments() {
const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const data = await response.json();

const failed = data._embedded.balance_adjustments.filter(
adj => adj.state === 'FAILED'
);

if (failed.length === 0) {
console.log('✓ No failed adjustments found');
return [];
}

console.log(`⚠ Found ${failed.length} failed adjustments:\n`);

failed.forEach(adj => {
console.log(`${adj.id}:`);
console.log(` Type: ${adj.type}`);
console.log(` Amount: $${adj.amount / 100}`);
console.log(` Failure: ${adj.failure_code} - ${adj.failure_message}`);
console.log(` Created: ${adj.created_at}`);
});

return failed;
}

Generate Monthly Report

// Generate monthly adjustment report
async function monthlyAdjustmentReport(year, month) {
console.log(`=== Monthly Adjustment Report ===`);
console.log(`Period: ${year}-${month.toString().padStart(2, '0')}\n`);

// Fetch all adjustments
let allAdjustments = [];
let cursor = null;

do {
const url = cursor
? `https://api.ahrvo.network/payments/na/balance_adjustments?limit=100&after_cursor=${cursor}`
: 'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100';

const response = await fetch(url, {
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
});

const data = await response.json();
allAdjustments.push(...data._embedded.balance_adjustments);
cursor = data.page.next_cursor;

} while (cursor);

// Filter for specified month
const monthlyAdjustments = allAdjustments.filter(adj => {
const created = new Date(adj.created_at);
return created.getFullYear() === year && created.getMonth() + 1 === month;
});

// Calculate metrics
const succeeded = monthlyAdjustments.filter(a => a.state === 'SUCCEEDED');
const topUps = succeeded.filter(a => a.type === 'TOP_UP');
const deductions = succeeded.filter(a => a.type === 'DEDUCTION');

const totalTopUps = topUps.reduce((sum, a) => sum + a.amount, 0);
const totalDeductions = deductions.reduce((sum, a) => sum + a.amount, 0);
const netChange = totalTopUps - totalDeductions;

console.log('Summary:');
console.log(` Total Adjustments: ${monthlyAdjustments.length}`);
console.log(` Successful: ${succeeded.length}`);
console.log(`\nTop-Ups:`);
console.log(` Count: ${topUps.length}`);
console.log(` Total: $${totalTopUps / 100}`);
console.log(`\nDeductions:`);
console.log(` Count: ${deductions.length}`);
console.log(` Total: $${totalDeductions / 100}`);
console.log(`\nNet Change: $${netChange / 100}`);

// Breakdown by rail
const achCount = succeeded.filter(a => a.rail === 'ACH').length;
const wireCount = succeeded.filter(a => a.rail === 'WIRE').length;

console.log(`\nBy Rail:`);
console.log(` ACH: ${achCount}`);
console.log(` WIRE: ${wireCount}`);

return {
total: monthlyAdjustments.length,
succeeded: succeeded.length,
topUps: { count: topUps.length, total: totalTopUps },
deductions: { count: deductions.length, total: totalDeductions },
netChange: netChange,
byRail: { ACH: achCount, WIRE: wireCount }
};
}

// Usage
await monthlyAdjustmentReport(2024, 12);

Export to CSV

// Export balance adjustments to CSV
async function exportAdjustmentsToCSV() {
console.log('Fetching all balance adjustments...');

let allAdjustments = [];
let cursor = null;

do {
const url = cursor
? `https://api.ahrvo.network/payments/na/balance_adjustments?limit=100&after_cursor=${cursor}`
: 'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100';

const response = await fetch(url, {
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
});

const data = await response.json();
allAdjustments.push(...data._embedded.balance_adjustments);
cursor = data.page.next_cursor;

} while (cursor);

// Create CSV
let csv = 'ID,Created,Type,Amount,Currency,State,Rail,Description\n';

allAdjustments.forEach(adj => {
const amount = adj.type === 'DEDUCTION' ? -adj.amount : adj.amount;
csv += `${adj.id},${adj.created_at},${adj.type},${amount / 100},${adj.currency},${adj.state},${adj.rail},"${adj.description}"\n`;
});

console.log(`✓ Exported ${allAdjustments.length} adjustments to CSV`);

return csv;
}

Track Pending Adjustments

// Monitor pending adjustments
async function trackPendingAdjustments() {
const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const data = await response.json();

const pending = data._embedded.balance_adjustments.filter(
adj => adj.state === 'PENDING'
);

if (pending.length === 0) {
console.log('✓ No pending adjustments');
return [];
}

console.log(`Found ${pending.length} pending adjustments:\n`);

pending.forEach(adj => {
const created = new Date(adj.created_at);
const hoursAgo = Math.floor((Date.now() - created.getTime()) / (1000 * 60 * 60));

console.log(`${adj.id}:`);
console.log(` Type: ${adj.type}`);
console.log(` Amount: $${adj.amount / 100}`);
console.log(` Rail: ${adj.rail}`);
console.log(` Created: ${hoursAgo} hours ago`);

if (adj.rail === 'ACH' && hoursAgo > 72) {
console.log(` ⚠ WARNING: ACH pending for over 72 hours`);
} else if (adj.rail === 'WIRE' && hoursAgo > 24) {
console.log(` ⚠ WARNING: WIRE pending for over 24 hours`);
}
});

return pending;
}

Best Practices

  • Paginate Efficiently: Don't fetch everything

    // Good - use appropriate limit
    const data = await fetchAdjustments({ limit: 50 });

    // Bad - fetch all unnecessarily
    const all = await fetchAllAdjustments(); // Could be thousands
  • Cache When Appropriate: Reduce API calls

    const cache = {
    data: null,
    timestamp: null,
    ttl: 5 * 60 * 1000 // 5 minutes
    };

    async function getCachedAdjustments() {
    if (cache.data && Date.now() - cache.timestamp < cache.ttl) {
    return cache.data;
    }

    const data = await fetchAdjustments();
    cache.data = data;
    cache.timestamp = Date.now();

    return data;
    }
  • Filter Client-Side: No server-side filters

    • Fetch with reasonable limit
    • Filter by type, state, date in code
    • Cache filtered results
  • Monitor Failed Adjustments: Regular checks

    • Check for failed adjustments daily
    • Investigate failure reasons
    • Retry or escalate as needed
  • Track Net Changes: Balance reconciliation

    • Sum top-ups and deductions
    • Calculate net balance change
    • Compare with balance API
    • Identify discrepancies

Common Workflows

Daily Adjustment Summary

// Generate daily summary of adjustments
async function dailyAdjustmentSummary() {
const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const data = await response.json();

// Filter for today
const today = new Date();
today.setHours(0, 0, 0, 0);

const todaysAdjustments = data._embedded.balance_adjustments.filter(adj => {
const created = new Date(adj.created_at);
return created >= today;
});

console.log('=== Daily Adjustment Summary ===');
console.log(`Date: ${today.toDateString()}\n`);

const succeeded = todaysAdjustments.filter(a => a.state === 'SUCCEEDED');
const pending = todaysAdjustments.filter(a => a.state === 'PENDING');
const failed = todaysAdjustments.filter(a => a.state === 'FAILED');

console.log(`Total: ${todaysAdjustments.length}`);
console.log(` Succeeded: ${succeeded.length}`);
console.log(` Pending: ${pending.length}`);
console.log(` Failed: ${failed.length}`);

// Calculate amounts
const topUps = succeeded.filter(a => a.type === 'TOP_UP');
const deductions = succeeded.filter(a => a.type === 'DEDUCTION');

const totalTopUp = topUps.reduce((sum, a) => sum + a.amount, 0);
const totalDeduction = deductions.reduce((sum, a) => sum + a.amount, 0);

console.log(`\nTop-Ups: $${totalTopUp / 100} (${topUps.length})`);
console.log(`Deductions: $${totalDeduction / 100} (${deductions.length})`);
console.log(`Net: $${(totalTopUp - totalDeduction) / 100}`);

return {
total: todaysAdjustments.length,
succeeded: succeeded.length,
pending: pending.length,
failed: failed.length,
totalTopUp,
totalDeduction
};
}

Reconciliation Report

// Reconcile adjustments with balance
async function reconcileAdjustments() {
console.log('=== Balance Reconciliation ===\n');

// Fetch all adjustments
let allAdjustments = [];
let cursor = null;

do {
const url = cursor
? `https://api.ahrvo.network/payments/na/balance_adjustments?limit=100&after_cursor=${cursor}`
: 'https://api.ahrvo.network/payments/na/balance_adjustments?limit=100';

const response = await fetch(url, {
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
});

const data = await response.json();
allAdjustments.push(...data._embedded.balance_adjustments);
cursor = data.page.next_cursor;

} while (cursor);

// Calculate total adjustments
const succeeded = allAdjustments.filter(a => a.state === 'SUCCEEDED');

const totalTopUps = succeeded
.filter(a => a.type === 'TOP_UP')
.reduce((sum, a) => sum + a.amount, 0);

const totalDeductions = succeeded
.filter(a => a.type === 'DEDUCTION')
.reduce((sum, a) => sum + a.amount, 0);

const netAdjustments = totalTopUps - totalDeductions;

console.log('Adjustment History:');
console.log(` Total Top-Ups: $${totalTopUps / 100}`);
console.log(` Total Deductions: $${totalDeductions / 100}`);
console.log(` Net Adjustments: $${netAdjustments / 100}`);

return {
totalTopUps,
totalDeductions,
netAdjustments
};
}

Security Considerations

  • Access Control: Platform/Partner only

    • Only specific roles can list adjustments
    • Verify credentials have proper permissions
    • Not accessible to merchant users
  • Sensitive Data: Handle carefully

    • Adjustments contain financial data
    • Don't expose to unauthorized users
    • Log access to adjustment data
    • Implement audit trails
  • Rate Limiting: Respect limits

    • Don't poll excessively
    • Cache results appropriately
    • Use webhooks if available

Error Responses

Unauthorized

{
"_embedded": {
"errors": [
{
"message": "Authentication credentials are invalid"
}
]
}
}

Forbidden

{
"_embedded": {
"errors": [
{
"message": "User does not have permission to perform this action"
}
]
}
}

Troubleshooting

No Results Returned

  • Verify you have ROLE_PARTNER or ROLE_PLATFORM credentials
  • Check application has balance adjustments
  • Try without pagination parameters first
  • Verify environment (staging vs production)

Pagination Not Working

  • Verify cursor value is valid
  • Ensure cursor is from previous response
  • Check cursor hasn't expired
  • Start from beginning if issues

Missing Recent Adjustments

  • Results are eventually consistent
  • New adjustments may take moments to appear
  • Refresh and try again
  • Check creation timestamp
  • POST /balance_adjustments: Create new adjustment
  • GET /balances: Check current balance
  • GET /balance_entries: View balance ledger
  • GET /payment_instruments/{id}: View payment instrument