# Hooks

## Overview

Hooks let you run custom validation logic before or after banking actions. Use them to enforce custom policies (e.g. max balance per character), blacklist checks, or external integration across deposits, withdrawals, transfers, society money, loans, cards, and ATM flows.

## RegisterHook

If you are writing code **inside `tgg-banking`** (for example in `server/custom/*.lua`), use the built-in function:

```lua
RegisterHook(eventName, callback)
```

If you are writing code from an **external resource**, use export:

```lua
---@param eventName string
---@param callback fun(source: number, payload: table, result?: table): (boolean|table|nil)
---@return number | nil
exports['tgg-banking']:RegisterHook(eventName, callback)
```

`registerHook` (lowercase) is also available as an alias. Both registration methods are supported. Use the variant that matches where your script lives.

## Supported events

### Money actions (deposit, withdraw, transfer)

* `beforeDeposit`
* `afterDeposit`
* `beforeWithdraw`
* `afterWithdraw`
* `beforeTransfer`
* `afterTransfer`

### Society money exports

* `beforeAddSocietyMoney`
* `afterAddSocietyMoney`
* `beforeRemoveSocietyMoney`
* `afterRemoveSocietyMoney`

### Loan lifecycle

* `beforeLoanApply`
* `afterLoanApply`
* `beforeLoanPayment`
* `afterLoanPayment`
* `beforeLoanPayoff`
* `afterLoanPayoff`
* `beforeLoanApplyPayment`
* `afterLoanApplyPayment`

### Card lifecycle

* `beforeCardCreate`
* `afterCardCreate`
* `beforeCardFreeze`
* `afterCardFreeze`
* `beforeCardUnfreeze`
* `afterCardUnfreeze`
* `beforeCardTerminate`
* `afterCardTerminate`
* `beforeCardUpdateLimits`
* `afterCardUpdateLimits`

### ATM

* `beforeAtmAuthorize`
* `afterAtmAuthorize`
* `beforeAtmPinChange`
* `afterAtmPinChange`

## Blocking behavior (before\* hooks only)

* `return false` -> blocks action with default message.
* `return { success = false, message = 'Your custom message' }` -> blocks action with custom message.
* any other return value -> allows action.

## Where to use this code

Hook code runs on the **server** only. Add it in one of these ways:

<details>

<summary>Inside tgg-banking (server/custom/*.lua)</summary>

Put your hook script in `tgg-banking/server/custom/` (e.g. `server/custom/limits.lua`). It loads automatically with the resource. Use the native `RegisterHook` function.

</details>

<details>

<summary>External resource</summary>

Create your own FiveM resource (e.g. `my-banking-rules`) with a server script. Add `ensure tgg-banking` before it in `server.cfg`, add `tgg-banking` to `dependencies` in your `fxmanifest.lua`, and use `exports['tgg-banking']:RegisterHook(...)`. Your callback is written as a normal Lua function in your script; the runtime handles cross-resource function references automatically.

</details>

Register hooks once when the server or resource starts (top level of your server script, not inside an event handler).

## Examples

### Generic outline

<details>

<summary>Inside tgg-banking (server/custom/*.lua)</summary>

```lua
RegisterHook('eventName', function(source, payload, result)
    -- your logic
end)
```

</details>

<details>

<summary>External resource</summary>

```lua
exports['tgg-banking']:RegisterHook('eventName', function(source, payload, result)
    -- your logic
end)
```

</details>

The examples below use the **external resource** form. Replace with `RegisterHook` when using `server/custom/*.lua`.

### beforeDeposit

Payload: `amount`, `reason`, `iban`, `cardNumber`, `accountType`, `accountOwnerId`, `playerIdentifier`, `newAccountBalance`

Block deposits that would exceed a character's max bank balance:

```lua
exports['tgg-banking']:RegisterHook('beforeDeposit', function(source, payload)
    if payload.accountOwnerId == payload.playerIdentifier and payload.newAccountBalance > 150000 then
        return {
            success = false,
            message = 'You cannot have more than $150,000 in your bank account.'
        }
    end
end)
```

### afterDeposit

Same payload as `beforeDeposit` plus `result`.

Log successful deposits:

```lua
exports['tgg-banking']:RegisterHook('afterDeposit', function(source, payload, result)
    if result and result.success then
        print(('[BANKING] %s deposited %s to IBAN %s'):format(payload.playerIdentifier, payload.amount, payload.iban))
    end
end)
```

### beforeWithdraw

Payload: `amount`, `reason`, `iban`, `cardNumber`, `accountType`, `accountOwnerId`, `playerIdentifier`

Block withdrawals above a limit or from blacklisted accounts:

```lua
exports['tgg-banking']:RegisterHook('beforeWithdraw', function(source, payload)
    if payload.amount > 50000 then
        return { success = false, message = 'Maximum single withdrawal is $50,000.' }
    end
end)
```

### afterWithdraw

Same payload as `beforeWithdraw` plus `result`.

Log successful withdrawals:

```lua
exports['tgg-banking']:RegisterHook('afterWithdraw', function(source, payload, result)
    if result and result.success then
        print(('[BANKING] %s withdrew %s from IBAN %s'):format(payload.playerIdentifier, payload.amount, payload.iban))
    end
end)
```

### beforeTransfer

Payload: `amount`, `reason`, `senderIban`, `targetIban`, `senderOwnerId`, `targetOwnerId`, `senderAccountType`, `targetAccountType`, `playerIdentifier`, `newTargetBalance`

Block transfers that would exceed limits or to/from restricted accounts:

```lua
exports['tgg-banking']:RegisterHook('beforeTransfer', function(source, payload)
    if payload.amount > 100000 then
        return { success = false, message = 'Maximum single transfer is $100,000.' }
    end
end)
```

### afterTransfer

Same payload as `beforeTransfer` plus `result`.

Log successful transfers:

```lua
exports['tgg-banking']:RegisterHook('afterTransfer', function(source, payload, result)
    if result and result.success then
        print(('[BANKING] %s transferred %s from %s to %s'):format(
            payload.playerIdentifier,
            payload.amount,
            payload.senderIban,
            payload.targetIban
        ))
    end
end)
```

### beforeAddSocietyMoney / beforeRemoveSocietyMoney

Payload: `society`, `iban`, `amount`, `currentBalance`, `newBalance`, `source`, `initiator` (export calls use `source = 0`)

Block society deposits above a threshold:

```lua
exports['tgg-banking']:RegisterHook('beforeAddSocietyMoney', function(source, payload)
    if payload.amount > 100000 then
        return { success = false, message = 'Maximum single deposit is $100,000.' }
    end
end)
```

### beforeLoanApply / afterLoanApply

Payload: `playerIdentifier`, `amount`, `duration`, `interestRate`, `paymentAmount`, `totalAmount`, `paymentFrequency`, `source`. After hook adds `loanId`, `loanStatus`; result: `{ success, loanId, amount, paymentAmount, nextPaymentDate }`

Log new loans:

```lua
exports['tgg-banking']:RegisterHook('afterLoanApply', function(source, payload, result)
    if result and result.success then
        print(('[LOANS] %s received loan %s for $%s'):format(
            payload.playerIdentifier,
            result.loanId,
            payload.amount
        ))
    end
end)
```

### beforeCardCreate / afterCardCreate

Payload: `accountIban`, `playerIdentifier`, `displayName`, `color`, `source`. After adds `cardId`, `cardNumber`. **PIN and CVV never in payloads.**

Block card creation for certain account types or players:

```lua
exports['tgg-banking']:RegisterHook('beforeCardCreate', function(source, payload)
    -- Example: only allow one card per account via external tracking
    return -- allow by default
end)
```

### beforeAtmAuthorize / beforeAtmPinChange

Payload: `cardNumber`, `accountIban`, `playerIdentifier`, `source`. **Raw PIN and new PIN never in payloads.**

Block ATM access for specific cards (e.g. flagged accounts):

```lua
exports['tgg-banking']:RegisterHook('beforeAtmAuthorize', function(source, payload)
    -- PIN is never in payload; use cardNumber/accountIban for lookup
    if payload.cardNumber == 123456789 then
        return { success = false, message = 'This card has been restricted.' }
    end
end)
```
