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

# Hooks

Event hooks let third party resources define new behaviour without modifying the inventory code. A hook runs **before** an action happens - your callback can inspect it, cancel it by returning `false`, or (for `createItem`) change the item's metadata by returning a table. All hooks are server-side.

{% hint style="info" %}
Usage is identical to ox\_inventory, so scripts written for its hook system work through the backwards compatibility layer without editing.
{% endhint %}

### RegisterHook

Registers a hook and returns a `hookId` string. The callback may be `nil` if you only want the post-hook event.

```lua
exports["oph3z-inventory"]:RegisterHook(eventName, function(payload) end, options)
```

* **`eventName`** : `string` - one of the hook names below.
* **`callback`** : `function(payload)` or `nil` - return `false` to cancel the action.
* **`options?`** : `table`
  * **`print?`** : `boolean` - print to the console when the hook triggers.
  * **`itemFilter?`** : `{ [string]: true }` - only trigger for these item names.
  * **`inventoryFilter?`** : `string[]` - only trigger for inventory ids matching one of these Lua patterns.
  * **`typeFilter?`** : `{ [string]: true }` - only trigger for these inventory types (`player`, `stash`, `trunk`, `glovebox`, `drop`, `container`, `shop`).

### RemoveHooks

Removes a hook created by the calling resource. Without an id, all of that resource's hooks are removed. Hooks are also cleaned up automatically when the resource stops.

```lua
exports["oph3z-inventory"]:RemoveHooks(hookId)
exports["oph3z-inventory"]:RemoveHooks()
```

### swapItems

Fires before any item move - between slots, into stashes, trunks, gloveboxes, drops, or when giving. Return `false` to cancel.

Payload:

* **`source`** : `number`
* **`action`** : `string` - the move kind, `give` when giving.
* **`itemName`** : `string`
* **`count`** : `number`
* **`metadata`** : `table`
* **`fromInventory`** / **`toInventory`** : `string` - inventory ids.
* **`fromType`** / **`toType`** : `string`
* **`fromSlot`** : `table` - the source descriptor.
* **`toSlot?`** : `number`

Example - nobody can put water into trunks or gloveboxes:

```lua
exports["oph3z-inventory"]:RegisterHook("swapItems", function(payload)
    return false
end, {
    itemFilter = { water_bottle = true },
    inventoryFilter = { "^trunk", "^glovebox" }
})
```

### openInventory

Fires before a player opens a secondary inventory - stash, trunk, glovebox, container or another player. Return `false` to keep it closed.

Payload: **`source`** : `number`, **`inventoryId`** : `string`, **`inventoryType`** : `string`

```lua
exports["oph3z-inventory"]:RegisterHook("openInventory", function(payload)
    if exports["my-zones"]:IsRestricted(payload.source) then return false end
end, {
    typeFilter = { trunk = true }
})
```

### openShop

Fires before a player opens a shop. Return `false` to keep it closed.

Payload: **`source`** : `number`, **`shopId`** : `string`, **`shopType`** : `"shop"`, **`label`** : `string`

```lua
exports["oph3z-inventory"]:RegisterHook("openShop", function(payload)
    if payload.shopId == "black_market" and IsPolice(payload.source) then return false end
end)
```

### buyItem

Fires before a shop purchase - once per basket line in basket mode, where one `false` cancels the whole purchase.

Payload: **`source`** : `number`, **`shopId`** : `string`, **`shopType`** : `"shop"`, **`itemName`** : `string`, **`metadata`** : `table`, **`count`** : `number`, **`price`** : `number`, **`totalPrice`** : `number`, **`currency`** : `"cash"` or `"bank"`

```lua
exports["oph3z-inventory"]:RegisterHook("buyItem", function(payload)
    if payload.itemName == "weapon_pistol" and not HasLicense(payload.source) then return false end
end)
```

### usingItem

Fires before an item is used - eating, drinking, tools, and also equipping weapons. Return `false` to fully prevent the use.

Payload: **`source`** : `number`, **`inventoryId`** : `string`, **`name`** : `string`, **`label`** : `string`, **`slot`** : `number`, **`count`** : `number`, **`metadata`** : `table`

```lua
exports["oph3z-inventory"]:RegisterHook("usingItem", function(payload)
    if exports["my-cuffs"]:IsCuffed(payload.source) then return false end
end)
```

### createItem

Fires when an item comes into existence - `AddItem`, `AddItemTo`, or a shop purchase. Return a `table` to replace the starting metadata, or `false` to cancel the creation.

Payload: **`inventoryId`** : `number` or `string`, **`itemName`** : `string`, **`count`** : `number`, **`metadata`** : `table`

```lua
exports["oph3z-inventory"]:RegisterHook("createItem", function(payload)
    if payload.itemName == "weapon_pistol" then
        return { batch = os.date("%Y-%m") }
    end
end, {
    itemFilter = { weapon_pistol = true }
})
```

### Post-hook events

The `hookId` returned by `RegisterHook` is also an event name. After all hooks ran and the action completed or was rejected, that event fires with the result - this is where side effects belong.

```lua
local hookId = exports["oph3z-inventory"]:RegisterHook("swapItems", nil, {
    inventoryFilter = { "^trunk" }
})

AddEventHandler(hookId, function(success, payload)
    -- success = false when a hook rejected the action or it failed elsewhere
    if success then
        print(payload.itemName .. " moved to " .. payload.toInventory)
    end
end)
```
