# Developer > Developer API reference for ML Terminal System Category: TERMINAL SYSTEM · Source: https://miciomods.it/docs/ml-terminal-system-developer · Last updated: 2026-07-05 ## Overview All integration hooks live in the `open/` folder. These files are never escrowed and can be freely modified. The system also exposes server-side functions and custom events for external integrations. ## Server Handlers Located in `open/server.lua`. ### Item Distribution **open/server.lua** ```lua function OpenServer.BeforeGiveItem(src, item, amount) -- Return false to block the item from being given return true end ``` Called before the system gives a reward item (from quiz profiles or crafting). Return `false` to block. ### Action Completion **open/server.lua** ```lua function OpenServer.OnActionComplete(src, actionType, data) -- actionType is the executed action's trigger type ('client' or 'server') -- data = { terminalId, actionId, event, args } end ``` Fires after an action-panel button executes successfully. Use it for XP, battle-pass progress, or auditing. ## Client Handlers Located in `open/client.lua`. ### UI Access Control **open/client.lua** ```lua function OpenClient.BeforeOpenUI(data) -- Return false to prevent the terminal UI from opening return true end ``` ## Action Panel Integration The `actions` app type triggers custom events on your server or client. Your external script just registers the handler: **Server-Side Action Handler** **your_script/server.lua** ```lua RegisterNetEvent('myScript:lockdown', function(args) local level = args.level -- Lock all doors, trigger alarm, etc. end) ``` **Client-Side Action Handler** **your_script/client.lua** ```lua RegisterNetEvent('myScript:triggerAlarm', function(args) local zone = args.zone -- Play alarm sound, flash screen, etc. end) ``` ## Quiz Gating Apps of type `locked_folder` can be gated behind quiz completion: - `requireQuiz = true`: Requires ANY quiz on this terminal to be completed - `requireQuiz = 'quiz_id'`: Requires a SPECIFIC quiz to be completed - `requiredProfile = 'tactician'`: Requires a specific profile result from the quiz ## Quiz Rewards When a player confirms their profile, rewards are distributed automatically: - `money`: Cash via Bridge - `items`: Items via Bridge (array of `{ name, amount }`) - `vehicle`: Registers a vehicle (`{ name = "model" }`) to the player using `Config.Vehicles` settings - `job`: Sets the player's job via Bridge (`{ name, grade }`) ## Server Exports `GetGoatProfile(identifier, terminalId)` returns the quiz profile id a player was assigned on a terminal, or `nil` if they have not completed it. Reads from cache, falls back to the database. **your_script/server.lua** ```lua local profile = exports.ml_terminal_system:GetGoatProfile(identifier, 'my_terminal') if profile == 'tactician' then -- grant tactician perks end ``` - `identifier`: the framework player identifier (from `Bridge.GetPlayerId(src)`) - `terminalId`: the base terminal ID (without any `_locN` suffix) ## Config Validation All terminal configs are validated at startup via `Config.ValidateAll()`. A failure logs a descriptive [ERROR] for that terminal. Validated fields: - `label`: Required - `model`: Required - `coords` or `locations`: At least one required - `apps[].name` and `apps[].type`: Required per app - Quiz questions/profiles are NOT validated here, they merge from `config_questions.lua` by terminal ID at startup. - `kiosk.mode` and `kiosk.app`: Required if kiosk section exists