> For the complete documentation index, see [llms.txt](https://tgiann.gitbook.io/tgiann/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tgiann.gitbook.io/tgiann/scripts/tgiann-bank/hooks.md).

# Hooks

Event hooks let other resources react to bank actions, cancel them or extend them without touching the bank code.

{% hint style="danger" %}
All hooks work server-side only.
{% endhint %}

{% hint style="success" %}
Same pattern as the tgiann-inventory hooks. Pre events run before the action and can cancel it by returning `false`. Post events run after the change was written, their return value is ignored.
{% endhint %}

## RegisterHook <a href="#registerhook" id="registerhook"></a>

```lua
local hookId = exports["tgiann-bank"]:RegisterHook(eventName, function(payload) end, options)
```

* eventName: `string`
* payload: `table`
* options?: `table`
  * print?: `boolean`
    * Print to the console when triggering the event.
  * ibanFilter?: `{ [string]: true }`
    * The event only triggers when `payload.iban` or `payload.targetIban` is one of the keys.

Return:

* hookId: `number`

{% hint style="info" %}
Hooks of a resource are removed automatically when that resource stops. Register them again in `onResourceStart` of the bank if your resource may outlive a bank restart.
{% endhint %}

***

## Pre events

### transfer

Triggered before money leaves an account (ATM / phone transfer, paying a money request, `Transfer` and `TransferMoney` exports). Returning `false` cancels the transfer.

* Payload: `table`
  * iban: `string` source account
  * targetIban: `string`
  * citizenid?: `string` acting character, nil for the `TransferMoney` export
  * amount: `number`
  * note?: `string`

**Example**

```lua
-- the police account may not send more than $1,000,000 at once
exports["tgiann-bank"]:RegisterHook("transfer", function(payload)
    if payload.amount > 1000000 then return false end
end, { ibanFilter = { ["P000LS120000TG001234"] = true } })
```

***

### deposit

Triggered before cash is deposited at an ATM. Returning `false` cancels it.

* Payload: `table`
  * iban: `string`
  * citizenid: `string`
  * amount: `number`

**Example**

```lua
-- dirty money can not be deposited
exports["tgiann-bank"]:RegisterHook("deposit", function(payload)
    if exports["my-laundry"]:HasDirtyMoney(payload.citizenid) then return false end
end)
```

***

### withdraw

Triggered before money is withdrawn at an ATM. Returning `false` cancels it.

* Payload: `table`
  * iban: `string`
  * citizenid: `string`
  * amount: `number`

**Example**

```lua
-- wanted players can not take cash out
exports["tgiann-bank"]:RegisterHook("withdraw", function(payload)
    if exports["my-mdt"]:IsWanted(payload.citizenid) then return false end
end)
```

***

### askMoney

Triggered before a money request is created. Returning `false` cancels it.

* Payload: `table`
  * iban: `string` account that should pay
  * targetIban: `string` account that asked
  * citizenid: `string` character who asked
  * amount: `number`

**Example**

```lua
-- nobody can request money from job accounts
exports["tgiann-bank"]:RegisterHook("askMoney", function(payload)
    local payer = exports["tgiann-bank"]:GetAccountData(payload.iban)
    if payer and payer.type == "job" then return false end
end)
```

***

## Post events

### balanceChanged

* Payload: `table`
  * iban: `string`
  * balance: `number` new balance
  * delta: `number` positive on income, negative on outcome

**Example**

```lua
-- warn the owner when a business account drops below $1,000
exports["tgiann-bank"]:RegisterHook("balanceChanged", function(payload)
    if payload.delta < 0 and payload.balance < 1000 then
        local account = exports["tgiann-bank"]:GetAccountData(payload.iban)
        if account and account.type == "ownable" then
            print(("%s is almost empty"):format(account.name))
        end
    end
end)
```

***

### historyAdded

* Payload: `table`
  * iban: `string`
  * history: `table`
    * id, accountid: `number`
    * type: `"deposit" | "withdraw" | "income" | "outcome"`
    * amount: `number`
    * timestamp: `number`
    * targetIban?: `string`
    * targetName?: `string` readable name of the other account
    * name?, note?: `string` text in the server language
    * i18n?: `{ name?: table<string, string>, note?: table<string, string> }` one text per language when a script sent translations
    * actor?: `string` citizen id of the player who made the movement
    * channel: `string` history channel (`atm`, `transfer`, `invoice`, `system` or a custom one)
    * location?: `string` ATM label
    * fee: `number` government tax and ATM company fee
    * balance: `number` account balance right after the movement

**Example**

```lua
-- mirror every movement into your own log
exports["tgiann-bank"]:RegisterHook("historyAdded", function(payload)
    local h = payload.history
    print(("%s | %s | %s | $%s | balance $%s"):format(payload.iban, h.channel, h.type, h.amount, h.balance))
end)
```

***

### notificationAdded / notificationRemoved

A money request or bill landed on an account, or was resolved.

* Payload (`notificationAdded`): `table`
  * iban: `string`
  * notification: `table` `{ id, iban, targetIban, type = "wants" | "ask" | "bill", amount, targetName, timestamp }`
* Payload (`notificationRemoved`): `table`
  * iban: `string`
  * id: `number`

**Example**

```lua
-- push a phone notification when someone asks the account for money
exports["tgiann-bank"]:RegisterHook("notificationAdded", function(payload)
    local n = payload.notification
    if n.type == "wants" then
        print(("%s asks $%s from %s"):format(n.targetName or n.targetIban, n.amount, payload.iban))
    end
end)
```

***

### requestResolved

* Payload: `table`
  * iban: `string` account that asked
  * targetIban: `string` account that was asked
  * amount: `number`
  * action: `"paid" | "declined" | "cancelled"`

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("requestResolved", function(payload)
    if payload.action == "declined" then
        print(("%s declined the $%s request of %s"):format(payload.targetIban, payload.amount, payload.iban))
    end
end)
```

***

### accountAdded / accountRemoved

An account became visible or invisible to a character (created, shared, job / gang / business membership changed).

* Payload (`accountAdded`): `table`
  * citizenid: `string`
  * iban: `string`
  * account: `table` account data built for that character
  * isNew: `boolean` the account was just created
* Payload (`accountRemoved`): `table`
  * citizenid: `string`
  * iban: `string`

**Example**

```lua
-- keep your own cache of who can see which account
exports["tgiann-bank"]:RegisterHook("accountAdded", function(payload)
    myCache[payload.citizenid] = myCache[payload.citizenid] or {}
    myCache[payload.citizenid][payload.iban] = true
end)

exports["tgiann-bank"]:RegisterHook("accountRemoved", function(payload)
    if myCache[payload.citizenid] then myCache[payload.citizenid][payload.iban] = nil end
end)
```

***

### accountDeleted

* Payload: `table`
  * iban: `string`
  * owner: `string`

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("accountDeleted", function(payload)
    exports["my-billing"]:CancelStandingOrders(payload.iban)
end)
```

***

### accountRenamed

* Payload: `table`
  * iban: `string`
  * name: `string`

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("accountRenamed", function(payload)
    print(("%s is now called %s"):format(payload.iban, payload.name))
end)
```

***

### accountColorChanged

* Payload: `table`
  * iban: `string`
  * cardColor?: `string` `#RRGGBB`, nil when the default card was restored

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("accountColorChanged", function(payload)
    print(("%s card color: %s"):format(payload.iban, payload.cardColor or "default"))
end)
```

***

### accountFrozenChanged

* Payload: `table`
  * iban: `string`
  * frozen: `boolean`

**Example**

```lua
-- tell the owner when an admin freezes the account
exports["tgiann-bank"]:RegisterHook("accountFrozenChanged", function(payload)
    local account = exports["tgiann-bank"]:GetAccountData(payload.iban)
    if account and payload.frozen then
        print(("%s owned by %s was frozen"):format(payload.iban, account.owner))
    end
end)
```

***

### sharedUserAdded / sharedUserRemoved / sharedUserPermChanged

* Payload (`sharedUserAdded`): `table`
  * iban: `string`
  * user: `table` `{ citizenid, name, perm }`
* Payload (`sharedUserRemoved`): `table`
  * iban: `string`
  * citizenid: `string`
* Payload (`sharedUserPermChanged`): `table`
  * iban: `string`
  * citizenid: `string`
  * perm: `"can_withdraw" | "can_deposit" | "can_transfer" | "can_ask"`
  * value: `boolean`

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("sharedUserAdded", function(payload)
    print(("%s joined %s"):format(payload.user.name, payload.iban))
end)

exports["tgiann-bank"]:RegisterHook("sharedUserPermChanged", function(payload)
    print(("%s on %s: %s = %s"):format(payload.citizenid, payload.iban, payload.perm, tostring(payload.value)))
end)
```

***

### atmBalanceChanged

The cash inside an ATM changed (deposit, withdraw, money transport job).

* Payload: `table`
  * atmId: `number`
  * keyName: `string`
  * balance: `number`
  * delta: `number`

**Example**

```lua
exports["tgiann-bank"]:RegisterHook("atmBalanceChanged", function(payload)
    if payload.balance < 5000 then
        print(("ATM %s is almost empty"):format(payload.atmId))
    end
end)
```

## RemoveHooks <a href="#removehooks" id="removehooks"></a>

Removes a hook created by the invoking resource with the specified id.\
If no id is specified then all hooks registered by the resource are removed.

```lua
exports["tgiann-bank"]:RemoveHooks(id)
```

* id?: `number`
