Skip to main content

Create Balance Adjustment

Overview

Create a Balance Adjustment to increase (top-up) or decrease (deduction) your account balance for payouts. Balance adjustments allow you to manage your payout account balance by adding funds via ACH or wire transfer, or deducting funds as needed.

Resource Access

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

Arguments

ParameterTypeRequiredDescription
amountintegerYesAmount of adjustment in cents
currencystringYes3-letter ISO 4217 currency code (e.g., USD)
instrument_idstringYesID of the payment instrument
typestringYesType of adjustment (TOP_UP, DEDUCTION)
descriptionstringNoDescription of the balance adjustment
processorstringNoProcessor to use for the adjustment
railstringNoPayment rail (ACH, WIRE)
tagsobjectNoKey-value metadata pairs

Adjustment Types

TypeDescription
TOP_UPAdd funds to account balance (credit)
DEDUCTIONRemove funds from account balance (debit)

Payment Rails

RailDescription
ACHAutomated Clearing House (standard, 1-3 business days)
WIREWire transfer (faster, same or next business day)

Example Requests

Basic Top-Up via ACH

curl -X POST \
'https://api.ahrvo.network/payments/na/balance_adjustments' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"amount": 10000,
"currency": "USD",
"description": "Weekly balance top-up",
"instrument_id": "PI4Ppf8rxWYapuEqQr3u6efi",
"processor": "DUMMY_V1",
"rail": "ACH",
"type": "TOP_UP",
"tags": {
"purpose": "weekly_topup"
}
}'

Top-Up via Wire Transfer

curl -X POST \
'https://api.ahrvo.network/payments/na/balance_adjustments' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"amount": 50000,
"currency": "USD",
"description": "Urgent balance top-up",
"instrument_id": "PI4Ppf8rxWYapuEqQr3u6efi",
"processor": "DUMMY_V1",
"rail": "WIRE",
"type": "TOP_UP",
"tags": {
"urgency": "high",
"purpose": "emergency_funds"
}
}'

Balance Deduction

curl -X POST \
'https://api.ahrvo.network/payments/na/balance_adjustments' \
-u username:password \
-H 'Content-Type: application/json' \
-d '{
"amount": 5000,
"currency": "USD",
"description": "Fee correction deduction",
"instrument_id": "PI4Ppf8rxWYapuEqQr3u6efi",
"processor": "DUMMY_V1",
"rail": "ACH",
"type": "DEDUCTION",
"tags": {
"reason": "fee_correction"
}
}'

Example Response

{
"id": "balance_adjustment_cjWuGyhvBxEmgcUmxCzpvc",
"created_at": "2025-09-01T15:07:20.985846Z",
"updated_at": "2025-09-01T15:07:21.912828Z",
"amount": 10000,
"balance_entry_id": "balance_entry_corsu3cQg1TBLJJbmMyK3o",
"currency": "USD",
"description": "Weekly balance top-up",
"failure_code": null,
"failure_message": null,
"instrument_id": "PI4Ppf8rxWYapuEqQr3u6efi",
"rail": "ACH",
"state": "SUCCEEDED",
"tags": {
"purpose": "weekly_topup"
},
"top_up_config_id": null,
"trace_id": "7b44bd4e-31b0-4f34-afea-1d13526654b3",
"type": "TOP_UP",
"_links": {
"self": {
"href": "https://api.ahrvo.network/payments/na/balance_adjustments/balance_adjustment_cjWuGyhvBxEmgcUmxCzpvc"
}
}
}

Response Fields

FieldTypeDescription
idstringUnique balance adjustment ID
created_atstringTimestamp when created
updated_atstringTimestamp when last updated
amountintegerAdjustment amount in cents
balance_entry_idstringID of associated balance entry
currencystringCurrency code
descriptionstringAdjustment description
failure_codestringFailure code (if failed)
failure_messagestringFailure message (if failed)
instrument_idstringPayment instrument ID
railstringPayment rail used (ACH, WIRE)
statestringState (SUCCEEDED, FAILED, PENDING)
tagsobjectMetadata tags
top_up_config_idstringAuto top-up configuration ID (if applicable)
trace_idstringTrace ID for tracking
typestringAdjustment type (TOP_UP, DEDUCTION)

Adjustment States

StateDescription
SUCCEEDEDAdjustment completed successfully
FAILEDAdjustment failed
PENDINGAdjustment in progress

Additional Information

  • Balance Entry Creation: Each adjustment creates a balance entry

    • balance_entry_id links to balance ledger
    • Balance entries track all balance changes
    • Use for reconciliation and reporting
  • Top-Up vs Deduction: Direction matters

    • TOP_UP: Adds funds to your balance (credit)
    • DEDUCTION: Removes funds from your balance (debit)
    • Amount is always positive (direction determined by type)
  • Payment Rails: Speed and cost differences

    • ACH: Standard processing (1-3 business days), lower cost
    • WIRE: Expedited processing (same/next day), higher fees
    • Choose based on urgency and cost considerations
  • Payment Instrument: Bank account required

    • Must be a verified bank account
    • Used for ACH pulls/pushes
    • Verify account before first use
  • Processing Time: Varies by rail

    • ACH: 1-3 business days to settle
    • WIRE: Same or next business day
    • State changes from PENDING to SUCCEEDED when complete
  • Use Cases: When to adjust balance

    • Top-Up: Ensure sufficient funds for payouts
    • Top-Up: Prepare for high-volume payout periods
    • Deduction: Correct overfunded accounts
    • Deduction: Platform fee collection

Use Cases

Weekly Top-Up for Payouts

// Automatically top up balance for upcoming payouts
async function weeklyBalanceTopUp(instrumentId, amount) {
console.log('Creating weekly balance top-up...');

const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: amount,
currency: 'USD',
description: `Weekly top-up for ${new Date().toISOString().split('T')[0]}`,
instrument_id: instrumentId,
rail: 'ACH',
type: 'TOP_UP',
tags: {
schedule: 'weekly',
automated: 'true',
week_of: new Date().toISOString().split('T')[0]
}
})
}
);

const adjustment = await response.json();

console.log('✓ Balance top-up created');
console.log(` Amount: $${adjustment.amount / 100}`);
console.log(` State: ${adjustment.state}`);
console.log(` Rail: ${adjustment.rail}`);
console.log(` Balance Entry: ${adjustment.balance_entry_id}`);

return adjustment;
}

Urgent Wire Top-Up

// Urgent top-up using wire transfer for same-day processing
async function urgentWireTopUp(instrumentId, amount, reason) {
console.log('Creating urgent wire top-up...');

const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: amount,
currency: 'USD',
description: `Urgent wire top-up - ${reason}`,
instrument_id: instrumentId,
rail: 'WIRE',
type: 'TOP_UP',
tags: {
urgency: 'high',
reason: reason,
requested_by: 'finance_team'
}
})
}
);

const adjustment = await response.json();

console.log('✓ Urgent wire top-up initiated');
console.log(` Amount: $${adjustment.amount / 100}`);
console.log(` Expected: Same or next business day`);
console.log(` Reason: ${reason}`);

return adjustment;
}

// Usage
await urgentWireTopUp(
'PI4Ppf8rxWYapuEqQr3u6efi',
100000, // $1,000.00
'High volume payout period'
);

Smart Balance Top-Up

// Check balance and top up if below threshold
async function smartBalanceTopUp(instrumentId, threshold, topUpAmount) {
console.log('Checking balance...');

// Fetch current balance
const balanceResponse = await fetch(
'https://api.ahrvo.network/payments/na/balances',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const balances = await balanceResponse.json();
const currentBalance = balances.payouts_balance || 0;

console.log(`Current balance: $${currentBalance / 100}`);
console.log(`Threshold: $${threshold / 100}`);

if (currentBalance < threshold) {
console.log('Balance below threshold - initiating top-up...');

const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: topUpAmount,
currency: 'USD',
description: 'Automatic balance top-up (threshold triggered)',
instrument_id: instrumentId,
rail: 'ACH',
type: 'TOP_UP',
tags: {
automated: 'true',
trigger: 'threshold',
previous_balance: currentBalance.toString()
}
})
}
);

const adjustment = await response.json();

console.log('✓ Top-up created');
console.log(` Top-up amount: $${topUpAmount / 100}`);
console.log(` New balance (pending): $${(currentBalance + topUpAmount) / 100}`);

return adjustment;
} else {
console.log('✓ Balance sufficient - no top-up needed');
return null;
}
}

// Usage
await smartBalanceTopUp(
'PI4Ppf8rxWYapuEqQr3u6efi',
50000, // $500.00 threshold
100000 // $1,000.00 top-up amount
);

Balance Deduction for Fee Collection

// Deduct platform fees from balance
async function collectPlatformFees(instrumentId, feeAmount, period) {
console.log(`Collecting platform fees for ${period}...`);

const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: feeAmount,
currency: 'USD',
description: `Platform fees - ${period}`,
instrument_id: instrumentId,
rail: 'ACH',
type: 'DEDUCTION',
tags: {
fee_type: 'platform',
period: period,
collected_at: new Date().toISOString()
}
})
}
);

const adjustment = await response.json();

console.log('✓ Platform fees deducted');
console.log(` Amount: $${adjustment.amount / 100}`);
console.log(` Period: ${period}`);
console.log(` Balance Entry: ${adjustment.balance_entry_id}`);

return adjustment;
}

// Usage
await collectPlatformFees(
'PI4Ppf8rxWYapuEqQr3u6efi',
25000, // $250.00 in fees
'December 2024'
);

Batch Balance Adjustments

// Create multiple balance adjustments in batch
async function batchBalanceAdjustments(adjustments) {
console.log(`Processing ${adjustments.length} balance adjustments...\n`);

const results = {
successful: [],
failed: []
};

for (const adj of adjustments) {
try {
const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(adj)
}
);

const adjustment = await response.json();

results.successful.push({
id: adjustment.id,
type: adjustment.type,
amount: adjustment.amount
});

console.log(`${adjustment.type} - $${adjustment.amount / 100}`);

} catch (error) {
results.failed.push({
adjustment: adj,
error: error.message
});

console.log(`✗ Failed: ${error.message}`);
}

// Rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}

console.log(`\n=== Batch Complete ===`);
console.log(`Successful: ${results.successful.length}`);
console.log(`Failed: ${results.failed.length}`);

return results;
}

// Usage
await batchBalanceAdjustments([
{
amount: 50000,
currency: 'USD',
description: 'Merchant A payout funding',
instrument_id: 'PI4Ppf8rxWYapuEqQr3u6efi',
rail: 'ACH',
type: 'TOP_UP'
},
{
amount: 30000,
currency: 'USD',
description: 'Merchant B payout funding',
instrument_id: 'PI4Ppf8rxWYapuEqQr3u6efi',
rail: 'ACH',
type: 'TOP_UP'
}
]);

Monitor Adjustment Status

// Create adjustment and monitor until completion
async function createAndMonitorAdjustment(adjustmentData) {
console.log('Creating balance adjustment...');

const response = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify(adjustmentData)
}
);

let adjustment = await response.json();

console.log('✓ Adjustment created');
console.log(` ID: ${adjustment.id}`);
console.log(` Initial state: ${adjustment.state}`);

// Monitor status if pending
if (adjustment.state === 'PENDING') {
console.log('\nMonitoring status...');

let attempts = 0;
const maxAttempts = 20;

while (adjustment.state === 'PENDING' && attempts < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, 5000));

const statusResponse = await fetch(
`https://api.ahrvo.network/payments/na/balance_adjustments/${adjustment.id}`,
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

adjustment = await statusResponse.json();
attempts++;

console.log(` Check ${attempts}: ${adjustment.state}`);
}
}

if (adjustment.state === 'SUCCEEDED') {
console.log('\n✓ Adjustment completed successfully');
} else if (adjustment.state === 'FAILED') {
console.log('\n✗ Adjustment failed');
console.log(` Failure: ${adjustment.failure_message}`);
}

return adjustment;
}

Best Practices

  • Verify Instrument: Ensure payment instrument is valid

    // Check instrument before creating adjustment
    const instrument = await fetchPaymentInstrument(instrumentId);
    if (instrument.type === 'BANK_ACCOUNT' && instrument.verified) {
    await createBalanceAdjustment(instrumentId, amount);
    }
  • Choose Right Rail: Based on urgency

    • Use ACH for standard, cost-effective top-ups
    • Use WIRE for urgent, time-sensitive needs
    • Consider wire fees vs urgency trade-off
  • Monitor Balance: Proactive management

    • Set up alerts for low balance
    • Automate top-ups at thresholds
    • Plan for high-volume periods
  • Document Adjustments: Clear descriptions

    {
    description: "Weekly payout funding - Week of Dec 10, 2024",
    tags: {
    purpose: "payout_funding",
    week: "2024-12-10",
    scheduled: "true"
    }
    }
  • Track with Tags: Comprehensive metadata

    • Purpose of adjustment
    • Automated vs manual
    • Business context
    • Approval references
  • Handle Errors: Robust error handling

    try {
    const adjustment = await createBalanceAdjustment(data);
    if (adjustment.state === 'FAILED') {
    console.error('Adjustment failed:', adjustment.failure_message);
    }
    } catch (error) {
    console.error('API error:', error);
    }

Common Workflows

Pre-Payout Balance Check

// Ensure sufficient balance before creating payouts
async function ensureSufficientBalance(requiredAmount, instrumentId) {
console.log('=== Pre-Payout Balance Check ===\n');

// Step 1: Check current balance
console.log('Step 1: Checking current balance...');
const balanceResponse = await fetch(
'https://api.ahrvo.network/payments/na/balances',
{
headers: {
'Authorization': 'Basic ' + btoa('username:password')
}
}
);

const balances = await balanceResponse.json();
const currentBalance = balances.payouts_balance || 0;

console.log(` Current: $${currentBalance / 100}`);
console.log(` Required: $${requiredAmount / 100}`);

// Step 2: Top up if needed
if (currentBalance < requiredAmount) {
const shortfall = requiredAmount - currentBalance;
const topUpAmount = shortfall + 10000; // Add $100 buffer

console.log(`\nStep 2: Insufficient balance - topping up $${topUpAmount / 100}...`);

const adjustment = await fetch(
'https://api.ahrvo.network/payments/na/balance_adjustments',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: topUpAmount,
currency: 'USD',
description: 'Pre-payout balance top-up',
instrument_id: instrumentId,
rail: 'ACH',
type: 'TOP_UP',
tags: {
reason: 'payout_preparation',
shortfall: shortfall.toString()
}
})
}
).then(r => r.json());

console.log('✓ Top-up initiated');
console.log(` Adjustment ID: ${adjustment.id}`);

return { sufficient: false, topUpCreated: true, adjustment };
} else {
console.log('\n✓ Sufficient balance available');
return { sufficient: true, topUpCreated: false };
}
}

Security Considerations

  • Access Control: Platform/Partner only

    • Only ROLE_PARTNER or ROLE_PLATFORM can create adjustments
    • Not available to merchant users
    • Verify credentials before use
  • Audit Trail: Track all adjustments

    • Log who created adjustment
    • Log when and why
    • Use tags for detailed tracking
    • Review adjustment history regularly
  • Amount Validation: Prevent errors

    • Validate amount is reasonable
    • Check for typos (extra zeros)
    • Confirm deductions don't overdraw
    • Implement approval workflows for large amounts
  • Instrument Verification: Use verified accounts

    • Only use verified bank accounts
    • Verify account ownership
    • Validate routing/account numbers

Error Responses

Unauthorized

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

Forbidden

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

Invalid Parameters

{
"status": 400,
"message": "Invalid request parameters",
"details": "Amount must be a positive integer"
}

Troubleshooting

Adjustment Fails - Insufficient Funds (Deduction)

  • Check current balance before deduction
  • Deduction amount exceeds available balance
  • Reduce deduction amount
  • Top up first if needed

Adjustment Stuck in PENDING

  • ACH takes 1-3 business days
  • Wire takes 1 business day
  • Check during business hours
  • Contact support if delayed >3 days

Invalid Instrument

  • Payment instrument not found
  • Instrument not verified
  • Instrument not a bank account
  • Verify instrument ID and type
  • GET /balance_adjustments: List all balance adjustments
  • GET /balances: Check current balance
  • GET /payment_instruments/{id}: Verify payment instrument
  • POST /balance_transfers: Transfer between balances