UniFi API Explorer
Mix.install([
{:unifi, path: Path.join(__DIR__, ".")},
{:kino, "~> 0.18.0"}
])
Setup
Configure the API clients. Set UNIFI_LOCAL_API_KEY in your environment before starting Livebook.
req = UniFi.Script.local_client()
legacy = UniFi.Script.legacy_client()
sys = UniFi.Script.system_client()
site_id = UniFi.Script.first_site_id(req)
Kino.Markdown.new("✅ Clients configured, site: `#{site_id}`")
System Info
Console-level information from the UniFi OS system API.
{:ok, %{status: 200, body: info}} = UniFi.Network.System.info(sys)
rows = for {k, v} <- Enum.sort(info), do: "| `#{k}` | `#{inspect(v)}` |"
"""
| Key | Value |
|-----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Application Info
The Network application version running on the console.
{:ok, %{status: 200, body: body}} = UniFi.Network.Info.get(req)
rows = for {k, v} <- Enum.sort(body), do: "| `#{k}` | `#{inspect(v)}` |"
"""
| Key | Value |
|-----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Sites
Local sites managed by this controller.
{:ok, %{status: 200, body: %{"data" => sites}}} = UniFi.Network.Sites.list(req)
rows = for s <- sites, do: "| `#{s["id"]}` | #{s["name"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Adopted Devices
All UniFi devices adopted on this site.
{:ok, %{status: 200, body: %{"data" => devices}}} = UniFi.Network.Devices.list(req, site_id)
rows =
for d <- devices do
"| #{d["name"] || d["macAddress"]} | #{d["model"]} | #{d["ipAddress"] || "—"} | #{d["state"]} |"
end
"""
| Name | Model | IP | State |
|------|-------|----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
case devices do
[first | _] ->
{:ok, %{status: 200, body: detail}} = UniFi.Network.Devices.get(req, site_id, first["id"])
{:ok, %{status: 200, body: stats}} = UniFi.Network.Devices.get_latest_statistics(req, site_id, first["id"])
detail_rows = for {k, v} <- Enum.sort(detail), do: "| `#{k}` | `#{inspect(v)}` |"
stats_rows = for {k, v} <- Enum.sort(stats), do: "| `#{k}` | `#{inspect(v)}` |"
"""
### Device Details: #{first["name"]}
| Key | Value |
|-----|-------|
#{Enum.join(detail_rows, "\n")}
### Live Statistics
| Key | Value |
|-----|-------|
#{Enum.join(stats_rows, "\n")}
"""
|> Kino.Markdown.new()
_ ->
Kino.Markdown.new("*(no devices)*")
end
Devices Pending Adoption
Devices that have been discovered but not yet adopted.
{:ok, %{status: 200, body: %{"data" => pending}}} = UniFi.Network.Devices.list_pending(req)
case pending do
[] ->
Kino.Markdown.new("*(none)*")
_ ->
rows = for d <- pending, do: "| #{inspect(d)} |"
"""
| Device |
|--------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Connected Clients
Currently connected wired and wireless clients.
{:ok, %{status: 200, body: %{"data" => clients}}} = UniFi.Network.Clients.list(req, site_id)
rows =
clients
|> Enum.sort_by(fn c -> String.downcase(c["name"] || c["macAddress"] || "") end)
|> Enum.map(fn c ->
"| #{c["name"] || c["macAddress"]} | #{c["ipAddress"] || "—"} | `#{c["macAddress"]}` | #{c["type"]} |"
end)
"""
| Name | IP | MAC | Type |
|------|----|-----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
case clients do
[first | _] ->
{:ok, %{status: 200, body: detail}} = UniFi.Network.Clients.get(req, site_id, first["id"])
detail_rows = for {k, v} <- Enum.sort(detail), do: "| `#{k}` | `#{inspect(v)}` |"
"""
### Client Details: #{first["name"] || first["macAddress"]}
| Key | Value |
|-----|-------|
#{Enum.join(detail_rows, "\n")}
"""
|> Kino.Markdown.new()
_ ->
Kino.Markdown.new("*(no clients)*")
end
Networks
VLAN and subnet configurations, with references showing which devices and clients use each network.
{:ok, %{status: 200, body: %{"data" => networks}}} = UniFi.Network.Networks.list(req, site_id)
rows =
for n <- networks do
"| #{n["name"] || n["id"]} | #{n["vlan"] || "untagged"} | #{n["purpose"] || n["type"] || "?"} |"
end
"""
| Name | VLAN | Purpose |
|------|------|---------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
case networks do
[first | _] ->
{:ok, %{status: 200, body: detail}} = UniFi.Network.Networks.get(req, site_id, first["id"])
detail_rows = for {k, v} <- Enum.sort(detail), do: "| `#{k}` | `#{inspect(v)}` |"
"""
### Network Details: #{first["name"]}
| Key | Value |
|-----|-------|
#{Enum.join(detail_rows, "\n")}
"""
|> Kino.Markdown.new()
_ ->
Kino.Markdown.new("*(no networks)*")
end
WiFi Broadcasts
Configured SSIDs and their security settings.
{:ok, %{status: 200, body: %{"data" => broadcasts}}} = UniFi.Network.WiFi.list(req, site_id)
rows =
for b <- broadcasts do
enabled = if b["enabled"] != false, do: "✓", else: "✗"
"| #{enabled} | #{b["name"] || b["id"]} |"
end
"""
| Enabled | Name |
|---------|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
case broadcasts do
[first | _] ->
{:ok, %{status: 200, body: detail}} = UniFi.Network.WiFi.get(req, site_id, first["id"])
detail_rows = for {k, v} <- Enum.sort(detail), do: "| `#{k}` | `#{inspect(v)}` |"
"""
### WiFi Broadcast Details: #{first["name"]}
| Key | Value |
|-----|-------|
#{Enum.join(detail_rows, "\n")}
"""
|> Kino.Markdown.new()
_ ->
Kino.Markdown.new("*(no broadcasts)*")
end
WAN Interfaces
Upstream internet connections.
{:ok, %{status: 200, body: %{"data" => wans}}} = UniFi.Network.Supporting.list_wans(req, site_id)
rows = for w <- wans, do: "| #{w["name"] || w["id"]} | #{w["ipAddress"] || w["address"] || "—"} |"
"""
| Name | IP |
|------|----|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
VPN Servers
{:ok, %{status: 200, body: %{"data" => servers}}} = UniFi.Network.Supporting.list_vpn_servers(req, site_id)
case servers do
[] ->
Kino.Markdown.new("*(none)*")
_ ->
rows = for s <- servers, do: "| #{s["name"] || s["id"]} | #{s["type"] || "?"} |"
"""
| Name | Type |
|------|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
VPN Tunnels
Site-to-site VPN connections.
{:ok, %{status: 200, body: %{"data" => tunnels}}} = UniFi.Network.Supporting.list_vpn_tunnels(req, site_id)
case tunnels do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for t <- tunnels, do: "| #{t["name"] || t["id"]} | #{inspect(t)} |"
"""
| Name | Data |
|------|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Firewall Zones
Zone-based firewall configuration. Returns an error if zone-based firewall is not enabled.
case UniFi.Network.Firewall.list_zones(req, site_id) do
{:ok, %{status: 200, body: %{"data" => zones}}} ->
rows = for z <- zones, do: "| `#{z["id"]}` | #{z["name"] || z["id"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
{:ok, %{status: s, body: %{"message" => msg}}} ->
Kino.Markdown.new("⚠️ #{s}: #{msg}")
{:ok, %{status: s}} ->
Kino.Markdown.new("⚠️ status #{s}")
end
Firewall Policies
case UniFi.Network.Firewall.list_policies(req, site_id) do
{:ok, %{status: 200, body: %{"data" => policies}}} ->
rows =
for p <- policies do
enabled = if p["enabled"] != false, do: "✓", else: "✗"
"| #{enabled} | #{p["name"] || p["id"]} | #{p["action"] || "?"} |"
end
"""
| Enabled | Name | Action |
|---------|------|--------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
{:ok, %{status: s, body: %{"message" => msg}}} ->
Kino.Markdown.new("⚠️ #{s}: #{msg}")
{:ok, %{status: s}} ->
Kino.Markdown.new("⚠️ status #{s}")
end
ACL Rules
Access control list rules and their ordering.
{:ok, %{status: 200, body: %{"data" => rules}}} = UniFi.Network.ACL.list(req, site_id)
{:ok, %{status: _, body: ordering}} = UniFi.Network.ACL.get_ordering(req, site_id)
case rules do
[] ->
Kino.Markdown.new("*(none)*\n\nOrdering: `#{inspect(ordering["orderedAclRuleIds"])}`")
_ ->
rows = for r <- rules, do: "| #{r["name"] || r["id"]} | #{r["action"] || "?"} |"
"""
| Name | Action |
|------|--------|
#{Enum.join(rows, "\n")}
Ordering: `#{inspect(ordering["orderedAclRuleIds"])}`
"""
|> Kino.Markdown.new()
end
DNS Policies
{:ok, %{status: 200, body: %{"data" => policies}}} = UniFi.Network.DNS.list(req, site_id)
case policies do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for p <- policies, do: "| #{p["name"] || p["id"]} |"
"""
| Name |
|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Traffic Matching Lists
{:ok, %{status: 200, body: %{"data" => lists}}} = UniFi.Network.TrafficMatching.list(req, site_id)
case lists do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for l <- lists, do: "| `#{l["id"]}` | #{l["name"] || l["id"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Hotspot Vouchers
{:ok, %{status: 200, body: %{"data" => vouchers}}} = UniFi.Network.Hotspot.list_vouchers(req, site_id)
case vouchers do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for v <- vouchers, do: "| #{v["code"] || v["id"]} |"
"""
| Code |
|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
RADIUS Profiles
{:ok, %{status: 200, body: %{"data" => profiles}}} = UniFi.Network.Supporting.list_radius_profiles(req, site_id)
case profiles do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for p <- profiles, do: "| #{p["name"]} | `#{p["id"]}` |"
"""
| Name | ID |
|------|----|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Device Tags
{:ok, %{status: 200, body: %{"data" => tags}}} = UniFi.Network.Supporting.list_device_tags(req, site_id)
case tags do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for t <- tags, do: "| `#{t["id"]}` | #{t["name"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
DPI Categories
Deep Packet Inspection application categories.
{:ok, %{status: 200, body: %{"data" => cats}}} = UniFi.Network.Supporting.list_dpi_categories(req)
rows = for c <- cats, do: "| #{c["id"]} | #{c["name"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
DPI Applications
{:ok, %{status: 200, body: %{"data" => apps}}} = UniFi.Network.Supporting.list_dpi_applications(req)
rows = for a <- Enum.take(apps, 30), do: "| #{a["id"]} | #{a["name"]} |"
"""
| ID | Name |
|----|------|
#{Enum.join(rows, "\n")}
*(#{length(apps)} total)*
"""
|> Kino.Markdown.new()
Countries
Regulatory country list for channel/power settings.
{:ok, %{status: 200, body: %{"data" => countries}}} = UniFi.Network.Supporting.list_countries(req)
rows = for c <- countries, do: "| #{c["code"]} | #{c["name"]} |"
"""
| Code | Name |
|------|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: System Info
Controller build, version, data retention, and debug settings from the legacy API.
{:ok, %{body: %{"data" => [info]}}} = UniFi.Network.Legacy.Stats.sysinfo(legacy)
rows = for {k, v} <- Enum.sort(info), do: "| `#{k}` | `#{inspect(v)}` |"
"""
| Key | Value |
|-----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Health
Subsystem health status for WLAN, WAN, LAN, VPN, and WWW.
{:ok, %{body: %{"data" => items}}} = UniFi.Network.Legacy.Stats.health(legacy)
rows =
for h <- items do
"| #{h["subsystem"]} | #{h["status"]} | #{h["num_adopted"] || 0} |"
end
"""
| Subsystem | Status | Adopted |
|-----------|--------|---------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Device Stats
Detailed per-device statistics with uptime — much richer than the integration API.
{:ok, %{body: %{"data" => devices}}} = UniFi.Network.Legacy.Stats.devices(legacy)
rows =
for d <- devices do
name = d["name"] || d["mac"]
days = div(d["uptime"] || 0, 86400)
"| #{name} | #{d["model"]} | #{days}d |"
end
"""
| Name | Model | Uptime |
|------|-------|--------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Client Stats
The legacy API returns ~91 fields per client, including signal strength, satisfaction score, SSID, channel, radio info, and DPI data.
{:ok, %{body: %{"data" => clients}}} = UniFi.Network.Legacy.Stats.clients(legacy)
rows =
clients
|> Enum.sort_by(fn c -> String.downcase(c["hostname"] || c["name"] || c["mac"] || "") end)
|> Enum.map(fn c ->
name = c["name"] || c["hostname"] || c["mac"]
essid = c["essid"] || (if c["is_wired"], do: "wired", else: "?")
"| #{name} | #{c["ip"] || "—"} | #{c["signal"] || "—"} | #{c["satisfaction"] || "—"} | #{essid} |"
end)
"""
| Name | IP | Signal | Satisfaction | Network |
|------|----|--------|--------------|---------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Rogue APs
Neighboring access points detected by your UniFi APs, sorted by signal strength.
{:ok, %{body: %{"data" => aps}}} = UniFi.Network.Legacy.Stats.rogue_aps(legacy)
rows =
aps
|> Enum.sort_by(& &1["rssi"] || 0, :desc)
|> Enum.take(20)
|> Enum.map(fn a ->
"| #{a["essid"] || "*(hidden)*"} | #{a["channel"]} | #{a["rssi"]} | `#{a["bssid"]}` |"
end)
"""
#{length(aps)} detected, showing top 20 by RSSI:
| SSID | Channel | RSSI | BSSID |
|------|---------|------|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Events & Alarms
{:ok, %{body: %{"data" => events}}} = UniFi.Network.Legacy.Stats.events(legacy)
{:ok, %{body: %{"data" => alarms}}} = UniFi.Network.Legacy.Stats.alarms(legacy)
events_md =
case events do
[] -> "*(no events)*"
_ ->
rows = for e <- Enum.take(events, 20), do: "| #{e["datetime"]} | #{e["msg"] || e["key"]} |"
"| Time | Event |\n|------|-------|\n#{Enum.join(rows, "\n")}"
end
alarms_md =
case alarms do
[] -> "*(no alarms)*"
_ ->
rows = for a <- Enum.take(alarms, 20), do: "| #{a["datetime"]} | #{a["msg"] || a["key"]} |"
"| Time | Alarm |\n|------|-------|\n#{Enum.join(rows, "\n")}"
end
"""
### Events
#{events_md}
### Alarms
#{alarms_md}
"""
|> Kino.Markdown.new()
Legacy: DPI Stats
Deep Packet Inspection traffic statistics.
{:ok, %{body: %{"data" => dpi}}} = UniFi.Network.Legacy.Stats.dpi(legacy)
case dpi do
[] -> Kino.Markdown.new("*(none)*")
_ ->
rows = for d <- dpi, do: "| `#{inspect(d)}` |"
"""
| Data |
|------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Legacy: Channels & Spectrum
Current channel usage and spectrum scan data from your access points.
{:ok, %{body: %{"data" => channels}}} = UniFi.Network.Legacy.Stats.current_channels(legacy)
rows = for {k, v} <- Enum.sort(hd(channels)), do: "| `#{k}` | `#{inspect(v)}` |"
"""
| Key | Value |
|-----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
{:ok, %{body: %{"data" => scans}}} = UniFi.Network.Legacy.Stats.spectrum_scan(legacy)
rows = for s <- scans, do: "| `#{s["mac"]}` | #{length(s["spectrum_table"] || [])} |"
"""
| MAC | Channels |
|-----|----------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Settings
All 35 setting categories. The mgmt key contains SSH configuration.
{:ok, %{body: %{"data" => settings}}} = UniFi.Network.Legacy.Settings.list(legacy)
rows = for s <- settings, do: "| `#{s["key"]}` | `#{s["_id"]}` |"
"""
| Key | ID |
|-----|----|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Port Forwards
NAT port forwarding rules.
{:ok, %{body: %{"data" => fwds}}} = UniFi.Network.Legacy.PortForwards.list(legacy)
case fwds do
[] ->
Kino.Markdown.new("*(none)*")
_ ->
rows =
for f <- fwds do
enabled = if f["enabled"], do: "✓", else: "✗"
"| #{enabled} | #{f["name"] || "unnamed"} | #{f["proto"]} | #{f["dst_port"]} | #{f["fwd"]}:#{f["fwd_port"]} |"
end
"""
| Enabled | Name | Proto | Port | Forward To |
|---------|------|-------|------|------------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Legacy: Static Routes
{:ok, %{body: %{"data" => routes}}} = UniFi.Network.Legacy.Routing.list(legacy)
case routes do
[] ->
Kino.Markdown.new("*(none)*")
_ ->
rows =
for r <- routes do
enabled = if r["enabled"], do: "✓", else: "✗"
"| #{enabled} | #{r["name"]} | #{r["static-route_network"]} | #{r["static-route_nexthop"]} |"
end
"""
| Enabled | Name | Network | Next Hop |
|---------|------|---------|----------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
end
Legacy: Firewall Rules & Groups
Traditional (non-zone-based) firewall rules.
{:ok, %{body: %{"data" => rules}}} = UniFi.Network.Legacy.FirewallRules.list(legacy)
{:ok, %{body: %{"data" => groups}}} = UniFi.Network.Legacy.FirewallRules.list_groups(legacy)
rules_md =
case rules do
[] -> "*(none)*"
_ ->
rows = for r <- rules, do: "| #{r["name"] || r["_id"]} | #{r["action"]} | #{r["ruleset"]} |"
"| Name | Action | Ruleset |\n|------|--------|--------|\n#{Enum.join(rows, "\n")}"
end
groups_md =
case groups do
[] -> "*(none)*"
_ ->
rows = for g <- groups, do: "| #{g["name"]} | #{g["group_type"]} |"
"| Name | Type |\n|------|------|\n#{Enum.join(rows, "\n")}"
end
"""
### Rules
#{rules_md}
### Groups
#{groups_md}
"""
|> Kino.Markdown.new()
Legacy: Known Users
All clients the controller has ever seen — not just currently connected ones.
{:ok, %{body: %{"data" => users}}} = UniFi.Network.Legacy.Users.list(legacy)
{:ok, %{body: %{"data" => groups}}} = UniFi.Network.Legacy.Users.list_groups(legacy)
user_rows =
users
|> Enum.sort_by(fn u -> String.downcase(u["name"] || u["mac"] || "") end)
|> Enum.map(fn u ->
blocked = if u["blocked"], do: "🚫", else: ""
"| #{u["name"] || "—"} | `#{u["mac"]}` | #{blocked} |"
end)
group_rows = for g <- groups, do: "| #{g["name"]} | `#{g["_id"]}` |"
"""
#{length(users)} known users:
| Name | MAC | Blocked |
|------|-----|---------|
#{Enum.join(user_rows, "\n")}
### User Groups
| Name | ID |
|------|----|
#{Enum.join(group_rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: WLAN Config
Full WLAN configuration objects with all settings.
{:ok, %{body: %{"data" => wlans}}} = UniFi.Network.Legacy.WLANConf.list(legacy)
rows =
for w <- wlans do
enabled = if w["enabled"], do: "✓", else: "✗"
"| #{enabled} | #{w["name"]} | #{w["security"]} | #{w["hide_ssid"]} |"
end
"""
| Enabled | Name | Security | Hidden |
|---------|------|----------|--------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Network Config
Full network configuration objects including WAN, LAN, and VPN networks.
{:ok, %{body: %{"data" => nets}}} = UniFi.Network.Legacy.NetworkConf.list(legacy)
rows = for n <- nets, do: "| #{n["name"]} | #{n["purpose"]} | `#{n["_id"]}` |"
"""
| Name | Purpose | ID |
|------|---------|-----|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()
Legacy: Miscellaneous
Port profiles, dynamic DNS, RADIUS, hotspot operators, tags, and current API user.
counts =
[
{"Port profiles", UniFi.Network.Legacy.Misc.list_port_profiles(legacy)},
{"Dynamic DNS", UniFi.Network.Legacy.Misc.list_dynamic_dns(legacy)},
{"RADIUS profiles", UniFi.Network.Legacy.Misc.list_radius_profiles(legacy)},
{"Hotspot operators", UniFi.Network.Legacy.Misc.list_hotspot_operators(legacy)},
{"Hotspot 2.0 configs", UniFi.Network.Legacy.Misc.list_hotspot2_conf(legacy)},
{"Tags", UniFi.Network.Legacy.Misc.list_tags(legacy)},
{"RADIUS accounts", UniFi.Network.Legacy.Misc.list_accounts(legacy)},
{"Channel plans", UniFi.Network.Legacy.Misc.list_channel_plans(legacy)},
{"Virtual devices", UniFi.Network.Legacy.Misc.list_virtual_devices(legacy)}
]
|> Enum.map(fn {name, {:ok, %{body: %{"data" => d}}}} -> "| #{name} | #{length(d)} |" end)
"""
| Resource | Count |
|----------|-------|
#{Enum.join(counts, "\n")}
"""
|> Kino.Markdown.new()
{:ok, %{body: %{"data" => [self]}}} = UniFi.Network.Legacy.Misc.self(legacy)
picked = Map.take(self, ["name", "email", "email_alert_enabled", "is_super", "role"])
rows = for {k, v} <- Enum.sort(picked), do: "| `#{k}` | `#{inspect(v)}` |"
"""
### Current API User
| Key | Value |
|-----|-------|
#{Enum.join(rows, "\n")}
"""
|> Kino.Markdown.new()