# Exports

> This page explains how to register and execute commands and actions from external scripts using the terminal's built-in exports.

{% tabs %}
{% tab title="Client" %}

#### addExternal(name,callback)

> Use this export to register a custom callback. It triggers whenever the terminal processes an action with a matching callback value.
>
> **Parameters**
>
> * **name**:`string` Action name, should match the field callback from a server side action.
> * **callback**: `function(data)` Callback to perform
>
> **Return**
>
> * **success**:`boolean` true will allow the command to execute the following actions, false will stop everything and print the failure action.

#### addSuccess(command, callback)

> Use this export to register a onSuccess callback to trigger when a command is completed successfully.
>
> **Parameters**
>
> * **command**:`string` Must be an existing command.
> * **callback**:`function(data)` Callback to perform

#### terminal(action)

> Triggers an array of actions within the terminal, adhering to the format specified in [Terminal](/laptop-pack-v3/laptop-v3/terminal.md)
>
> ```lua
> local actions = {
>     {
>         type = "text",
>         input = "No vehicle found nearby.",
>         style = "error",
>         delay = 0
>     }
> }
> exports['av_laptop']:terminal(actions)
> ```

{% endtab %}

{% tab title="Server" %}

#### addCommand(settings)

> Use this exports server side to register a new command for Terminal.
>
> **Parameters:**
>
> * **command**:`string` Command name, needs to be unique.
> * **show**:`boolean` Makes the command visible for player when using /help command.
> * **allowed**: `function(playerId, laptopSerial)` Should return a boolean, gets triggered when command /help is used and field show is true, is an extra layer where you can run custom code to restrict command access.
> * **canProcess**: `function(playerId, laptopSerial, args)` Should return a boolean, gets triggered when player uses command, use it to verify if the arguments are valid or if the player have X item, etc.
> * **onSuccess**: `function(playerId, laptopSerial, args)` Should return a boolean, triggered when all actions are completed successfully.
> * **actions**:`table` A table with all actions to perform in terminal.
> * **output?**:`table` A final action we can use to display text on terminal if all actions were completed successfully.
>
> **An example running this command can be found below.**
> {% endtab %}
> {% endtabs %}

#### Keyfob Example

This example script registers the `keyfob` command to execute a sequence of actions, demonstrating how to:

* Trigger 3 custom client-side callbacks (`demo:validate`, `demo:getClosest`, and `demo:processKeys`).
* Use the `userInput` action type to pause the sequence and capture the vehicle's SSID.
* Reward the player with the vehicle keys once the entire action sequence is successfully completed.

<figure><img src="/files/owkrjo8XFAlvuS3si5YU" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="client.lua" %}

```lua
local temp_ids = {}
local temp_vehicle = nil

CreateThread(function()
    while not GetResourceState('av_laptop') == 'started' do
        Wait(100)
    end
    exports['av_laptop']:addExternal("demo:validate", validateInput)
    exports['av_laptop']:addExternal("demo:getClosest", getClosest)
    exports['av_laptop']:addExternal("demo:processKeys", processKeys)
end)

function getClosest()
    local data = {}
    local playerCoords = GetEntityCoords(cache.ped)
    local vehicles = lib.getNearbyVehicles(playerCoords, 10.0)
    for _, v in pairs(vehicles) do
        local veh = type(v) == "table" and (v.vehicle or v.entity) or v
        local plate = GetVehicleNumberPlateText(veh)
        local modelName = exports['av_laptop']:getVehicleName(GetEntityModel(veh))
        local distance = #(playerCoords - GetEntityCoords(veh))
        local cleanModel = string.gsub(modelName, "%s+", "")
        local ssid = string.format("%s_0x%03X", string.upper(string.sub(cleanModel, 1, 6)), math.random(256, 4095))
        temp_ids[ssid] = {
            vehicle = veh,
            plate = plate,
            model = modelName,
            ssid = ssid,
            distance = distance
        }
        table.insert(data, {
            plate,
            modelName,
            ssid,
            string.format("%.1fm", distance)
        })
    end
    if #data == 0 then
        exports['av_laptop']:terminal({
            {
                type = "text",
                input = "No vehicle found nearby.",
                style = "error",
                delay = 0
            }
        })
        return false
    end
    exports['av_laptop']:terminal({
        {
            type = "table",
            columns = {"PLATE", "MODEL", "SSID", "DISTANCE"},
            rows = data,
            delay = 0
        },
    })
    return true
end

function validateInput(args)
    if not args then return false end
    local targetSSID = args['extraData']
    if not targetSSID then
        print("No target ssid provided in args")
        return false
    end
    if temp_ids[targetSSID] then
        temp_vehicle = temp_ids[targetSSID] and temp_ids[targetSSID].vehicle or nil
        if not temp_vehicle then
            print("Vehicle associated with SSID not found, it might have been deleted or gone out of range")
            return false
        end
        local dist = #(GetEntityCoords(cache.ped) - GetEntityCoords(temp_vehicle))
        if dist > 11.0 then
            exports['av_laptop']:terminal({
                {
                    type = "text",
                    input = "Vehicle is too far away.",
                    style = "error",
                    delay = 0
                }
            })
            return false
        end
        return true
    else
        print("Provided SSID does not match any temporary IDs")
        return false
    end
end

function processKeys()
    print("processKeys() called, temp_vehicle:", temp_vehicle)
    if not temp_vehicle then
        print("No vehicle set for processing keys or it got deleted (?)")
        return false
    end
    local plate = GetVehicleNumberPlateText(temp_vehicle)
    TriggerEvent('qb-vehiclekeys:client:AddKeys', plate) -- default qb-vehiclekeys event for giving keys
    return true
end
```

{% endtab %}

{% tab title="server.lua" %}

```lua
local test_command = {
    command = "keyfob", -- command to use in terminal
    show = false, -- Set to true if you want the command to be visible in the terminal command list
    allowed = function(playerId, laptopSerial)
        return true
    end,
    onSuccess = function()
        return true
    end,
    canProcess = function(playerId, laptopSerial, args)
        return true
    end,
    actions = {
        {type = "text", input = "Mounting radio interface...", delay = 800},
        {type = "progressbar", input = "Scanning local frequency spectrum", delay = 3500},
        {type = "text", input = "Filtering encrypted broadcasts...", delay = 800},
        {type = "external", callback = "demo:getClosest"}, -- This action will trigger our client event to get the closest SSID and return it to the next action
        {type = "userInput", input = "Enter target SSID:", color = "yellow", delay = 500, external = "demo:validate"},
        {type = "text", input = "Target isolated. Intercepting data packets...", color = "var(--accent)", delay = 800},
        {type = "progressbar", input = "Synchronizing hardware handshake", delay = 4000},
        {type = "text", input = "Payload captured. Executing decryption protocol...", delay = 500},
        {type = "minigame", input = "sniffer", label = "FOB_CLONING.EXE", delay = 0},
        {type = "external", callback = "demo:processKeys"}
    },
    output = {
        message = "SUCCESS: Keyfob signal cloned.",
        color = "green"
    }
}

CreateThread(function()
    while not GetResourceState('av_laptop') == 'started' do
        Wait(100)
    end
    local added, msg = exports['av_laptop']:addCommand(test_command)
    print("Adding terminal command:", added, msg)
end)
```

{% endtab %}

{% tab title="fxmanifest.lua" %}

```lua
fx_version 'cerulean'
description 'AV Example'
author 'Avilchiis'
version '1.0.0'
lua54 'yes'
games {
'gta5'
}

shared_scripts {
'@ox_lib/init.lua',
}

client_scripts {
'client.lua',
}

server_scripts {
'server.lua'
}

dependencies {
    'ox_lib',
}
```

{% endtab %}
{% endtabs %}


---

# 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://docs.av-scripts.com/laptop-pack-v3/laptop-v3/terminal/exports.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.
