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

# Compatibility

## Compatibility

Other resources call `qb-inventory` and `ox_inventory` **by name** — that is how FiveM exports work, an export is addressed to a resource name and nothing else. This resource answers to both names, so scripts written for either one keep working without being edited.

{% hint style="success" %}
**tl;dr — install the proxy, change nothing else.** Stop the real `qb-inventory` / `ox_inventory`, `ensure` the matching folder from `compat/` under that same name, and every third-party script that called the old inventory now reaches this one. See Quick install below.
{% endhint %}

#### Why this is needed at all

`exports.ox_inventory:AddItem(...)` only works if a resource **literally named** `ox_inventory` is running and has registered an `AddItem` export. There is no alias mechanism in FiveM — the name in the export call IS the address. So if a server switches its inventory to `aty_inventory` but a weapon shop script still says `exports.ox_inventory:AddItem(...)`, that call goes nowhere unless something answers to the name `ox_inventory`.

`compat/qb-inventory/` and `compat/ox_inventory/` are that something. Each is a tiny resource folder — a few dozen lines, no state, no database access — whose only job is to sit under the old name and forward every call straight to `aty_inventory`. Read server/api/ox.lua or compat/ox\_inventory/server.lua if you want to see exactly what "forward" means; there is nothing hidden in it.

#### Quick install

```cfg
ensure aty_lib
ensure aty_inventory

# pick whichever names your other scripts actually call —
# install both if you are not sure, it is harmless to run both
ensure qb-inventory      # the proxy from compat/qb-inventory, NOT the original
ensure ox_inventory      # the proxy from compat/ox_inventory, NOT the original
```

1. **Stop or delete the real `qb-inventory` / `ox_inventory` folder first.** Two resources cannot share one name — if the genuine one is still present and started, the proxy will either fail to start or (worse) start and race it, and which one answers a given call becomes load order, not a setting.
2. Copy `compat/qb-inventory/` and/or `compat/ox_inventory/` out to your `resources/` folder — they can live anywhere, they only need to keep their folder name.
3. `ensure` them **after** `aty_inventory` in `server.cfg`. Order relative to each other does not matter.
4. Run `invdoctor` in the server console. A correct install prints a line like *"`ox_inventory` is this resource wearing that name"* — see Troubleshooting below for what a **wrong** install looks like.

{% hint style="danger" %}
**Qbox needs one more thing, and it is an ordering rule.**

Qbox ships `ox_inventory`, so step 1 is not optional there — leaving it installed means `aty_inventory` starts, shows up in the loading screen, and F2 still opens the old inventory, because that is the resource still answering to the name.

On top of that, `qbx_core` reads the item list out of `ox_inventory`'s own files while it is starting (`require '@ox_inventory.data.items'`). The proxy serves those files from the live catalogue, which means it has to be able to reach `aty_inventory` by then:

```cfg
ensure aty_lib
ensure aty_inventory     # before the core, not after
ensure ox_inventory      # the proxy from compat/
ensure qbx_core
```

Get that order wrong and the core starts believing the server has no items. The proxy hands back an empty list rather than an error — an error there would take the core, and everything that depends on it, down with it — and says so in the console: `data/items.lua was read before aty_inventory could answer`, followed by the line that names the fix.
{% endhint %}

#### What Qbox answers for

`aty_lib` matches a framework by resource name and knows `qb-core` and `es_extended`; Qbox is neither, so the bridge reports no framework. This resource asks `qbx_core` itself for the four things that matter:

| Question     | On Qbox                                                      |
| ------------ | ------------------------------------------------------------ |
| Identity     | `PlayerData.citizenid` — the character, not the account      |
| Job and gang | `PlayerData.job` / `.gang`, so job gates gate                |
| Needs        | `hunger` and `thirst` metadata, plus the HUD event           |
| Money        | `qbx_core`'s `GetMoney` / `AddMoney` / `RemoveMoney` exports |

```
invwallet <playerId>     which backend holds the money, and what it reads
```

Before 1.7.4 none of that happened: the resource ran its standalone answers, so money meant the cash item and never the wallet, and every character on one account shared a bag.

{% hint style="warning" %}
**Upgrading a Qbox server from 1.7.3 or earlier.** Bags were keyed on the licence and are now keyed on the citizenid. Back up `aty_inventories`, then run `invqbxkeys` to see what would move and `invqbxkeys confirm` to move it.
{% endhint %}

**Cash as an item on Qbox**

`qbx_core` keeps every account named in the convar `inventory:accounts` (default `["money"]`) as an item of its own, and writes it through `exports.ox_inventory:SetItem` — which on this setup is the proxy, so the `money` item lands in this inventory. That item weighs nothing and has no stack limit, unlike `Config.Money.stack` for mirrored cash: Qbox writes the whole balance in one set and never retries, so it must always fit in one slot.

The mirror keeps that `money` item and the wallet equal in both directions, as ox\_inventory's own Qbox bridge does: Qbox's writes bring the item up to the wallet, and dropping, handing over or `RemoveItem`-ing the item moves the wallet. `cash` copies an older mirror left in bags are taken back once. With no `money` definition to adopt (no parked ox\_inventory), `cash` stands in for it.

**aty\_escmenu**

When `aty_escmenu` replaces the pause menu, the game reports no pause menu open. The inventory also reads the `escMenuOpen` state bag, so it does not open underneath it, and container blips are named for its map panel.

{% hint style="warning" %}
The proxies are deliberately **not** declared as dependencies of `aty_inventory`. FiveM stops every dependant when a dependency restarts and does not bring them back — if the proxy depended on `aty_inventory`, a plain `restart aty_inventory` would silently kill the proxy, and every third-party script would go dark until someone noticed and restarted it by hand. A server that does not need a proxy also should not be forced to run one.
{% endhint %}

#### "Do I need to change `Config.Inventory` in my other scripts?"

**No — leave it exactly as it is.** This is the single most common question about this compatibility layer, so it gets its own answer:

A lot of multi-framework scripts have something like:

```lua
Config.Inventory = 'ox_inventory'
-- …
exports[Config.Inventory]:AddItem(src, 'water', 1)
```

That code does not care what inventory is *actually* running — it only cares that a resource named `ox_inventory` answers `AddItem` the way ox does. Once the proxy is installed under that name, it does exactly that. Changing `Config.Inventory` to `'aty_inventory'` does not make this MORE compatible — it breaks it, because the script almost certainly has no branch for `'aty_inventory'` at all and falls through to nothing. Leave the value alone; the proxy's whole purpose is to make that value keep being true.

#### Two ways to use it

**A — install the proxy (recommended).** Covered above. Nothing to touch in any other resource, ever, as long as the export it calls is on the list below.

**B — call this resource directly**, for new code or code you are already editing anyway, without installing a second resource folder at all:

```lua
-- qb-style, prefixed directly on aty_inventory
exports.aty_inventory:qb_AddItem(src, 'water', 1)
exports.aty_inventory:qb_RemoveItem(src, 'water', 1)
exports.aty_inventory:qb_GetInventory(src)
exports.aty_inventory:qb_GetItemCount(src, 'water')
exports.aty_inventory:qb_ClearInventory(src)
-- client: exports.aty_inventory:qb_GetPlayerItems()

-- ox-style, native names on aty_inventory (only the two that
-- collide with this resource's own shape need the ox_ prefix)
exports.aty_inventory:AddItem(inv, 'water', 1)
exports.aty_inventory:ox_GetInventory(inv)
exports.aty_inventory:ox_GetInventoryWeight(inv)
```

#### The ox\_inventory export surface, in full

This is not a small convenience shim — it is the **entire** ox server and client API, reimplemented with ox's own argument order and return shapes (`server/api/ox.lua`). Ox's `Search` has a genuinely odd asymmetry — a single item name returns a bare value, a list of names returns a keyed table — and that asymmetry is reproduced on purpose, not "cleaned up", because real scripts written against ox depend on it.

Every one of these still goes through the same transaction engine a player uses when dragging an item by hand: weight limits, stacking rules, the optimistic lock and the ledger all apply. This is a second **name**, never a second, unchecked **path** into the data.

<table><thead><tr><th width="220">Category</th><th>Exports</th></tr></thead><tbody><tr><td>Add / remove</td><td><code>AddItem</code> · <code>RemoveItem</code></td></tr><tr><td>Reading</td><td><code>Search</code> · <code>GetItem</code> · <code>GetItemCount</code> · <code>GetInventoryItems</code></td></tr><tr><td>Slot lookups</td><td><code>GetSlot</code> · <code>GetSlotIdWithItem</code> · <code>GetSlotWithItem</code> · <code>GetSlotsWithItem</code> · <code>GetSlotIdsWithItem</code></td></tr><tr><td>Capacity checks</td><td><code>CanCarryItem</code> · <code>CanCarryWeight</code> · <code>CanCarryAmount</code> · <code>GetInventoryMaxWeight</code></td></tr><tr><td>Writing state</td><td><code>SetMetadata</code> · <code>SetDurability</code> · <code>ClearInventory</code> · <code>SetMaxWeight</code> · <code>SetSlotCount</code></td></tr><tr><td>Slot planning</td><td><code>GetEmptySlot</code> · <code>GetItemSlots</code> · <code>GetSlotForItem</code> · <code>CanSwapItem</code></td></tr><tr><td>Moving &#x26; setting</td><td><code>SetItem</code> · <code>SwapSlots</code></td></tr><tr><td>Containers</td><td><code>RegisterStash</code> · <code>CreateTemporaryStash</code> · <code>GetContainerFromSlot</code> · <code>forceOpenInventory</code> · <code>InspectInventory</code> · <code>RemoveInventory</code></td></tr><tr><td>Shops</td><td><code>RegisterShop</code></td></tr><tr><td>Police pair</td><td><code>ConfiscateInventory</code> · <code>ReturnInventory</code></td></tr><tr><td>Vehicles &#x26; weapons</td><td><code>UpdateVehicle</code> · <code>GetCurrentWeapon</code></td></tr><tr><td>Ground drops</td><td><code>CreateDropFromPlayer</code> · <code>CustomDrop</code></td></tr><tr><td>Catalogue</td><td><code>Items</code> · <code>ItemList</code></td></tr><tr><td>Hooks</td><td><code>registerHook</code> · <code>removeHooks</code></td></tr><tr><td>Framework glue<br><sub>(called by ESX's own ox bridge)</sub></td><td><code>setPlayerInventory</code></td></tr><tr><td>pefcl banking</td><td><code>getCash</code> · <code>getBank</code> · <code>addCash</code> · <code>removeCash</code> · <code>getCards</code> · <code>giveCard</code><br><sub><code>getCards</code> / <code>giveCard</code> answer empty and say why: bank cards are not modelled here</sub></td></tr><tr><td>Present, but says so<br><sub>(registered so the call cannot throw; prints one line explaining what it does instead)</sub></td><td><code>ConvertItems</code><br><sub>bulk conversion runs through <code>invimport</code>, which shows a dry run first</sub></td></tr><tr><td>Prefixed<br><sub>(name collides with this resource's own shape)</sub></td><td><code>ox_GetInventory</code> · <code>ox_GetInventoryWeight</code><br><sub>reachable under ox's own names as <code>GetInventory</code> and <code>Inventory</code></sub></td></tr></tbody></table>

**Client side:**

<table><thead><tr><th width="220">Category</th><th>Exports</th></tr></thead><tbody><tr><td>What you carry</td><td><code>GetPlayerItems</code> · <code>GetItemCount</code></td></tr><tr><td>Weight</td><td><code>GetPlayerWeight</code> · <code>GetPlayerMaxWeight</code></td></tr><tr><td>Reading</td><td><code>Search</code> · <code>Items</code> · <code>ItemList</code></td></tr><tr><td>Slot lookups</td><td><code>GetSlotWithItem</code> · <code>GetSlotsWithItem</code> · <code>GetSlotIdWithItem</code> · <code>GetSlotIdsWithItem</code></td></tr><tr><td>Acting</td><td><code>useItem</code> · <code>useSlot</code> · <code>giveItemToTarget</code></td></tr><tr><td>Weapons</td><td><code>getCurrentWeapon</code> · <code>weaponWheel</code></td></tr><tr><td>The panel</td><td><code>openInventory</code> · <code>closeInventory</code> · <code>openNearbyInventory</code></td></tr><tr><td>Notices</td><td><code>notify</code></td></tr><tr><td>Progress bar</td><td><code>Progress</code> · <code>ProgressActive</code> · <code>CancelProgress</code></td></tr><tr><td>Present, but says so<br><sub>(registered so the call cannot throw; each prints one line explaining what it does instead)</sub></td><td><code>Keyboard</code> · <code>setStashTarget</code> · <code>displayMetadata</code></td></tr></tbody></table>

{% hint style="warning" %}
**The progress bar and the last row are worth understanding before you rely on them.**

`Progress` draws this resource's own bar and runs it for the full `duration`: `label`, `canCancel`, `useWhileDead` and `disable` are honoured, and as in ox the callback is told whether it was cancelled while the export returns whether it finished. `anim` and `prop` are **not** played — they would fight the animations this resource plays for its own actions — and the console says so once. A bar that reported "finished" without ever running would make a script hand out its reward instantly, so this one always runs.

`Keyboard` is ox re-publishing **ox\_lib's** input dialog under its own name. It is not an inventory feature and there is no general dialog here to hand back, so it returns `nil`; call `lib.inputDialog` directly. `weaponWheel` can only hold the wheel off — `Config.Weapons.wheel = false` still wins over any script.
{% endhint %}

A few of these behave on screen as ox's do. A hook that returns `false` prints `[hooks] hook_N (<resource>) rejected <event>` in the server console (ox's `inventory:loghookrejection`, on by default), and `options.print = true` logs every run of that hook. `ConfiscateInventory` closes the player's open inventory; `ReturnInventory` closes it and tells the player their items were given back. As in ox, a `ReturnInventory` for a player with nothing held does nothing at all, so a jail script may call it on every release.

{% hint style="info" %}
**Not on either list?** Both lists are checked against ox's own source by `invoxapi` (the exports this resource publishes) and `invoxproxy` (the same names reached as `exports.ox_inventory:X()`, which is the path your script actually takes). If a name is genuinely absent, the proxy has nothing registered under it, so the call resolves to `nil` and errors the way any missing export does — this is not a silent failure, the calling script's own error handling (or lack of it) is what decides what happens next. Two ways to close the gap: add the name to the `MAP` table at the top of `compat/ox_inventory/server.lua` (or `client.lua`) — it forwards to the export of that name on `aty_inventory`, so the export has to exist there too — or rewrite that one call against this resource's own native exports in Exports — most ox exports not on this list have a same-named or clearly equivalent native export already.
{% endhint %}

#### Troubleshooting

Run `invdoctor` first, always — it is read-only and checks exactly the things that go wrong with a compatibility install:

* **`` `ox_inventory` is this resource wearing that name ``** — correct install, nothing to do.
* **`` `ox_inventory` is running as well as this one ``** — the *real* `ox_inventory` is still present and started alongside the proxy or `aty_inventory` itself. Stop it in `server.cfg`; which one of two live inventories answers a given call is load order, not a setting, and this is by a wide margin the most common "it's broken" report that turns out not to be a bug at all.

If the resource names all check out but a specific call still misbehaves, two more read-only commands narrow it down further:

* **`invbridge`** — asks `aty_lib` live what inventory it thinks is running, rather than trusting a snapshot taken at boot. If a bridge-based aty\_\* resource (a shop script, a crafting bench) is writing metadata that never shows up, this is usually why: the bridge resolved a different or no inventory in the up-to-ten-second window after startup, and every write since has gone through that stale answer.
* **`invforeign`** — checks that items and use-handlers registered by other resources (the qb-core catalogue, a `CreateUseableItem` call from an old script) were actually adopted and still work, and that this resource's own registration wins when both sides claim the same item name. Useful when "drop it in, change nothing" doesn't seem to hold for one specific item.

#### Self-identification

A proxy answers a hidden export, `AtyProxyTarget`, when asked — it returns the name of the resource it forwards to. This is exactly how `invdoctor` tells "a rival inventory is genuinely running" apart from "this is our own installer wearing that name": both look identical from `GetResourceState` alone, and a doctor that flags its own installer as a conflict is one people learn to ignore, which buries the finding that actually matters.

#### The framework mirror

```lua
Config.QbMirror = { … }
```

Some framework code (qb-core's own scripts, mostly) reads a player's inventory straight out of `QBCore.Functions.GetPlayerData().items` instead of asking any inventory resource by export. No proxy fixes that — there is no export call to intercept. The mirror writes that table back on every inventory change instead, so those reads stay correct without the reading code being touched at all.

```
invmirror       inspect what the mirror currently holds for a player
invbridge       inspect what aty_lib resolved the inventory to be
invforeign      check that foreign items/handlers were adopted correctly
```

See Migration for moving the *data* — existing player inventories and stash contents — across from `qb-inventory` or `ox_inventory`. This page is only about keeping other resources' **code** working; that page is about not losing anyone's items along the way.
