> For the complete documentation index, see [llms.txt](https://documentation.rcore.cz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.rcore.cz/paid-resources/rcore_police/api/server.md).

# Server

Server-side events and exports exposed by `rcore_police`. Call them from other resources running on the same server.

## 📡 Events

<details>

<summary>rcore_police:server:SetBodyCamState</summary>

Registers a **server-side event** to manually control a player's bodycam state, typically used in scenarios such as **temporary permission overrides** or **anti-cheat bypasses**.

```lua
---@param playerId number - target playerId which you want to set permission
---@param state boolean - used for listening for player state

AddEventHandler('rcore_police:server:SetBodyCamState', function(playerId, state)
    -- REGISTER PLAYER TEMP PERMISSION
end)
```

</details>

## 👂 Listeners

<details>

<summary>onGroups</summary>

Used for listening for any `onGroups` actions.

```lua
---@param listenerName string - name of the listener to register for onGroups events
---@return string type - current action/task being done
---@return table data - the data of player in that group

exports["rcore_police"]:registerListener("onGroups", function(type, data)
    print("Received 'onGroups' event:")
    print("Type:", type)
    print("Data:", json.encode(data))
end)
```

</details>

<details>

<summary>onState</summary>

Used for listening for any interaction actions on players.

```lua
---@param listenerName string - name of the listener to register for onState events
---@return string type - current type
---@return string action - current action
---@return number playerId - player the state change was performed on

exports["rcore_police"]:registerListener("onGroups", function(type, action, playerId)
    print("Received 'onState' event:")
    print("Type:", type)
    print("Action:", action)
    print("Player ID:", playerId)
end)
```

</details>

## 🔍 Player State

<details>

<summary>IsPlayerCuffed</summary>

```lua
---@param playerId number - ID of player which you want to get state of cuffed
---@return boolean isCuffed

local isCuffed = exports['rcore_police']:IsPlayerCuffed(playerId)

if isCuffed then
    print('Player is cuffed')
else
    print('Player is not cuffed')
end
```

</details>

<details>

<summary>IsPlayerEscorted</summary>

```lua
---@param playerId number - ID of player which you want to get state of escort
---@return boolean isEscorted

local isEscorted = exports['rcore_police']:IsPlayerEscorted(playerId)
```

</details>

<details>

<summary>IsPlayerHeadBagged</summary>

```lua
---@param playerId number - ID of player which you want to get state of head bag
---@return boolean isHeadBagged

local isHeadBagged = exports['rcore_police']:IsPlayerHeadBagged(playerId)
```

</details>

## ⚡ Actions

<details>

<summary>JailPlayer</summary>

Opens a dialog form to put the specific player in jail.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to get jailed
---@return boolean isJailed
---@return string statusOrErr

local isJailed, statusOrErr = exports['rcore_police']:JailPlayer(playerId, target)
```

</details>

<details>

<summary>SearchPlayer</summary>

Opens the target player's inventory for searching.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to search inventory
---@return boolean isSearched
---@return string statusOrErr

local isSearched, statusOrErr = exports['rcore_police']:SearchPlayer(playerId, target)
```

</details>

<details>

<summary>Escort</summary>

Sets/unsets escort on the target player.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to get escorted
---@return boolean isEscorted
---@return string statusOrErr

local isEscorted, statusOrErr = exports['rcore_police']:Escort(playerId, target)
```

</details>

<details>

<summary>Zipties</summary>

Sets/unsets zip ties on the target player.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to set zipties
---@return boolean isZiptied
---@return string statusOrErr

local isZiptied, statusOrErr = exports['rcore_police']:Zipties(playerId, target)
```

</details>

<details>

<summary>Handcuff</summary>

Sets/unsets handcuffs on the target player.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to set handcuffs
---@return boolean isCuffed
---@return string statusOrErr

local isCuffed, statusOrErr = exports['rcore_police']:Handcuff(playerId, target)
```

</details>

<details>

<summary>PutPlayerInVehicle</summary>

Puts the target player into the closest vehicle seat.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to put into vehicle
---@return boolean isInVehicle
---@return string statusOrErr

local isInVehicle, statusOrErr = exports['rcore_police']:PutPlayerInVehicle(playerId, target)
```

</details>

<details>

<summary>TakePlayerFromVehicle</summary>

Takes the target player out of the closest vehicle.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to get from vehicle
---@return boolean isFromVehicle
---@return string statusOrErr

local isFromVehicle, statusOrErr = exports['rcore_police']:TakePlayerFromVehicle(playerId, target)
```

</details>

<details>

<summary>RemoveHandcuff</summary>

Removes handcuffs/zip ties from the target player.

```lua
---@param playerId number - ID of player which is starting the interaction
---@param target number - ID of player which you want to remove handcuffs/zipties
---@return boolean isRemovedCuffs
---@return string statusOrErr

local isRemovedCuffs, statusOrErr = exports['rcore_police']:RemoveHandcuff(playerId, target)
```

</details>

<details>

<summary>ForceUncuff</summary>

Force-removes zip ties/handcuffs from the target player.

```lua
---@param target number - ID of player which you want to remove handcuffs/zipties
---@return boolean isRemovedCuffs
---@return string statusOrErr

local isRemovedCuffs, statusOrErr = exports['rcore_police']:ForceUncuff(target)
```

</details>

## 👮 General

<details>

<summary>GetPoliceOnline</summary>

```lua
---@return number policeOnline - defaults to 0 when none are online

local policeOnline = exports['rcore_police']:GetPoliceOnline()
```

</details>

<details>

<summary>CreateInvoiceByServer</summary>

{% hint style="warning" %}
This export is **not** a replacement for your invoice system. It is a hook over the rcore\_police invoice system when using the standalone bridge or a supported invoice system.
{% endhint %}

{% hint style="info" %}
The distribution of invoice payments depends on the `InvoiceSystem.WhenInvoiceSentBalanceToAllDepartmentJobs` setting in your config:

* `true`: the invoice amount is split equally among all department society accounts.
* `false`: only the issuing job's society account receives the money.
  {% endhint %}

Creates an invoice for a player directly from the server-side (e.g., for automated billing systems, admin commands, or integration with other resources).

```lua
---@param targetId number - player ID of the user who should receive the invoice
---@param amount number - the amount the player should pay
---@param metadata table - additional data: { job?: string, reason: string }
---@return boolean success

-- Basic usage: Issue a speeding ticket
local success = exports["rcore_police"]:CreateInvoiceByServer(targetPlayerId, 500, {
    job = "police",
    reason = "Speeding violation - 120 km/h in a 50 km/h zone"
})
```

`metadata.job` must be a valid department group defined in your configuration with an existing society account. If not provided, all department groups are used or it defaults to `"police"`.

```lua
-- Example: Admin command to issue a fine
RegisterCommand("issuefine", function(source, args, rawCommand)
    local targetId = tonumber(args[1])
    local amount = tonumber(args[2])
    local reason = table.concat(args, " ", 3)

    if not targetId or not amount or not reason then
        print("Usage: /issuefine [playerId] [amount] [reason]")
        return
    end

    local success = exports["rcore_police"]:CreateInvoiceByServer(targetId, amount, {
        job = "police",
        reason = reason
    })

    if success then
        print(string.format("Fine of $%d issued to player %d for: %s", amount, targetId, reason))
    else
        print("Failed to issue fine")
    end
end, true) -- restricted to admins
```

</details>

## 📹 Bodycam

<details>

<summary>GetBodyCamPlayers</summary>

```lua
---@return table retval         -- array of active bodycam players
---@return string statusCode    -- "OK" | "EMPTY"

local retval, statusCode = exports["rcore_police"]:GetBodyCamPlayers()

if statusCode == "OK" then
    for _, bodycam in ipairs(retval) do
        print("Officer:", bodycam.officerName, "ID:", bodycam.playerId)
    end
end
```

Return structure:

```lua
{
    [1] = {
        playerId = 1,                    -- Server player ID
        playerCoords = vector3(x, y, z), -- Player coordinates
        officerName = "John Doe",        -- Character name
        location = ""                    -- Location string
    },
    [2] = { ... }
}
```

</details>

<details>

<summary>SpectateBodycam</summary>

```lua
---@param playerId number        -- player who will spectate
---@param officerPlayerId number -- officer with active bodycam
---@return boolean retval        -- success state
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID" | "INVALID_OFFICER_ID" | "SAME_PLAYER" | "NO_ACTIVE_BODYCAM"

local retval, statusCode = exports["rcore_police"]:SpectateBodycam(playerId, officerPlayerId)
```

</details>

<details>

<summary>ActivateOfficerBodycam</summary>

Toggles bodycam state (activates if inactive, deactivates if active).

```lua
---@param playerId number -- officer player ID

exports["rcore_police"]:ActivateOfficerBodycam(playerId)
```

</details>

<details>

<summary>DeactivateOfficerBodycam</summary>

Toggles bodycam state (activates if inactive, deactivates if active).

```lua
---@param playerId number -- officer player ID

exports["rcore_police"]:DeactivateOfficerBodycam(playerId)
```

</details>

## 🤼 Tackle

<details>

<summary>GetActiveTackles</summary>

```lua
---@return table retval         -- tackle registry table
---@return string statusCode    -- "OK" | "EMPTY"

local retval, statusCode = exports["rcore_police"]:GetActiveTackles()

if statusCode == "OK" then
    for tackleId, tackle in pairs(retval) do
        print("Tackle #" .. tackleId .. ": Cop " .. tackle.initiator .. " tackling " .. tackle.target)
    end
end
```

Return structure:

```lua
{
    [1] = {
        initiator = 1,           -- Server player ID of the cop doing the tackle
        target = 2,              -- Server player ID of the person being tackled
        startTime = 123456789    -- GetGameTimer() when tackle started
    },
    [2] = { ... }
}
```

</details>

<details>

<summary>IsTackled</summary>

```lua
---@param playerId number        -- player ID to check
---@return boolean retval        -- is player tackled
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID"

local retval, statusCode = exports["rcore_police"]:IsTackled(playerId)
```

</details>

<details>

<summary>GetPlayerTackleInfo</summary>

```lua
---@param playerId number        -- player ID to get info for
---@return table|nil retval      -- tackle info object
---@return string statusCode     -- "OK" | "INVALID_PLAYER_ID" | "NOT_TACKLED" | "TACKLE_NOT_FOUND"

local retval, statusCode = exports["rcore_police"]:GetPlayerTackleInfo(playerId)

if retval then
    print("Role:", retval.role)
    print("Initiator:", retval.initiator)
    print("Target:", retval.target)
    print("Duration:", GetGameTimer() - retval.startTime, "ms")
end
```

Return structure:

```lua
{
    tackleId = 1,            -- Unique tackle identifier
    role = "initiator",      -- "initiator" (cop) or "target" (tackled player)
    initiator = 1,           -- Server player ID of the cop doing the tackle
    target = 2,              -- Server player ID of the person being tackled
    startTime = 123456789    -- GetGameTimer() when tackle started
}
```

</details>

<details>

<summary>RemoveTackleByPlayer</summary>

```lua
---@param playerId number          -- player ID to remove tackle for
---@param skipClientReset? boolean -- skip sending client reset events
---@return boolean retval          -- success state
---@return string statusCode       -- "OK" | "INVALID_PLAYER_ID" | "NOT_TACKLED" | "TACKLE_NOT_FOUND"

local retval, statusCode = exports["rcore_police"]:RemoveTackleByPlayer(playerId)
```

</details>
