# Server

## Compatibility

This script works with other popular inventory systems, like es\_extended, qb-inventory, and ox\_inventory

For ESX and QBCore functions, the setup is done automatically. But, if you want to keep using exports from ox\_inventory or qb-inventory for compatibility, you need to turn on this option in the file: `jaksam_inventory/integrations/sv_integrations.lua`

## Server functions

Here there are built-in exports of jaksam's inventory

### addItem

Adds items to an inventory with support for metadata and specific slot placement

```lua
exports['jaksam_inventory']:addItem(inventoryId, itemName, amount, metadata, slotId)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to add items to
  * Can be a player server ID or inventory ID
* `itemName`: string
  * The name of the item to add
* `amount`: number
  * How many items to add
* `metadata`: table (optional)
  * Additional data for the item (e.g. weapon serial, item durability)
* `slotId`: number (optional)
  * Specific slot to place the item in

#### Returns

* `success`: boolean
  * true if items were added successfully
* `resultCode`: string
  * Error message if the operation failed

#### Example

```lua
-- Add 5 bread to a player's inventory
local success, result = exports['jaksam_inventory']:addItem(1, 'bread', 5)

-- Add a weapon with metadata
local success, result = exports['jaksam_inventory']:addItem(1, 'WEAPON_PISTOL', 1, {
    serial = "ABC123",
    ammo = 12
})

-- Add item to specific slot
local success, result = exports['jaksam_inventory']:addItem(1, 'bread', 1, nil, 5) -- slot 5
```

### addItemToTrunk

Adds items to a vehicle trunk using only the vehicle plate, automatically resolving the full inventory ID

```lua
exports['jaksam_inventory']:addItemToTrunk(plate, itemName, amount, metadata, slotId)
```

#### Parameters

* `plate`: string
  * The vehicle license plate
* `itemName`: string
  * The name of the item to add
* `amount`: number
  * How many items to add
* `metadata`: table (optional)
  * Additional data for the item
* `slotId`: number (optional)
  * Specific slot to place the item in

#### Returns

* `success`: boolean
  * true if items were added successfully
* `resultCode`: string
  * Error message if the operation failed (e.g., "vehicle\_not\_found")
* `notificationType`: string
  * Type of notification to show to the user

#### Example

```lua
-- Add 5 water bottles to vehicle trunk
local plate = GetVehicleNumberPlateText(vehicle)
local success, result = exports['jaksam_inventory']:addItemToTrunk(plate, 'water', 5)

if not success then
    print("Failed to add item: " .. result)
end

-- Add item with metadata
local success = exports['jaksam_inventory']:addItemToTrunk("ABC 123", 'phone', 1, {
    number = "555-0123"
})
```

#### Notes

* Works with owned vehicles (even if not spawned/in garage)
* Works with NPC vehicles (if currently spawned)
* Automatically creates trunk inventory if it doesn't exist
* For owned vehicles, inventory is persistent (saved to database)

### addItemToGlovebox

Adds items to a vehicle glovebox using only the vehicle plate, automatically resolving the full inventory ID

```lua
exports['jaksam_inventory']:addItemToGlovebox(plate, itemName, amount, metadata, slotId)
```

#### Parameters

* `plate`: string
  * The vehicle license plate
* `itemName`: string
  * The name of the item to add
* `amount`: number
  * How many items to add
* `metadata`: table (optional)
  * Additional data for the item
* `slotId`: number (optional)
  * Specific slot to place the item in

#### Returns

* `success`: boolean
  * true if items were added successfully
* `resultCode`: string
  * Error message if the operation failed (e.g., "vehicle\_not\_found")
* `notificationType`: string
  * Type of notification to show to the user

#### Example

```lua
-- Add documents to glovebox
local plate = GetVehicleNumberPlateText(vehicle)
local success = exports['jaksam_inventory']:addItemToGlovebox(plate, 'documents', 1)

-- Add multiple items
local success = exports['jaksam_inventory']:addItemToGlovebox("XYZ 789", 'money', 500)
```

#### Notes

* Works with owned vehicles (even if not spawned/in garage)
* Works with NPC vehicles (if currently spawned)
* Automatically creates glovebox inventory if it doesn't exist
* For owned vehicles, inventory is persistent (saved to database)

### removeItemFromTrunk

Removes items from a vehicle trunk using only the vehicle plate, automatically resolving the full inventory ID

```lua
exports['jaksam_inventory']:removeItemFromTrunk(plate, itemName, amount, metadata, slotId)
```

#### Parameters

* `plate`: string
  * The vehicle license plate
* `itemName`: string
  * The name of the item to remove
* `amount`: number
  * How many items to remove
* `metadata`: table (optional)
  * Metadata to match for removal (optional filtering)
* `slotId`: number (optional)
  * Specific slot to remove from

#### Returns

* `success`: boolean
  * true if items were removed successfully
* `resultCode`: string
  * Error message if the operation failed
* `notificationType`: string
  * Type of notification to show to the user

#### Example

```lua
-- Remove 3 water bottles from trunk
local plate = GetVehicleNumberPlateText(vehicle)
local success = exports['jaksam_inventory']:removeItemFromTrunk(plate, 'water', 3)

-- Remove from specific slot
local success = exports['jaksam_inventory']:removeItemFromTrunk("ABC 123", 'weapon', 1, nil, 5)
```

#### Notes

* Vehicle must exist (owned vehicle in database or NPC vehicle currently spawned)
* Returns false with "vehicle\_not\_found" if vehicle doesn't exist

### removeItemFromGlovebox

Removes items from a vehicle glovebox using only the vehicle plate, automatically resolving the full inventory ID

```lua
exports['jaksam_inventory']:removeItemFromGlovebox(plate, itemName, amount, metadata, slotId)
```

#### Parameters

* `plate`: string
  * The vehicle license plate
* `itemName`: string
  * The name of the item to remove
* `amount`: number
  * How many items to remove
* `metadata`: table (optional)
  * Metadata to match for removal (optional filtering)
* `slotId`: number (optional)
  * Specific slot to remove from

#### Returns

* `success`: boolean
  * true if items were removed successfully
* `resultCode`: string
  * Error message if the operation failed
* `notificationType`: string
  * Type of notification to show to the user

#### Example

```lua
-- Remove documents from glovebox
local plate = GetVehicleNumberPlateText(vehicle)
local success = exports['jaksam_inventory']:removeItemFromGlovebox(plate, 'documents', 1)

if not success then
    print("Document not found in glovebox")
end
```

#### Notes

* Vehicle must exist (owned vehicle in database or NPC vehicle currently spawned)
* Returns false with "vehicle\_not\_found" if vehicle doesn't exist

### getInventoryIdFromPlate

Resolves the full inventory ID for a vehicle compartment using only the vehicle plate

```lua
exports['jaksam_inventory']:getInventoryIdFromPlate(plate, compartment)
```

#### Parameters

* `plate`: string
  * The vehicle license plate
* `compartment`: string
  * Either "trunk" or "glovebox"

#### Returns

* `inventoryId`: string | nil
  * The full inventory ID (format: "vehicle:plate:model:compartment")
  * nil if vehicle not found

#### Example

```lua
-- Get trunk inventory ID
local plate = GetVehicleNumberPlateText(vehicle)
local trunkId = exports['jaksam_inventory']:getInventoryIdFromPlate(plate, "trunk")

if trunkId then
    print("Trunk ID: " .. trunkId)
    -- Now you can use standard inventory functions
    local inventory = exports['jaksam_inventory']:getInventory(trunkId)
end

-- Get glovebox inventory ID
local gloveboxId = exports['jaksam_inventory']:getInventoryIdFromPlate("ABC 123", "glovebox")
```

#### Notes

* Searches in this order:
  1. Owned vehicles database (ESX: `owned_vehicles`, QBCore: `player_vehicles`)
  2. Existing inventories in `jaksam_inventory` table
  3. Currently spawned vehicles (GetAllVehicles - NPC vehicles)
* For owned vehicles, automatically creates inventory if it doesn't exist
* Created inventories are persistent for owned vehicles, temporary for NPC vehicles
* Works even if vehicle is not currently spawned (garage)

### canCarryItem

Checks if an inventory has space for additional items, considering both weight and slot limits

```lua
exports['jaksam_inventory']:canCarryItem(inventoryId, itemName, amount)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to check
  * Can be a player server ID or inventory ID
* `itemName`: string
  * The name of the item to check
* `amount`: number
  * How many items to check for

#### Returns

* `boolean`
  * true if the inventory can carry the items
  * false if adding would exceed weight or slot limits

#### Example

```lua
-- Check if player can carry 5 bread
local canCarry = exports['jaksam_inventory']:canCarryItem(1, 'bread', 5)

if canCarry then
    -- Safe to add items
    exports['jaksam_inventory']:addItem(1, 'bread', 5)
end
```

### canSwapItem

Checks if swapping firstItem (removing firstItemCount) with testItem (adding testItemCount) is possible

```lua
exports['jaksam_inventory']:canSwapItem(inventoryId, firstItem, firstItemCount, testItem, testItemCount)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to check
  * Can be a player server ID or inventory ID
* `firstItem`: string
  * The name of the item to check
* `firstItemCount`: number
  * How many items to remove
* `testItem`: string
  * The name of the item to add
* `testItemCount`: number
  * How many items to add

#### Returns

* `boolean`
  * true if the inventory can swap the items
  * false if swapping is not possible

#### Example

```lua
-- Check if player can swap 5 bread for 1 water
local playerId = 1
local canSwap = exports['jaksam_inventory']:canSwapItem(playerId, 'bread', 5, 'water', 1)

if canSwap then
    exports['jaksam_inventory']:removeItem(playerId, 'bread', 5)
    exports['jaksam_inventory']:addItem(playerId, 'water', 1)
end
```

### clearInventory

Removes all items from an inventory, with optional exclusion of specific items

```lua
exports['jaksam_inventory']:clearInventory(inventoryId, excludedItems)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to clear
  * Can be a player server ID or inventory ID
* `excludedItems`: string | table (optional)
  * Items to exclude from clearing (keep in inventory)
  * Can be a single item name (string) or an array of item names (table)
  * If not provided, all items will be removed

#### Returns

* `success`: boolean
  * true if inventory was cleared successfully
  * false if inventory doesn't exist or database update failed

#### Example

```lua
local playerId = 14

-- Clear all items from player inventory
local success = exports['jaksam_inventory']:clearInventory(playerId)

-- Clear inventory but keep specific items
local success = exports['jaksam_inventory']:clearInventory(playerId, 'phone') -- keep phone

-- Clear inventory but keep multiple items
local success = exports['jaksam_inventory']:clearInventory(1, {'phone', 'id_card', 'driver_license'})

-- Clear stash inventory
local success = exports['jaksam_inventory']:clearInventory('police_stash_1')
```

### createInventory

Creates a new inventory in both database and memory (depending on options). If an inventory with the same ID already exists, returns the existing one without modifying it

```lua
exports['jaksam_inventory']:createInventory(id, label, options, items, inventoryType, metadata)
```

#### Parameters

* `id`: string | nil
  * Unique identifier for the inventory. If nil, a random ID is generated
* `label`: string | nil
  * Display name for the inventory. If nil, a translation based on inventory type will be used
* `options`: table (optional)
  * Configuration options for the inventory:
  * `maxWeight` (number, optional): Maximum weight capacity
  * `maxSlots` (number, optional): Maximum number of slots
  * `columns` (number, optional): Number of columns for grid display in the UI (for example you can make an inventory that's total slots is 10, but only has 2 columns, so it will be a 2x5 grid)
  * `temporary` (boolean, optional): If true, the inventory is not saved to the database and will be lost on script restart
  * `prefillItems` (table, optional): Random loot configuration. Items are picked via weighted selection without replacement. Structure:
    * `minTypes` (number, optional): Minimum number of different item types to add. Default: 1
    * `maxTypes` (number, optional): Maximum number of different item types to add. Default: pool size
    * `items` (table, **required**): Array of possible items, each entry: `{name = string, chance = number, min = number, max = number, metadata = table?}`
      * `name` (string, **required**): Item name
      * `chance` (number, optional): Relative weight for selection (higher = more likely). Default: 1
      * `min` (number, optional): Minimum amount when picked. Default: 1
      * `max` (number, optional): Maximum amount when picked. Default: 1
      * `metadata` (table, optional): Metadata to attach to the item
  * `revealItems` (table, optional): Progressive item reveal animation when the inventory is opened. Items appear one by one. Structure:
    * `delayPerItem` (number, optional): Milliseconds between each item reveal. Default: 1000
    * `randomOrder` (boolean, optional): If true, items are revealed in random order instead of slot order. Default: false
  * `slots` (table, optional): Per-slot configuration. Key is the slot number, value is a `SlotConfig` table:
    * `label` (string, optional): Display label for the slot placeholder
    * `image` (string, optional): Placeholder image name shown when slot is empty
    * `opacity` (number, optional): Placeholder image opacity (0.0 - 1.0)
    * `whitelist` (table, optional): Slot-level whitelist. Format: `{itemName = true, ...}`. Takes priority over inventory-level whitelist
    * `blacklist` (table, optional): Slot-level blacklist. Format: `{itemName = true, ...}`. Applied before inventory whitelist
  * `whitelist` (table, optional): Inventory-level item whitelist (used as fallback if a slot has no filter). Format: `{itemName = true, ...}`
  * `blacklist` (table, optional): Inventory-level item blacklist. Format: `{itemName = true, ...}`
  * `allowedJobs` (table, optional): Jobs allowed to access this inventory. Format: `{police = true, sheriff = true}`
  * `allowedIdentifiers` (table, optional): Character identifiers allowed to access this inventory. Format: `{charIdentifier = true, ...}`
  * `disableIncoming` (boolean, optional): If true, items cannot be transferred into this inventory by the player
  * `disableOutgoing` (boolean, optional): If true, items cannot be transferred out of this inventory by the player
  * `dropDisabled` (boolean, optional): If true, items cannot be dropped from this inventory
  * `noLimitDrag` (boolean, optional): If true, dragging ignores the amount selection dialog and moves the full stack. Used internally for shops
* `items`: table (optional)
  * Static items to add when the inventory is first created. Array format: `{{itemName, amount, metadata}, ...}`
  * Ignored if the inventory already exists in the database
* `inventoryType`: string (optional)
  * Type of inventory. Default: "stash". Other values: "player", "trunk", "glovebox"
* `metadata`: table (optional)
  * Additional metadata for the inventory

#### Returns

* `inventory`: Inventory | nil
  * The created (or existing) inventory table, or nil if creation failed
  * Structure: `{id, label, options, items, type, totalWeight, metadata}`

#### Example

```lua
-- Example: Create a loot crate with dynamic loot based on rarity
-- Don't forget to secure the event somehow depending on your use case, otherwise cheaters can simply trigger the event to get free loot
RegisterNetEvent('myresource:openLootCrate', function(rarity)
    local playerId = source
    
    -- Define loot pools based on rarity
    local lootPools = {
        common = {
            minTypes = 1,
            maxTypes = 2,
            items = {
                { name = "water",   chance = 15, min = 1, max = 3 },
                { name = "bread",   chance = 15, min = 1, max = 2 },
                { name = "bandage", chance = 10, min = 1, max = 2 },
            }
        },
        rare = {
            minTypes = 2,
            maxTypes = 4,
            items = {
                { name = "water",         chance = 10, min = 2, max = 4 },
                { name = "bread",         chance = 8,  min = 2, max = 3 },
                { name = "bandage",       chance = 8,  min = 2, max = 3 },
                { name = "lockpick",      chance = 5,  min = 1, max = 2 },
                { name = "weapon_pistol", chance = 2,  min = 1, max = 1 },
            }
        },
        legendary = {
            minTypes = 3,
            maxTypes = 5,
            items = {
                { name = "water",         chance = 8,  min = 3, max = 5 },
                { name = "bandage",       chance = 8,  min = 3, max = 4 },
                { name = "lockpick",      chance = 6,  min = 2, max = 3 },
                { name = "weapon_pistol", chance = 4,  min = 1, max = 1 },
                { name = "weapon_rifle",  chance = 2,  min = 1, max = 1 },
            }
        }
    }
    
    local selectedLoot = lootPools[rarity] or lootPools.common
    
    local inventory = exports['jaksam_inventory']:createInventory(
        nil, -- Auto generate ID
        "Loot Crate (" .. rarity .. ")", -- Dynamic label
        {
            temporary = true, -- Inventory will be lost on script restart
            maxSlots = 5,
            maxWeight = 50.0,
            disableIncoming = true, -- Items cannot be added to this inventory by the player
            prefillItems = selectedLoot,
            revealItems = {
                delayPerItem = 1000,
                randomOrder = true
            }
        },
        nil,
        'stash',
        nil
    )
    
    -- Open the inventory interface for the player
    if inventory then
        exports['jaksam_inventory']:forceOpenInventory(playerId, inventory.id)
    end
end)
```

```lua
-- Create a persistent stash with fixed starting items
local inventory = exports['jaksam_inventory']:createInventory(
    "welcome_kit_" .. charId,
    "Welcome Kit",
    { maxSlots = 5, maxWeight = 20.0 },
    {
        {"bread", 3, nil},
        {"water", 2, nil},
    },
    'stash',
    nil
)
```

#### Notes

* If `id` already exists, the existing inventory is returned as is, static `items` and `prefillItems` are NOT re-applied
* `prefillItems` uses weighted random selection **without replacement** (each item type can only be picked once)
* `prefillItems` is processed via `options`, while static `items` is a separate parameter. they serve different purposes
* Use `temporary = true` for ephemeral inventories (lootboxes, event rewards) to avoid database bloat

### forceOpenInventory

Forces an inventory to be opened for a specific player without permission checks

```lua
exports['jaksam_inventory']:forceOpenInventory(playerId, inventoryId)
```

#### Parameters

* `playerId`: number
  * The server ID of the player who will see the inventory
* `inventoryId`: string | number
  * The inventory ID to open
  * Can be a player server ID (number) or inventory ID (string)

#### Returns

This function doesn't return any value

#### Example

```lua
-- Open a stash for a player
local playerId = 1
exports['jaksam_inventory']:forceOpenInventory(playerId, 'police_stash_1')

-- Open another player's inventory (search/rob)
local targetPlayerId = 2
exports['jaksam_inventory']:forceOpenInventory(playerId, targetPlayerId)

-- Open inventory from a custom menu/UI
RegisterNetEvent('myresource:openCustomStorage', function(storageId)
    local playerId = source
    exports['jaksam_inventory']:forceOpenInventory(playerId, storageId)
end)
```

### getInventory

Gets complete data about an inventory including its items, weight limits, and metadata

```lua
exports['jaksam_inventory']:getInventory(inventoryId)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to get data for
  * Can be a player server ID (number) or inventory ID (string)

#### Returns

* `inventory`: table | nil

  * Table containing the inventory data with the following structure:

  ```lua
  {
      id = string,          -- Unique identifier of the inventory
      label = string,       -- Display name of the inventory
      type = string,        -- Type of inventory (e.g. "player", "stash", "trunk")
      options = table,      -- Inventory options and settings
      items = table,        -- Items contained in the inventory
      totalWeight = number, -- Current total weight of inventory
      limits = {
          maxSlots = number,  -- Maximum number of slots
          maxWeight = number  -- Maximum weight capacity
      },
      metadata = table      -- Additional inventory metadata
  }
  ```

#### Example

```lua
-- Get a player's inventory
local inventory = exports['jaksam_inventory']:getInventory(1) -- player with server ID 1

-- Get a stash inventory
local stashInv = exports['jaksam_inventory']:getInventory('police_stash_1')

if inventory then
    print(inventory.totalWeight) -- prints current weight
    print(inventory.limits.maxWeight) -- prints max weight allowed
    print(json.encode(inventory.items, {indent = true})) -- {["SLOT-4"] = {name = "itemName", amount = 1, metadata = {}}}
end
```

### getItemFromSlot

Gets an item from a specific slot in an inventory

```lua
exports['jaksam_inventory']:getItemFromSlot(inventoryId, slotId, returnRaw)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to get the item from
  * Can be a player server ID (number) or inventory ID (string)
* `slotId`: number
  * The slot number to get the item from

#### Returns

* `item`: table | nil

  * The item in the slot, or nil if the slot is empty
  * Item structure:

  ```lua
  {
      name = string,     -- Item name
      amount = number,   -- Item amount
      metadata = table   -- Item metadata
  }
  ```

#### Example

```lua
-- Get item from player's slot 5
local playerId = 1
local item = exports['jaksam_inventory']:getItemFromSlot(playerId, 5)

if item then
    print('Item name:', item.name)
    print('Amount:', item.amount)
    print('Metadata:', json.encode(item.metadata))

    item.metadata.durability = 50 -- update metadata
    exports['jaksam_inventory']:setItemMetadataInSlot(playerId, 5, item.metadata) -- save metadata
end

-- Get item from stash
local stashItem = exports['jaksam_inventory']:getItemFromSlot('police_stash_1', 3)
```

### getItemByName

Gets the first item found in an inventory by its name, with optional metadata filtering

```lua
exports['jaksam_inventory']:getItemByName(inventoryId, itemName, metadata)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to search in
  * Can be a player server ID (number) or inventory ID (string)
* `itemName`: string
  * The name of the item to search for
* `metadata`: table (optional)
  * Metadata to match against when searching
  * If provided, only items with matching metadata will be returned

#### Returns

* `item`: table | nil

  * The first item found matching the criteria, or nil if not found
  * Item structure:

  ```lua
  {
      name = string,     -- Item name
      amount = number,   -- Item amount in that specific slot
      metadata = table   -- Item metadata or nil
  }
  ```
* `slotId`: number | nil
  * The raw slot ID where the item was found (1-based index)
  * nil if item not found

#### Example

```lua
-- Get first bread item in player's inventory
local playerId = 1
local item, slotId = exports['jaksam_inventory']:getItemByName(playerId, 'bread')

if item then
    print('Found bread in slot:', slotId)
    print('Amount in this slot:', item.amount)
    print('Item metadata:', json.encode(item.metadata))
end

-- Get weapon with specific serial number
local weapon, weaponSlot = exports['jaksam_inventory']:getItemByName(playerId, 'WEAPON_PISTOL', {
    serial = "ABC123"
})

if weapon then
    print('Found weapon in slot:', weaponSlot)
    print('Weapon ammo:', weapon.metadata.ammo)
end
```

### getItemsByName

Gets all items from an inventory by name, with optional metadata filtering

```lua
exports['jaksam_inventory']:getItemsByName(inventoryId, itemName, metadata, strict)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to search in
  * Can be a player server ID (number) or inventory ID (string)
* `itemName`: string
  * The name of the items to search for
* `metadata`: table (optional)
  * Metadata to match against when searching
  * If provided, only items with matching metadata will be returned
* `strict`: boolean (optional)
  * Whether to match the metadata strictly (default: nil)
  * If true, all metadata fields must match exactly

#### Returns

* `items`: table

  * Array of all items found matching the criteria
  * Empty table `{}` if no items found
  * Each item in the array has the following structure:

  ```lua
  {
      name = string,     -- Item name
      amount = number,   -- Item amount in that specific slot
      metadata = table,  -- Item metadata or nil
      slot = number      -- Raw slot ID where the item was found (1-based index)
  }
  ```

#### Example

```lua
-- Get all bread items in player's inventory
local playerId = 1
local breads = exports['jaksam_inventory']:getItemsByName(playerId, 'bread')

print('Found ' .. #breads .. ' bread stacks')
for i = 1, #breads do
    local bread = breads[i]
    print('Slot ' .. bread.slot .. ': ' .. bread.amount .. ' breads')
end

-- Get all weapons with specific metadata (ammo = 0)
local weapons = exports['jaksam_inventory']:getItemsByName(playerId, 'WEAPON_PISTOL', {
    ammo = 0
})

-- Calculate total amount across all slots (export['jaksam_inventory']:getItemTotalAmount is suggested to use instead)
local totalBread = 0
local allBreads = exports['jaksam_inventory']:getItemsByName(playerId, 'bread')
for i = 1, #allBreads do
    totalBread = totalBread + allBreads[i].amount
end
print('Total bread amount:', totalBread)

-- Remove all bread from inventory
local breads = exports['jaksam_inventory']:getItemsByName(playerId, 'bread')
for i = 1, #breads do
    exports['jaksam_inventory']:removeItem(playerId, 'bread', breads[i].amount, nil, breads[i].slot)
end
```

#### Notes

* Each item includes the `slot` field indicating where it was found
* Use this when you need to process multiple stacks of the same item
* For single item lookups, prefer `getItemByName` for better performance

### getItemLabel

Gets the display label of an item

```lua
exports['jaksam_inventory']:getItemLabel(itemName)
```

#### Parameters

* `itemName`: string
  * The name of the item to get the label for

#### Returns

* `label`: string | nil
  * The display label of the item
  * nil if item doesn't exist

#### Example

```lua
-- Get item label
local label = exports['jaksam_inventory']:getItemLabel('bread')
print(label) -- prints "Bread" or whatever label is set

-- Check if item exists using label (despite this would work the best way would be to use exports['jaksam_inventory']:getStaticItem)
if not exports['jaksam_inventory']:getItemLabel('invalid_item') then
    print('Item does not exist')
end
```

### getTotalItemAmount

Returns the total amount of a specific item in an inventory, including items in containers

```lua
exports['jaksam_inventory']:getTotalItemAmount(inventoryId, itemName, metadata, skipContainers)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to check
* `itemName`: string
  * The name of the item to count
* `metadata`: table (optional)
  * Metadata to match against when counting (if provided, only items with the same metadata AND name will be counted)
* `skipContainers`: boolean (optional)
  * If true, items in containers will not be counted

#### Returns

* `totalAmount`: number
  * Total amount of the item in the inventory, including containers (only if skipContainers is false)
* `totalAmountContainersExcluded`: number | nil
  * Total amount excluding containers (only if skipContainers is false)

#### Example

```lua
-- Get total amount of bread in inventory
local total = exports['jaksam_inventory']:getTotalItemAmount(1, 'bread')

-- Get amount with specific metadata
local total = exports['jaksam_inventory']:getTotalItemAmount(1, 'weapon_pistol', {
    serial = "ABC123"
})

-- Get amount excluding containers
local total, totalNoContainers = exports['jaksam_inventory']:getTotalItemAmount(1, 'bread', nil, true)
```

### hasItem

Checks if an inventory has a specific item

```lua
exports['jaksam_inventory']:hasItem(inventoryId, itemName, quantity)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to check
* `itemName`: string
  * The name of the item to check
* `quantity`: number (optional)
  * How many items to check for
  * Default is 1

#### Returns

* `boolean`
  * true if the inventory has the item
  * false if the inventory does not have the item

#### Example

```lua
-- Check if player has 5 bread
local hasItem = exports['jaksam_inventory']:hasItem(1, 'bread', 5)

if hasItem then
    -- Safe to remove items
    exports['jaksam_inventory']:removeItem(1, 'bread', 5)
end
```

### registerUsableItem

Registers a callback function that will be called when an item is used Framework specific registering item will work anyway, as ESX.RegisterUsableItem and QBCore one

```lua
exports['jaksam_inventory']:registerUsableItem(itemName, callback)
```

#### Parameters

* `itemName`: string
  * The name of the item to register
* `callback`: function
  * Function to call when item is used
  * Parameters of callback on ESX: `playerId, itemName, inventoryItem` (`name`, `metadata`, `amount`)
  * Parameters of callback on QBCore: `playerId, inventoryItem` (`name`, `metadata`, `amount`, etc.)

#### Returns

* `success`: boolean
  * true if registration was successful

#### Example

```lua
-- Register usable item on ESX
exports['jaksam_inventory']:registerUsableItem('bread', function(playerId, itemName, inventoryItem)
    -- Heal player when bread is used
    local plyPed = GetPlayerPed(playerId)
    local health = GetEntityHealth(plyPed)
    SetEntityHealth(plyPed, math.min(health + 20, 200))
end)

-- Register usable item on ESX showing used item metadata
exports['jaksam_inventory']:registerUsableItem('armour', function(playerId, itemName, inventoryItem)
    print("Armor has still " .. inventoryItem.metadata.value .. "% of durability")
end)
```

```lua
-- Register usable item on QBCore
exports['jaksam_inventory']:registerUsableItem('armour', function(playerId, item)
    print("Armor has still " .. item.metadata.value .. "% of durability")
end)
```

### registerStash

Dynamically registers a new stash and creates its server inventory during runtime

```lua
exports['jaksam_inventory']:registerStash(options)
```

#### Parameters

* `options`: table
  * Configuration table for the stash with the following fields:
  * `id` (string, optional): Unique ID for the stash. If not provided, one will be autogenerated
  * `label` (string, **required**): Display name for the stash
  * `coords` (vector3 | table, optional): Location where the stash can be accessed via interaction point
  * `maxWeight` (number, optional): Maximum weight capacity. Default: 100
  * `maxSlots` (number, optional): Maximum number of slots. Default: 100
  * `radius` (number, optional): Distance from which players can access the stash. Default: 3.0
  * `isPrivate` (boolean, optional): If true, creates a separate inventory for each player. Default: false
  * `allowedJobs` (table, optional): Table of job names that can access the stash. If nil, stash is public. Example: `{police = true, sheriff = true}`
  * `temporary` (boolean, optional): If true, stash won't be saved to database and lost on script restart. Default: false
  * `startingItems` (table, optional): Items to add when the stash is first created. Format: `{{itemName, amount, metadata}, {itemName2, amount2, metadata2}, ...}`
  * `runtimeOnly` (boolean, optional): If true (default), stash can only be opened programmatically. If false and coords are provided, creates client-side interaction points (jaksam\_inventory will handle also stash opening point itself) Default: true

#### Returns

* `stashId`: string | nil
  * The ID of the created stash
  * nil if creation failed

#### Example

```lua
-- Create a public stash with interaction point (runtimeOnly = false)
local stashId = exports['jaksam_inventory']:registerStash({
    label = "Public Storage",
    coords = vector3(100.0, 200.0, 30.0),
    maxWeight = 500,
    maxSlots = 50,
    radius = 5.0,
    runtimeOnly = false -- Enable interaction points
})

-- Create a job-restricted stash with interaction point
local policeStashId = exports['jaksam_inventory']:registerStash({
    id = "police_evidence",
    label = "Police Evidence Locker",
    coords = vector3(450.0, -990.0, 30.0),
    maxWeight = 1000,
    maxSlots = 100,
    radius = 3.0,
    allowedJobs = {police = true, sheriff = true},
    runtimeOnly = false -- Enable interaction points
})

-- Create a programmatic-only stash (default behavior, runtimeOnly = true)
-- Players can't access it via world interaction, only through code
local hiddenStashId = exports['jaksam_inventory']:registerStash({
    id = "secret_stash",
    label = "Secret Storage",
    maxWeight = 200,
    maxSlots = 30
    -- No coords provided, accessed only programmatically
})

-- Create a private stash (each player gets their own inventory when accessing the stash)
local privateStashId = exports['jaksam_inventory']:registerStash({
    id = "luxury_apartment_stash",
    label = "Personal Safe",
    coords = vector3(300.0, 400.0, 50.0),
    maxWeight = 200,
    maxSlots = 30,
    isPrivate = true
})

-- Create a temporary stash with starting items (won't save to database)
local tempStashId = exports['jaksam_inventory']:registerStash({
    label = "Event Loot Box",
    coords = vector3(500.0, 600.0, 20.0),
    maxWeight = 100,
    maxSlots = 20,
    temporary = true,
    startingItems = {
        {"bread", 5, nil},
        {"water", 3, nil},
        {"money", 1000, nil}
    }
})

-- Create a menu-based stash (runtimeOnly = true by default)
-- Useful for custom UI/menu systems
local virtualStashId = exports['jaksam_inventory']:registerStash({
    id = "player_bank_vault",
    label = "Bank Vault",
    maxWeight = 500,
    maxSlots = 50,
    isPrivate = true
    -- runtimeOnly = true by default, accessed only programmatically
})

-- Open stash programmatically from server (e.g., from a menu or command)
RegisterCommand('openvault', function(source)
    local charId = Framework.getPlayerCharIdentifier(source)
    local stashId = "player_bank_vault_" .. charId
    exports['jaksam_inventory']:forceOpenInventory(source, stashId)
end)

-- Alternative: Open from client-side script
-- exports['jaksam_inventory']:openInventory('stashId')
```

### removeItem

Removes items from an inventory

```lua
exports['jaksam_inventory']:removeItem(inventoryId, itemName, amount, metadata, slotId)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to remove items from
  * Can be a player server ID or inventory ID
* `itemName`: string
  * The name of the item to remove
* `amount`: number
  * How many items to remove
* `metadata`: table (optional)
  * Metadata to match when removing items (if provided, only items with the same metadata AND name will be removed)
* `slotId`: number (optional)
  * Specific slot to remove items from

#### Returns

* `success`: boolean
  * true if items were removed successfully
* `resultCode`: string
  * Error message if the operation failed

#### Example

```lua
-- Remove 5 bread from player inventory
local success, result = exports['jaksam_inventory']:removeItem(1, 'bread', 5)

-- Remove specific weapon by metadata
local success, result = exports['jaksam_inventory']:removeItem(1, 'weapon_pistol', 1, {
    serial = "ABC123"
})

-- Remove from specific slot
local success, result = exports['jaksam_inventory']:removeItem(1, 'bread', 1, nil, 5)
```

### saveDirtyInventories

Saves all modified inventories to the database

```lua
exports['jaksam_inventory']:saveDirtyInventories()
```

#### Parameters

None

#### Returns

* `success`: boolean
  * true if all inventories were saved successfully

#### Example

```lua
-- Save all modified inventories
exports['jaksam_inventory']:saveDirtyInventories()

-- Good practice to save before server restart
AddEventHandler('onResourceStop', function(resourceName)
    if resourceName == GetCurrentResourceName() then
        exports['jaksam_inventory']:saveDirtyInventories()
    end
end)
```

### saveDirtyInventory

Saves a specific inventory to the database if it has been modified

```lua
exports['jaksam_inventory']:saveDirtyInventory(inventoryId)
```

#### Parameters

* `inventoryId`: string | number
  * The ID of the inventory to save

#### Returns

* `success`: boolean
  * true if inventory was saved successfully

#### Example

```lua
-- Save specific inventory
exports['jaksam_inventory']:saveDirtyInventory('police_stash_1')

-- Save player inventory after important changes
local success = exports['jaksam_inventory']:saveDirtyInventory(1)
if not success then
    print('Failed to save inventory')
end
```

### setInventoryMaxWeight

Sets the maximum weight capacity for an inventory

```lua
exports['jaksam_inventory']:setInventoryMaxWeight(inventoryId, maxWeight)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID to modify
* `maxWeight`: number
  * The new maximum weight capacity

#### Returns

* `success`: boolean
  * true if weight was set successfully

#### Example

```lua
-- Set player inventory max weight
exports['jaksam_inventory']:setInventoryMaxWeight(1, 100)

-- Set stash max weight
exports['jaksam_inventory']:setInventoryMaxWeight('police_stash_1', 500)
```

### setItemMetadataInSlot

Updates the metadata of an item in a specific inventory slot

```lua
exports['jaksam_inventory']:setItemMetadataInSlot(inventoryId, slotId, metadata)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID containing the item
* `slotId`: number
  * The slot containing the item to update
* `metadata`: table
  * The new metadata to set

#### Returns

* `success`: boolean
  * true if metadata was updated successfully
* `resultCode`: string
  * Error message if the operation failed

#### Example

```lua
-- Update weapon ammo
exports['jaksam_inventory']:setItemMetadataInSlot(1, 5, {
    serial = "ABC123",
    ammo = 6 -- update ammo count
})

-- Update item durability
exports['jaksam_inventory']:setItemMetadataInSlot(1, 3, {
    durability = 50
})
```

### setDurability

Sets the durability value of an item in a specific inventory slot

```lua
exports['jaksam_inventory']:setDurability(inventoryId, slotId, durability)
```

#### Parameters

* `inventoryId`: string | number
  * The inventory ID containing the item
  * Can be a player server ID or inventory ID
* `slotId`: number
  * The slot containing the item to update
* `durability`: number
  * The durability value to set (will be clamped between 0 and 100)

#### Returns

* `success`: boolean
  * true if durability was updated successfully
* `resultCode`: string
  * Error message if the operation failed

#### Example

```lua
-- Set weapon durability to 75%
local success, result = exports['jaksam_inventory']:setDurability(1, 5, 75)

-- Decrease durability after weapon use
local item = exports['jaksam_inventory']:getItemFromSlot(playerId, slotId)
if item and item.metadata.durability then
    local newDurability = math.max(0, item.metadata.durability - 5)
    exports['jaksam_inventory']:setDurability(playerId, slotId, newDurability)
end

-- Set durability for stash item
exports['jaksam_inventory']:setDurability('police_stash_1', 3, 100)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.jaksam-scripts.com/jaksam-inventory/functions/server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
