Skip to content

Tool to endpoint map

Useful for three things: sizing the read-only API profile you grant, reading a FortiGate’s own API audit log and recognizing what produced each line, and knowing which questions are cheap and which are not.

ToolEndpoints
get_system_statuscmdb/system/global, plus monitor/system/status and monitor/system/resource/usage
list_address_objectscmdb/firewall/address
list_address_groupscmdb/firewall/addrgrp
list_servicescmdb/firewall.service/custom
list_policiescmdb/firewall/policy
list_vipscmdb/firewall/vip
list_interfacescmdb/system/interface
list_vlanscmdb/system/interface
list_static_routescmdb/router/static, plus cmdb/firewall/address when any route names an address object
ToolEndpoints
get_routing_tablemonitor/router/ipv4
list_dhcp_leasesmonitor/system/dhcp
get_arp_tablemonitor/network/arp
list_wifi_clientsmonitor/wifi/client, monitor/system/dhcp, monitor/network/arp
find_devicemonitor/wifi/client, monitor/system/dhcp, monitor/network/arp
find_referencesmonitor/system/object/usage for the verdict, plus five cmdb reads for detail — see below

Two tools are worth more than one REST call each by design, because the question they answer spans object types that FortiOS keeps apart.

find_references is the heaviest, and it works in two layers.

The authoritative layer is monitor/system/object/usage, which is the endpoint the web UI’s reference counter calls. It knows every table FortiOS tracks references in — 234 of them for a system interface on 7.0.14 — and it is what the verdict and the references list come from.

Reaching it takes one more step than you would expect. The endpoint is asked about an object within a named table, and asking the wrong table is not an error: query firewall/address about a name that is really an interface and FortiOS answers HTTP 200 with an empty list. So the tool first resolves what kind of object the name is by reading its defining cmdb table, and only then asks about usage. That resolution is reported back as resolved_as.

The detail layer is the same five cmdb reads as before — cmdb/firewall/policy, cmdb/firewall/addrgrp, cmdb/firewall.service/group, cmdb/firewall/vip, cmdb/router/static — kept because they carry readable detail the usage endpoint does not, such as a policy’s name and action. They are no longer the source of the verdict, only of the annotations on it.

One counting trap lives here: every currently_using row comes back with reference_count: 0, including rows that are genuine references. The row’s existence is the signal. Summing that field reports zero for an object with two references.

search_config issues six by default: cmdb/firewall/address, cmdb/firewall/addrgrp, cmdb/firewall.service/custom, cmdb/system/interface, cmdb/router/static, and cmdb/firewall/policy. Passing include_policies: false drops the last one, which on a large appliance is most of the transferred bytes.

list_targets makes no calls at all. It reports what the server was configured with, not what it can currently reach, so it answers instantly and also answers when every appliance is unreachable.

The monitor tree varies by platform and firmware in ways the configuration tree does not. A FortiGate with no wireless hardware has no monitor/wifi/client at all; some endpoints appear only above a given firmware version.

Monitor reads therefore carry a status alongside their rows rather than returning a bare list:

StatusCauseTreated as
okHTTP 200Data
unsupportedHTTP 404 or 405Absence, safe to carry on
deniedHTTP 401 or 403A permissions problem, reported
errorAny other status, or a transport failureA failure, reported

Only unsupported is treated as nothing there. That is what lets find_device keep working on a wired-only appliance while a denied read still gets surfaced instead of quietly reading as an empty network.

Configuration reads do not degrade at all — any status other than 200 raises.

The client library’s connector does the equivalent of if not response.ok: return []. Every 401, 403, 404, and 500 arrives as an empty list, with no exception and no status. So api.cmdb.*.get() is not used anywhere in this package; reads go through helpers that check status first and normalize the results payload afterwards.

The same helper also handles a second library problem. FortiOS returns a list for table endpoints and a bare object for singular ones such as system/global, and the library coerces with list() — which on an object yields its keys as strings, so callers receive a list of meaningless strings rather than a record.

FortiOS answers many user-fixable mistakes with HTTP 500 and a body like:

{ "status": "error", "error": -23, "cli_error": "..." }

rather than with a 4xx. Losing that body turns a diagnosable problem into a silent no-op, so the HTTP status and the FortiOS error code are kept as attributes on the raised error rather than only as text, which is what lets a partially-failed tool report denied: http=403 in sources_checked without parsing an error message back apart.

Every endpoint above is read with GET. A read-only administrator profile with read access to System, Firewall, Router, and Network — plus Wi-Fi if the appliance has radios — covers the whole tool surface. Nothing needs write access anywhere, and granting it would not enable any additional tool, because there is no write path in the codebase to reach.