Integration
What another resource can ask tCAD to do, what tCAD asks of you, and what it does not integrate with — no ESX or QBCore code, no inventory, no phone, and no billing.
tCAD integrates in exactly two directions, and it is worth being clear about both before you plan around it.
| Direction | Mechanism |
|---|---|
| Another resource → tCAD | exports.tCAD:* — 17 server-side exports |
| tCAD → your server | The eight hooks in config/ |
What tCAD needs from your framework, and where you supply it
Two things, both optional, both one hook:
| You want | Hook | File |
|---|---|---|
| Character names instead of Steam names | Config.displayName | config/sv_functions.lua |
| Your own callsign scheme | Config.formatCallsign | config/sv_functions.lua |
Both have worked examples for ESX and QBCore written into the file as comments. Neither is required: without them, tCAD uses the player's FiveM name and accepts whatever callsign they type.
That is genuinely the whole list. tCAD does not need your framework for jobs, for money, for inventory or for identity — it keys records by the player's licence identifier and resolves authority through ACE, which every framework leaves intact.
Permissions, if your framework owns them
Config.acePermission and every key in Config.permissions is answered through tLib's permission adapter, which passes the key to IsPlayerAceAllowed. If you have registered a framework resolver with tLib, that resolver answers instead, and tCAD needs no change — it never calls IsPlayerAceAllowed itself.
Without a resolver, grants are add_ace lines in server.cfg. See Permissions.
Pushing a call in from a phone or a radio
The common case. A civilian dials 911 in a phone resource, and the call should land on the dispatch board.
Use report911, not createCall. createCall requires the actor to hold tcad.calls.create, which a civilian does not and must not — report911 is the bounded path built for exactly this, and it answers a distinct disabled code if the server has switched it off, so your resource can tell "turned off" from "try again".
Reading the board out
A radio or AI-dispatcher resource that wants to know who is working and what is outstanding:
| Question | Export |
|---|---|
| Is the CAD up yet? | isReady — your consumer's first line |
| Who is on duty? | getOnDutyUnits, or getUnit for one player |
| What is outstanding? | getOpenCalls, then getCall for one |
| One sentence about a unit, to read on the air | getUnitNote |
| Send a unit to a call / clear them | attachUnit, detachUnit |
| Close a call | closeCall |
Taking an action off tCAD
The three event hooks fire after the change is written and pushed, and are side-effects only:
| Hook | Fires on |
|---|---|
Config.onCallEvent | a call created, re-prioritised, status-changed, held, released, cancelled or closed |
Config.onUnitEvent | a unit going on duty, going off duty, or changing status |
Config.onWarrantEvent | a warrant created, approved, denied, served or recalled |
The obvious thing to build on these is a Discord relay. Read what the hooks deliberately withhold before you do — the payloads are narrowed by allowlist specifically so that the five-line version of that relay cannot publish a civilian's identifiers by accident.
Replacing the in-world notice
Config.onAssignmentNotice in config/cl_functions.lua replaces the toast a unit gets when they are assigned, so ox_lib, a custom HUD or a radio tone can own it instead. Return false to suppress the shipped one.
⛔ What tCAD does not integrate with
Named plainly, because each of these is something a server owner reasonably assumes a CAD does.
| ESX / QBCore / any framework | No framework code, no integration file, no detection. Two optional hooks, as above |
| Inventory resources | Nothing. A warrant does not seize anything and an impound flag moves no item |
| Billing / fines | Nothing. There is no citation or fine record, and nothing debits a player |
| MDT or phone resources | No first-party integration. The export surface is how one would be built, by whoever builds it |
| Jail / prison resources | Nothing. A warrant has a status, not a sentence that executes |
| Discord roles | No role sync. Permissions are ACE, or your tLib resolver |
| A plate reader | The manual NCIC plate lookup exists. Automatic plate-reader hits do not — nothing produces them, and the tab that would show them is a placeholder |
| A browser or desktop client | Config.exposeWeb exists and there is no surface behind it. See Status |
What another resource must not do
- Do not call an operation name directly over the net event. The transport is tCAD's own and its operation registry is internal: names there are not API and change without notice. The seventeen exports are the API, and that is the whole reason there is no generic passthrough.
- Do not store a server id. It is a connection slot and it is reused. Records are keyed by the licence identifier, and tCAD resolves that itself.
- Do not assume
lat/lngare degrees. On every unit projection,latis the GTA world Y andlngthe world X, in metres. Swapping them is silent at every layer — the result is a marker in the sea and nothing raises.
Was this page helpful?
TIMMYG Studios