# Balance and Payment Preference Hooks

https://dev.wisecp.com/es/balance-hooks

The four hooks over the wallet, balance adjustments and the auto-payment chain.

## Overview

Money enters or leaves a customer wallet four ways: a top-up request, credit from an invoice, a manual adjustment by an administrator, and a change in the auto-payment chain.

Currency is the trap here: a balance is kept in its own currency while an invoice may be in another. Check which one an amount is in before carrying it anywhere.

## Reference

### Following the auto-payment chain

actionuser.autopay_changed

`AccountCards` head of the chain

Runs when the auto-payment chain of an account changes.

Parameters 2

$uidintThe owner of the account.

$autopayCtxarrayThe current head of the chain. When the chain empties this **arrives empty**: the account has no card left to pay with and renewals will fail.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:user.autopay_changed', 10, function ($uid, $autopayCtx) {
    // An empty chain means renewals will fail.
    if (!($autopayCtx['backup_card'] ?? null)) Acme::warnNoCard($uid);
});
```

### Following credit reaching the balance

actionuser.balance_credited

`Invoices` after conversion

Runs when credit from an invoice reaches a customer balance.

Parameters 4

$user_idintThe customer whose balance grew.

$amountfloatThe amount credited, **in the balance currency** and after conversion. It need not match the invoice total: the invoice may be in another currency.

$currencyintThe balance currency.

$invoicearrayThe source invoice.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:user.balance_credited', 10, function ($user_id, $amount, $currency, $invoice) {
    // The amount is in the balance currency: do not mix it with the invoice one.
    Acme::ledgerCredit($user_id, $amount, $currency);
});
```

### Following a balance adjustment

actionuser.credit_adjusted

`AdminUsers` two directions

Runs when an administrator adjusts a balance by hand.

Parameters 5

$user_idintThe customer whose balance moved.

$typestringWhich way: `up` credit, `down` debit.

$amountfloatThe adjustment amount.

$new_balancefloatThe balance after the change.

$cidintThe balance currency.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:user.credit_adjusted', 10,
    function ($user_id, $type, $amount, $new_balance, $cid) {
        Acme::ledgerAdjust($user_id, $type, $amount, $new_balance);
    });
```

### Following a top-up request

actionuser.funds_added

`AccountBalance` the net amount

Runs when a customer asks to top up their wallet.

Parameters 3

$uidintThe owner of the wallet.

$amountfloatThe **net** amount asked for. Tax and gateway commission are **not included**: what the customer pays is higher. Do not book this number as the amount paid.

$fundsCtxarrayContext: which surface the request came from and the minimum.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:user.funds_added', 10, function ($uid, $amount, $fundsCtx) {
    // The NET amount: tax and commission are not in it.
    Acme::noteTopupIntent($uid, $amount);
});
```

## Pitfalls

> **The balance amount is not the invoice amount**
> 
> What reaches a balance arrives **in the balance currency** and after conversion. It need not equal the invoice total; treating them as one number produces a gap in your books.

> **The top-up amount is the net amount**
> 
> The amount in the top-up hook is **net**: tax and gateway commission are not in it. What the customer pays is higher, so do not record this number as the sum collected.

## Related Articles

- [Customer Account Hooks](https://dev.wisecp.com/en/customer-account-hooks)
- [Invoice Lifecycle Hooks](https://dev.wisecp.com/en/invoice-lifecycle-hooks)
- [How Hooks Work](https://dev.wisecp.com/en/how-hooks-work)
