# Server exports

Call them on `exports['koja-inventory-v2']`. The resource name has dashes, so use the bracket form.

```lua
local ok, reason = exports['koja-inventory-v2']:AddItem(source, 'water', 2)
```

:::hint{type="info" title="Two API modes"}
With `Config.Ox.enabled = true` (the default), `AddItem`, `RemoveItem`, `GetItemCount`, `CanCarryItem`, `GetInventoryItems`, `Search`, `SetMetadata`, `ClearInventory`, `RegisterStash`, `RegisterShop` and `Items` use the **ox_inventory signatures** and are also served as `exports.ox_inventory`. See [ox_inventory compatibility](/new/inventory-v2/migrating-from-ox#what-stays-compatible). With `Config.Ox.enabled = false` they use the native signatures listed under [Inventory](#inventory). Every other export on this page is always available.
:::

`target` below is a player server id or a container id (`stash:<name>`, `trunk:<plate>`, `glovebox:<plate>`). See [Database](/new/inventory-v2/database#container-ids) for all container ids.

## Inventory

| Export | Returns | Description |
|---|---|---|
| `AddItem(target, name, count, metadata?)` | `true` or `false, reason` | Adds items, stacking first and then finding free space across pockets and the worn backpack. Reasons: `invalid_item`, `no_inventory`, `too_heavy`, `no_space`. |
| `RemoveItem(target, name, count, metadata?, itemId?)` | `boolean` | Removes items. Fails without removing anything if there are not enough. |
| `GetItemCount(target, name, metadata?)` | `number` | Total units. |
| `HasItem(target, name, count?)` | `boolean` | At least `count` (default 1). Always available. |
| `CanCarryItem(target, name, count, metadata?)` | `true` or `false, reason` | Checks weight and grid space without changing anything. |
| `GetInventoryItems(target)` | `table[]` | `{ name, label, count, metadata, slot, container, weight }` for every item. `slot` is the item id. |
| `Search(target, 'count'\|'slots', names, metadata?)` | `number`, `table[]` or a table by name | Counts or lists items by name. |
| `SetMetadata(target, itemId, metadata)` | `boolean` | Replaces the metadata of one item. |
| `ClearInventory(target, keep?)` | `true` | Removes everything except item names in `keep`. |
| `OpenInventory(source, type, data)` | `boolean` | Opens an inventory for a player: `'player', id`, `'stash', name`, `'shop', name`. |

## Single items

| Export | Returns | Description |
|---|---|---|
| `GetItem(target, itemId)` | `table` or `nil` | `{ id, name, label, count, metadata, container, weight, durability }`. |
| `SetDurability(target, itemId, value)` | `boolean` | Sets durability (0 to 100). |
| `AddDurability(source, itemId, amount)` | new value or `false` | Adds (positive) or removes (negative) durability. Removing goes through the normal wear rules, so the item can break. |
| `GetWeight(target)` | `current, max` | Carried weight in grams and the limit. |

```lua title="A lockpick that only wears when it fails"
exports['koja-inventory-v2']:RegisterUsableItem('lockpick', function(source, item)
    local success = math.random() < 0.6
    if not success then
        exports['koja-inventory-v2']:AddDurability(source, item.id, -25)
    end
    return false
end)
```

Returning `false` from the use handler skips the automatic per-use wear from `Config.Durability.tools`, so only your own call changes the durability.

## Drops

| Export | Returns | Description |
|---|---|---|
| `CreateDrop(coords, items)` | drop id or `nil` | Creates a drop on the ground. `items` is a list of `{ name = , count = , metadata = }` or `{ name, count, metadata }`. Merges with a nearby drop like a normal drop. |

```lua
exports['koja-inventory-v2']:CreateDrop(vec3(25.7, -1347.3, 29.49), {
    { name = 'water', count = 3 },
    { 'WEAPON_PISTOL', 1, { ammo = 12 } },
})
```

## Locations

Stashes, shops and crafting benches created at runtime. They are saved, show up in the admin panel's Locations tab, get a point and a sign for every player, and survive restarts.

| Export | Returns | Description |
|---|---|---|
| `CreateLocation(data)` | id or `false, reason` | Creates a location. |
| `UpdateLocation(id, data)` | `true` or `false, reason` | Changes fields of a runtime location. |
| `RemoveLocation(id)` | `boolean` | Deletes it. Stash contents stay in the database. |
| `GetLocations()` | `table[]` | All runtime locations. |

```lua
local id = exports['koja-inventory-v2']:CreateLocation({
    kind = 'stash',
    id = 'ballas_stash',
    label = 'Ballas stash',
    coords = vec3(85.2, -1959.4, 20.75),
    radius = 1.5,
    jobs = { ballas = 0 },
    width = 10,
    height = 8,
    maxWeight = 150000,
    shared = true,
})
```

| Field | Kinds | Description |
|---|---|---|
| `kind` | all | `'stash'`, `'shop'` or `'crafting'`. |
| `id` | all | Optional. Lowercase letters, digits and `_`, 2 to 32 characters. Generated when empty. Must not clash with a config name. |
| `label`, `coords`, `radius`, `jobs`, `blip` | all | Name, position, interaction radius (0.5 to 10), `{ job = minGrade }`, map blip. |
| `width`, `height`, `maxWeight`, `shared` | stash | Grid, weight limit, shared or per player. |
| `width`, `items` | shop | Grid width and `{ { name, price, stock? } }`. |
| `recipes` | crafting | Recipe ids from `Config.Recipes`. |

Reasons: `invalid`, `invalid_name`, `name_taken`, `no_items`, `no_recipes`.

## Stashes and shops (native mode)

| Export | Description |
|---|---|
| `RegisterStash({ name, label, coords?, radius?, width, height, maxWeight?, jobs?, shared?, owner? })` | Registers a stash. `owner` (string) makes it private to that identifier. |
| `RegisterShop({ name, label, locations?, jobs?, width?, items })` | Registers or replaces a shop. |

With ox mode on, use the ox signatures instead: `RegisterStash(name, label, slots, maxWeight, owner, groups, coords)` and `RegisterShop(type, { name, inventory, locations, groups })`.

## Usable items and clothing

| Export | Description |
|---|---|
| `RegisterUsableItem(name, function(source, item) end)` | Runs when the item is used. `item` is `{ name, id, count, meta, container }`. Return `false` to cancel consuming it. |
| `AddClothing(target, category, drawable, texture, gender?)` | Gives a clothing item, e.g. `AddClothing(source, 'jackets', 22, 1)`. Categories are the keys in `Config.Clothing.categories`. |
| `GetItemDefinitions(name?)` | One item definition or all of them. |

## Hooks

| Export | Description |
|---|---|
| `RegisterHook(event, callback, options?)` | Same as ox `registerHook`. Returns a hook id. See [Events and hooks](/new/inventory-v2/api/events-and-hooks). |
| `RemoveHooks(id?)` | Removes one hook, or every hook of the calling resource. |

## Search

| Export | Description |
|---|---|
| `RegisterSearchCheck(function(target) end)` | Lets your script decide if a player can be frisked. Return `true` to allow, `false` to block, `nil` to let the default checks (hands up, cuffed, dead) decide. |
| `IsBeingSearched(target)` | `true` while someone is frisking that player. |

## More

- [Runtime items](/new/inventory-v2/api/runtime-items): `RegisterItem`, `RegisterItems`, `CreateItem`, `RemoveItemDefinition`, `GetDynamicItems`.
- [Custom slots](/new/inventory-v2/api/custom-slots): `RegisterSlot`, `RemoveSlot`, `GetSlotItem`, `SetSlotItem`, `GetSlots`.
