> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elementlabs.net/llms.txt
> Use this file to discover all available pages before exploring further.

# The qb-inventory swap hook

> Add the RegisterOnSwapItems export a product needs to see items move on qb-inventory.

Some products need to know when a player moves an item from one inventory to another, and to be able
to refuse the move: a shop that must not be emptied into a stash, a job container that only accepts
certain items.

Every other supported inventory publishes a hook for this. `qb-inventory` has none: its item move is
an internal event with nothing to subscribe to. A product that needs the hook reports it and stops:

```text theme={null}
[qb-inventory] onSwapItems needs the RegisterOnSwapItems export, which stock qb-inventory does not have.
```

## Outcome

`qb-inventory` publishes a `RegisterOnSwapItems` export, and products that watch item movement start
and work. The edit is around fifteen lines in two of its files. Nothing else on your server changes.

<Note>
  Only products that watch item movement need this. If no product reports the line above, you have
  nothing to do here.
</Note>

## Prerequisites

* `qb-inventory` running on your server, and a copy of the two files you are about to edit.
* The steps below are written against current `qb-inventory` from `qbcore-framework/qb-inventory`.
  If yours is already a fork, the function names are the same but the line numbers are not.
* Console access to restart `qb-inventory` and the product.

## Steps

### 1. Add the export

Open `qb-inventory/server/functions.lua` and add this at the end of the file.

```lua theme={null}
local swapHooks = {}

--- Registers a handler called before an item moves between two inventories.
--- Returning false from any handler refuses the move.
function RegisterOnSwapItems(handler)
    swapHooks[#swapHooks + 1] = handler
end

exports('RegisterOnSwapItems', RegisterOnSwapItems)

--- Runs every handler. Returns false as soon as one of them refuses.
function RunSwapHooks(payload)
    for _, handler in ipairs(swapHooks) do
        if handler(payload) == false then
            return false
        end
    end
    return true
end
```

### 2. Call it from the move

Open `qb-inventory/server/main.lua` and find the handler for
`qb-inventory:server:SetInventoryData`. It starts like this:

```lua theme={null}
RegisterNetEvent('qb-inventory:server:SetInventoryData', function(fromInventory, toInventory, fromSlot, toSlot, fromAmount, toAmount)
```

Inside it, after both items have been read (the two lines that call `getItem`) and **before**
anything is added or removed, insert:

```lua theme={null}
    local allowed = RunSwapHooks({
        source = src,
        action = toItem and 'swap' or 'move',
        fromInventory = fromInventory,
        toInventory = toInventory,
        fromType = nil,
        toType = nil,
        fromSlot = fromItem or fromSlot,
        toSlot = toItem or toSlot,
        count = toAmount or fromAmount,
    })

    if not allowed then return end
```

Returning before the move is what refuses it: the item never leaves its slot, and the player's
inventory redraws unchanged.

### 3. Restart

```text theme={null}
restart qb-inventory
restart <the product>
```

## Verification

The product no longer reports the missing export when it starts.

To confirm the hook fires, move an item into an inventory the product watches. A product that refuses
the move leaves the item where it was.

## Next steps

### What the product receives

The handler is called with one table, the same shape every supported inventory reports:

| Field           | Meaning                                                     |
| --------------- | ----------------------------------------------------------- |
| `source`        | The player who moved the item                               |
| `action`        | `move`, `swap` or `stack`                                   |
| `fromInventory` | The inventory the item leaves: a player id, or a stash name |
| `toInventory`   | The inventory it arrives in                                 |
| `fromSlot`      | The item leaving, or its slot number when the slot is empty |
| `toSlot`        | The item being displaced, or the destination slot number    |
| `count`         | How many are moving                                         |

A handler that returns `false` refuses the move. Any other return value (including no return at all)
allows it.

### Keeping the edit

`qb-inventory` updates overwrite both files. After updating it, re-apply the two steps above; the
product reports the missing export again if you forget, so this fails loudly rather than silently.

## Related

* [Supported server resources](/sdk/supported-resources)
