> For the complete documentation index, see [llms.txt](https://docs.timecord.dev/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.timecord.dev/docs/guide/script.md).

# Script

The TimeCord script tracks time automatically from your game server, so players do not have to press a button in Discord. When a player comes on duty their linked Discord account is clocked in, and when they go off duty it is clocked out.

The current script is written in Lua for **FiveM** and supports the **ESX** framework.

{% hint style="info" %}
Are you a good qbcore scripter and want to help us translate the script to qbcore? Get in touch on our [Discord](https://discord.gg/Jsd9YnJWQw).
{% endhint %}

### How it works

The script listens for the ESX `esx:playerLoaded` and `esx:playerDropped` events. When one fires, it reads the player's ESX **job**, looks up the API key you configured for that job, and sends an HTTP request to TimeCord, which handles the rest. TimeCord matches the player to their Discord account and clocks them in or out. In short: coming on duty clocks in, leaving clocks out.

### Download

Get the script here: [github.com/DanielLogisch/timecord\_esx\_script](https://github.com/DanielLogisch/timecord_esx_script)

### Requirements

You need the **Node.js runtime** on the game server to install the script's dependencies.

* Windows: download the installer from [nodejs.org](https://nodejs.org/en/download) and run it.
* Linux: follow [this guide](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04).

### Installation

#### Windows

1. Go to your FXServer `resources` folder and unzip the script as a new folder.
2. Run `windows_setup.bat` to install the needed dependencies automatically.
3. Enable autostart by adding this to your `server.cfg`:

```
ensure timecord_esx_script-master
```

#### Linux

1. Go to your FXServer `resources` folder, create a new folder, and paste the script source there.
2. Go to the script path.
3. Make the setup script executable: `chmod +x linux_setup.sh`
4. Run it: `./linux_setup.sh`
5. Update your `server.cfg` to enable autostart.

### Importing the ESX object

Newer ESX versions import the shared object differently. If you are on a newer version, update the script accordingly:

```javascript
// Old ESX object import
let ESX;
emitNet('esx:getSharedObject', (obj) => { ESX = obj })

// New ESX object import
const ESX = exports["es_extended"].getSharedObject();
```

### Configuration

TimeCord ties an **API key to each job**. Map job names to keys in the script config:

```json
// BASIC EXAMPLE
"api": {
    "police": "2c76b58e-fa2c-4a84-b9a9-fa79cd305864",
    "ambulance": "1c76258e-fa2c-4a84-b9a9-fa79cd305841"
}
```

The **key** is the exact job name as it appears in your database, so the script can check whether a player has that job. The **value** is the API key for the server your bot runs on. Generate keys in the dashboard under **Settings -> Script**. You can add as many jobs as you like, and only the jobs you list here are tracked.

{% hint style="warning" %}
In the dashboard's script settings, make sure the **IP address of your game server** is configured, otherwise requests are rejected. And never share your API key.
{% endhint %}

### Custom duty event

If your server has an on/off-duty system where players toggle duty without leaving the server, use the custom event to clock them in or out. Pass `true` to clock in and `false` to clock out.

```lua
-- Note that this is a server / client event.
-- Protect the event so players cannot spam it, or you will get an API ban.

-- LUA CLIENT
TriggerServerEvent('timecord:dutyTrigger', playerId, true)  -- clock in
TriggerServerEvent('timecord:dutyTrigger', playerId, false) -- clock out

-- LUA SERVER
TriggerEvent('timecord:dutyTrigger', playerId, true)  -- clock in
TriggerEvent('timecord:dutyTrigger', playerId, false) -- clock out

-- JS CLIENT
emitNet('timecord:dutyTrigger', playerId, true)  -- clock in
emitNet('timecord:dutyTrigger', playerId, false) -- clock out

-- JS SERVER
emit('timecord:dutyTrigger', playerId, true)  -- clock in
emit('timecord:dutyTrigger', playerId, false) -- clock out
```

### Troubleshooting

* **`esx:playerDropped` not firing.** Some servers report this event misbehaving, which can leave a session open. It may be overwritten by your ESX setup or another resource. Work around it by removing `onNet('esx:playerDropped')` from the script and replacing it with your own custom event, or by using the FiveM `playerDropped` event instead.
* **A job is not being tracked.** Confirm the job name in the config exactly matches the ESX job name, and that the API key for it is valid in your dashboard.
* **Forgotten sessions.** If a clock-out is ever missed, TimeCord's automatic clock-out closes sessions that stay open too long (see [Statistics & Time](/docs/guide/statistics-and-time.md#automatic-clock-out-forgotten-shifts)).

Need help writing or extending a script? Open a ticket on our [Discord](https://discord.gg/Jsd9YnJWQw).
