---
title: "Get interface by ID"
method: GET
path: "/api/v1/interfaces/{id}"
tags: ["Interfaces"]
---

# Get interface by ID

`GET /api/v1/interfaces/{id}`

## Request

- Base URL: `https://app.scanopy.net`
- URL: `https://app.scanopy.net/api/v1/interfaces/{id}`
- Auth: one of:
  - API key in header `Authorization`
  - API key in cookie `session_id`

## Path parameters

- `id` string, uuid, required

## Response `200`

Interface found

- ApiResponseInterface: Envelope for a successful response. Failures are sent with a non-2xx status and an `ApiErrorResponse` body instead.
  - `data` object: The result payload. Omitted on failure.
    - `mac_address` string: MAC address, as discovered.
    - `mac_address_source` union: How a discovered value reached us. Every variant here has something that writes it. Sources with no producer are deliberately absent: a rung the applier can never see is a rung nothing can be tested against, and the tier decision is better made by whoever writes the reader than guessed in advance. **Do not derive `Ord`.** A derive compares the variant and then the payload, which would make `Probe(Docker) < Probe(Snmp)` on declaration order alone. Ordering is only ever [`Self::rank`]. **Externally tagged**, which is serde's default and is left unstated for that reason. Thirty-three of these variants carry nothing, and a tag on a variant with no content is a key that distinguishes nothing — `"Unspecified"`, not `{"type":"Unspecified"}`, in every row of every column. The two that do carry a [`ClientProbe`] keep it under their own name, `{"Probe":"Snmp"}`, which tells them apart from each other and from every bare name.
      - 'Unspecified': Provenance unknown: a payload from a daemon predating the rung, a row predating the column, or a source this binary does not recognise. Below everything, so it never displaces a value we know the origin of and anything may improve on it.
      - 'OwnAddress': The host's own address, standing in for a name it does not have. Nothing on this server writes it any more: an address is an identifier, and the display ladder shows it without a copy in `name`. Daemons up to v0.17.14 still send it, and it is kept so their payloads deserialise before ingest drops the copy.
      - 'ServiceMatch': Implied by a matched service definition.
      - 'LldpNeighbourAddress': A /24 (or /64) convention around an address a neighbour advertised. LLDP carries no netmask TLV, so the range is our invention rather than the neighbour's claim.
      - 'CipVendorId': A manufacturer string synthesised from a numeric CIP vendor ID, because we ship no ODVA vendor table. Distinct from [`Self::Probe`] over the same transport for the reason the module doc gives: the variant names what was read, not how it arrived, and `"CIP vendor 1"` is our own construction rather than anything the device emitted.
      - 'SysDescrMatch': An operating system matched in SNMP `sysDescr` against a Recog fingerprint. The text is the device's own, but the OS is our reading of it, so it ranks below anything read off the host.
      - 'SysObjectIdMatch': An operating system implied by an SNMP `sysObjectID` a Recog fingerprint names. Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'LldpSysDescMatch': An operating system matched in the system description an LLDP neighbour advertised for itself (`lldpRemSysDesc`). Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'SshBannerMatch': An operating system matched in an SSH server's identification string, such as the `Ubuntu-3ubuntu13` a distribution's OpenSSH package appends.
      - 'HttpServerMatch': An operating system matched in an HTTP `Server` header, such as `Microsoft-IIS/10.0`.
      - 'X509SubjectMatch': A device or OS matched in the subject of a TLS certificate the host served, such as the `OU=RV042` a Linksys router's self-signed certificate carries.
      - 'X509IssuerMatch': A device or OS matched in the issuer of a TLS certificate the host served: an appliance whose factory certificate names its own maker as the CA.
      - 'HtmlTitleMatch': A device or OS matched in the `<title>` of a page the host's web server returned.
      - 'HttpWwwAuthMatch': A device or OS matched in the realm of an HTTP `WWW-Authenticate` challenge.
      - 'HttpCookieMatch': A device or OS matched in a cookie the host's web server set.
      - 'FaviconMatch': A device or OS matched by the MD5 hash of the host's `/favicon.ico`.
      - 'FtpBannerMatch': A device or OS matched in an FTP server's greeting.
      - 'TelnetBannerMatch': A device or OS matched in a Telnet banner.
      - 'RtspServerMatch': A device or OS matched in an RTSP server's `Server` header.
      - 'TcpStackMatch': An operating system family matched in the TCP/IP stack's reply to a connection: the initial TTL, window, MSS and TCP option layout of its SYN-ACK. The weakest match: it names only a family, and is applied only to a host nothing else names an OS for.
      - 'DnsSdDeviceInfoMatch': An operating system matched in an mDNS `_device-info._tcp` record, such as a Mac's `model=MacBookPro18,3`.
      - 'DnsSdAirPlayMatch': An operating system matched in the `model` an mDNS `_airplay._tcp` record carries, such as a Mac's `model=Mac17,2`. Macs that share nothing still advertise AirPlay.
      - 'InterfaceNameMatch': A subnet type guessed from the name of the interface that holds the range: `wg0` for a VPN tunnel, `br-guest` for a guest network. The name is the operating system's; the type is our reading of it.
      - 'DnsSdInstanceName': A DNS-SD instance label — the Chromecast `fn=Living Room TV`, typed by a person during device setup.
      - 'DnsSdHostname': A hostname a device announced for itself over mDNS: the SRV target, such as `chromecast-a1b2c3.local`. Machine-generated, unlike the instance label beside it.
      - 'DnsSdServicePort': A port a device advertised for one of its services in an mDNS SRV record, such as 631 for `_ipp._tcp`. Recorded where the port scan did not cover that port.
      - 'LldpChassisId': A chassis ID a neighbour advertised for itself.
      - 'Lldpd': An LLDP neighbour the `lldpd` service on the daemon's own host heard on one of its ports. Distinct from [`Self::LldpChassisId`], which is the identity a neighbour advertised: this names the listener that recorded the adjacency.
      - 'ReverseDns': Reverse DNS. A known speaker that is not the subject.
      - 'ForwardingTable': A router's `ipNetToMediaTable` cache, or a switch's bridge FDB. One variant for both: each is "a device telling us about a MAC that is not its own", with no basis to rank one above the other.
      - 'ArpReply': We broadcast an ARP request for a specific address and something replied claiming it.
      - 'IcmpEcho': We sent an ICMP echo request to the address and it answered.
      - 'PortScan': We opened a TCP connection to a port, or a UDP probe to it was answered. Stamps the port, and the address of a host found only this way.
      - 'DaemonSelfReport': The daemon reading its own host: NIC and routing configuration, its own hostname and its OS. `Native` for the reason [`Self::ProfinetDcp`] is: the host describes itself, first-hand, with no transport or third party between the reading and the machine. It outranks [`Self::ContainerRuntimeInfo`], whose engine may run in a VM on this machine.
      - 'ProfinetDcp': A PROFINET DCP Identify exchange: we sent the request and the transport correlated the reply to the station that sent it. `Native`, not merely `Queried` — like [`Self::Probe`] over [`ClientProbe::ModbusTcp`]/`EtherNetIp`/`OpcUa`, the protocol is the device's own rather than a generic MIB approximating it. A bare variant rather than `Probe(ClientProbe)` on purpose: [`ClientProbe`] is scoped to application probes reached over an already-open TCP/UDP port (`every_client_probe_variant_has_a_producer` enforces that every variant has an `AppProbe` producer), and DCP is raw Ethernet with no port at all.
      - 'ContainerRuntimeInfo': A container engine (Docker, Podman) reporting the machine it runs on, from its `info` endpoint: the host OS, its release and kernel. `Queried`, not `Native`: we chose the engine and authenticated to it, but the machine it describes is the host only when the engine runs on it directly. Docker Desktop, OrbStack, Colima, Rancher Desktop and `podman machine` run the engine in a Linux VM, and `info` describes that VM. A bare variant rather than `Probe(Docker)`, which is the container listing; this is a different exchange.
      - 'HypervisorConfig': The configuration of the hypervisor or container runtime that runs the guest, read through its API: the MAC of a Proxmox guest's virtual NIC or of a container's macvlan endpoint, and the hostname and distribution a Proxmox LXC container's config sets. `Native` for the reason [`Self::ProfinetDcp`] is: the hypervisor or runtime assigned that MAC, keeps it for the guest's or container's life and puts it on the wire for it, so its record is the NIC's own identity, not a third party's report of it. That is what lets a guest with no address still be identified by its NIC. A bare variant rather than `Probe(Proxmox)` or `Probe(Docker)`, which cover everything else those APIs report and stay `Reported`.
      - 'GuestAgent': Software inside a guest read this from the guest's own operating system and answered the hypervisor's API: the QEMU guest agent behind Proxmox, and the same role VMware Tools and Hyper-V integration services fill. `Native` for the reason [`Self::ProfinetDcp`] is: the guest describes itself, over a channel the hypervisor binds to that one guest, so it is first-hand, not the hypervisor's report of the guest (`Probe(Proxmox)`).
      - 'SshScript': A script the operator wrote, run on the host over SSH, printed it. Queried: we chose the host, authenticated to it and read the answer from its own shell. Human-authored, because the operator chose what the script reports, which is what puts it above the machine values SNMP and LLDP emit about the same fields.
      - object: A value the thing emitted about itself, over whatever transport [`ClientProbe`] names.
        - `Probe` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - object: A value a person entered into the thing we read it from, carried back over the same transport: SNMP `sysLocation`, a name set in a controller.
        - `Authored` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - 'Manual': A person asserted it in Scanopy. Nothing discovery reads displaces it.
    - `fdb_macs` string[]: MAC addresses the switch learned on this port. A port with one learned MAC can be resolved to a neighbor link; several indicate an uplink.
    - `fdb_macs_source` union: How a discovered value reached us. Every variant here has something that writes it. Sources with no producer are deliberately absent: a rung the applier can never see is a rung nothing can be tested against, and the tier decision is better made by whoever writes the reader than guessed in advance. **Do not derive `Ord`.** A derive compares the variant and then the payload, which would make `Probe(Docker) < Probe(Snmp)` on declaration order alone. Ordering is only ever [`Self::rank`]. **Externally tagged**, which is serde's default and is left unstated for that reason. Thirty-three of these variants carry nothing, and a tag on a variant with no content is a key that distinguishes nothing — `"Unspecified"`, not `{"type":"Unspecified"}`, in every row of every column. The two that do carry a [`ClientProbe`] keep it under their own name, `{"Probe":"Snmp"}`, which tells them apart from each other and from every bare name.
      - 'Unspecified': Provenance unknown: a payload from a daemon predating the rung, a row predating the column, or a source this binary does not recognise. Below everything, so it never displaces a value we know the origin of and anything may improve on it.
      - 'OwnAddress': The host's own address, standing in for a name it does not have. Nothing on this server writes it any more: an address is an identifier, and the display ladder shows it without a copy in `name`. Daemons up to v0.17.14 still send it, and it is kept so their payloads deserialise before ingest drops the copy.
      - 'ServiceMatch': Implied by a matched service definition.
      - 'LldpNeighbourAddress': A /24 (or /64) convention around an address a neighbour advertised. LLDP carries no netmask TLV, so the range is our invention rather than the neighbour's claim.
      - 'CipVendorId': A manufacturer string synthesised from a numeric CIP vendor ID, because we ship no ODVA vendor table. Distinct from [`Self::Probe`] over the same transport for the reason the module doc gives: the variant names what was read, not how it arrived, and `"CIP vendor 1"` is our own construction rather than anything the device emitted.
      - 'SysDescrMatch': An operating system matched in SNMP `sysDescr` against a Recog fingerprint. The text is the device's own, but the OS is our reading of it, so it ranks below anything read off the host.
      - 'SysObjectIdMatch': An operating system implied by an SNMP `sysObjectID` a Recog fingerprint names. Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'LldpSysDescMatch': An operating system matched in the system description an LLDP neighbour advertised for itself (`lldpRemSysDesc`). Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'SshBannerMatch': An operating system matched in an SSH server's identification string, such as the `Ubuntu-3ubuntu13` a distribution's OpenSSH package appends.
      - 'HttpServerMatch': An operating system matched in an HTTP `Server` header, such as `Microsoft-IIS/10.0`.
      - 'X509SubjectMatch': A device or OS matched in the subject of a TLS certificate the host served, such as the `OU=RV042` a Linksys router's self-signed certificate carries.
      - 'X509IssuerMatch': A device or OS matched in the issuer of a TLS certificate the host served: an appliance whose factory certificate names its own maker as the CA.
      - 'HtmlTitleMatch': A device or OS matched in the `<title>` of a page the host's web server returned.
      - 'HttpWwwAuthMatch': A device or OS matched in the realm of an HTTP `WWW-Authenticate` challenge.
      - 'HttpCookieMatch': A device or OS matched in a cookie the host's web server set.
      - 'FaviconMatch': A device or OS matched by the MD5 hash of the host's `/favicon.ico`.
      - 'FtpBannerMatch': A device or OS matched in an FTP server's greeting.
      - 'TelnetBannerMatch': A device or OS matched in a Telnet banner.
      - 'RtspServerMatch': A device or OS matched in an RTSP server's `Server` header.
      - 'TcpStackMatch': An operating system family matched in the TCP/IP stack's reply to a connection: the initial TTL, window, MSS and TCP option layout of its SYN-ACK. The weakest match: it names only a family, and is applied only to a host nothing else names an OS for.
      - 'DnsSdDeviceInfoMatch': An operating system matched in an mDNS `_device-info._tcp` record, such as a Mac's `model=MacBookPro18,3`.
      - 'DnsSdAirPlayMatch': An operating system matched in the `model` an mDNS `_airplay._tcp` record carries, such as a Mac's `model=Mac17,2`. Macs that share nothing still advertise AirPlay.
      - 'InterfaceNameMatch': A subnet type guessed from the name of the interface that holds the range: `wg0` for a VPN tunnel, `br-guest` for a guest network. The name is the operating system's; the type is our reading of it.
      - 'DnsSdInstanceName': A DNS-SD instance label — the Chromecast `fn=Living Room TV`, typed by a person during device setup.
      - 'DnsSdHostname': A hostname a device announced for itself over mDNS: the SRV target, such as `chromecast-a1b2c3.local`. Machine-generated, unlike the instance label beside it.
      - 'DnsSdServicePort': A port a device advertised for one of its services in an mDNS SRV record, such as 631 for `_ipp._tcp`. Recorded where the port scan did not cover that port.
      - 'LldpChassisId': A chassis ID a neighbour advertised for itself.
      - 'Lldpd': An LLDP neighbour the `lldpd` service on the daemon's own host heard on one of its ports. Distinct from [`Self::LldpChassisId`], which is the identity a neighbour advertised: this names the listener that recorded the adjacency.
      - 'ReverseDns': Reverse DNS. A known speaker that is not the subject.
      - 'ForwardingTable': A router's `ipNetToMediaTable` cache, or a switch's bridge FDB. One variant for both: each is "a device telling us about a MAC that is not its own", with no basis to rank one above the other.
      - 'ArpReply': We broadcast an ARP request for a specific address and something replied claiming it.
      - 'IcmpEcho': We sent an ICMP echo request to the address and it answered.
      - 'PortScan': We opened a TCP connection to a port, or a UDP probe to it was answered. Stamps the port, and the address of a host found only this way.
      - 'DaemonSelfReport': The daemon reading its own host: NIC and routing configuration, its own hostname and its OS. `Native` for the reason [`Self::ProfinetDcp`] is: the host describes itself, first-hand, with no transport or third party between the reading and the machine. It outranks [`Self::ContainerRuntimeInfo`], whose engine may run in a VM on this machine.
      - 'ProfinetDcp': A PROFINET DCP Identify exchange: we sent the request and the transport correlated the reply to the station that sent it. `Native`, not merely `Queried` — like [`Self::Probe`] over [`ClientProbe::ModbusTcp`]/`EtherNetIp`/`OpcUa`, the protocol is the device's own rather than a generic MIB approximating it. A bare variant rather than `Probe(ClientProbe)` on purpose: [`ClientProbe`] is scoped to application probes reached over an already-open TCP/UDP port (`every_client_probe_variant_has_a_producer` enforces that every variant has an `AppProbe` producer), and DCP is raw Ethernet with no port at all.
      - 'ContainerRuntimeInfo': A container engine (Docker, Podman) reporting the machine it runs on, from its `info` endpoint: the host OS, its release and kernel. `Queried`, not `Native`: we chose the engine and authenticated to it, but the machine it describes is the host only when the engine runs on it directly. Docker Desktop, OrbStack, Colima, Rancher Desktop and `podman machine` run the engine in a Linux VM, and `info` describes that VM. A bare variant rather than `Probe(Docker)`, which is the container listing; this is a different exchange.
      - 'HypervisorConfig': The configuration of the hypervisor or container runtime that runs the guest, read through its API: the MAC of a Proxmox guest's virtual NIC or of a container's macvlan endpoint, and the hostname and distribution a Proxmox LXC container's config sets. `Native` for the reason [`Self::ProfinetDcp`] is: the hypervisor or runtime assigned that MAC, keeps it for the guest's or container's life and puts it on the wire for it, so its record is the NIC's own identity, not a third party's report of it. That is what lets a guest with no address still be identified by its NIC. A bare variant rather than `Probe(Proxmox)` or `Probe(Docker)`, which cover everything else those APIs report and stay `Reported`.
      - 'GuestAgent': Software inside a guest read this from the guest's own operating system and answered the hypervisor's API: the QEMU guest agent behind Proxmox, and the same role VMware Tools and Hyper-V integration services fill. `Native` for the reason [`Self::ProfinetDcp`] is: the guest describes itself, over a channel the hypervisor binds to that one guest, so it is first-hand, not the hypervisor's report of the guest (`Probe(Proxmox)`).
      - 'SshScript': A script the operator wrote, run on the host over SSH, printed it. Queried: we chose the host, authenticated to it and read the answer from its own shell. Human-authored, because the operator chose what the script reports, which is what puts it above the machine values SNMP and LLDP emit about the same fields.
      - object: A value the thing emitted about itself, over whatever transport [`ClientProbe`] names.
        - `Probe` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - object: A value a person entered into the thing we read it from, carried back over the same transport: SNMP `sysLocation`, a name set in a controller.
        - `Authored` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - 'Manual': A person asserted it in Scanopy. Nothing discovery reads displaces it.
    - `admin_status` 'Up' | 'Down' | 'Testing': SNMP ifAdminStatus values per IF-MIB RFC 2863
    - `host_id` string, uuid, required: The host this entity belongs to.
    - `if_alias` string, nullable: SNMP ifAlias - user-configured description
    - `if_descr` string, nullable: SNMP ifDescr - interface description (e.g., GigabitEthernet0/1), where one was read. `None` for a source with nothing to put here — PROFINET DCP Identify carries no per-port description at all. Same principle as `if_index`/`if_type`: an absent value is `None`, never a fabricated string standing in for it.
    - `if_index` integer, nullable: SNMP ifIndex — stable identifier within device, where one was read. `None` for a port learned from a neighbour's LLDP/CDP advertisement rather than from the device's own ifTable: the far end tells us the port exists and what it is called, never its index. `0` used to stand in for that, which is a real ifIndex on some agents and made "never read" indistinguishable from "read as zero". Not the identity of the row. `match_existing_interface` tries `(host_id, if_name)` first and the live unique index is on that pair; the index tier only runs for a row that has one.
    - `if_name` string, nullable: SNMP ifName - short interface name (e.g., Gi1/0/1)
    - `if_type` integer, nullable: SNMP ifType - IANAifType integer (6=ethernet, 24=loopback, etc.), where one was read. `None` is *unknown*, never a type. Everything that filters on this must treat unknown as included — a port at the far end of a cable is physical by construction, and excluding it for lack of a number would drop the row from resolution and from the map.
    - `interface_source` union: How a discovered value reached us. Every variant here has something that writes it. Sources with no producer are deliberately absent: a rung the applier can never see is a rung nothing can be tested against, and the tier decision is better made by whoever writes the reader than guessed in advance. **Do not derive `Ord`.** A derive compares the variant and then the payload, which would make `Probe(Docker) < Probe(Snmp)` on declaration order alone. Ordering is only ever [`Self::rank`]. **Externally tagged**, which is serde's default and is left unstated for that reason. Thirty-three of these variants carry nothing, and a tag on a variant with no content is a key that distinguishes nothing — `"Unspecified"`, not `{"type":"Unspecified"}`, in every row of every column. The two that do carry a [`ClientProbe`] keep it under their own name, `{"Probe":"Snmp"}`, which tells them apart from each other and from every bare name.
      - 'Unspecified': Provenance unknown: a payload from a daemon predating the rung, a row predating the column, or a source this binary does not recognise. Below everything, so it never displaces a value we know the origin of and anything may improve on it.
      - 'OwnAddress': The host's own address, standing in for a name it does not have. Nothing on this server writes it any more: an address is an identifier, and the display ladder shows it without a copy in `name`. Daemons up to v0.17.14 still send it, and it is kept so their payloads deserialise before ingest drops the copy.
      - 'ServiceMatch': Implied by a matched service definition.
      - 'LldpNeighbourAddress': A /24 (or /64) convention around an address a neighbour advertised. LLDP carries no netmask TLV, so the range is our invention rather than the neighbour's claim.
      - 'CipVendorId': A manufacturer string synthesised from a numeric CIP vendor ID, because we ship no ODVA vendor table. Distinct from [`Self::Probe`] over the same transport for the reason the module doc gives: the variant names what was read, not how it arrived, and `"CIP vendor 1"` is our own construction rather than anything the device emitted.
      - 'SysDescrMatch': An operating system matched in SNMP `sysDescr` against a Recog fingerprint. The text is the device's own, but the OS is our reading of it, so it ranks below anything read off the host.
      - 'SysObjectIdMatch': An operating system implied by an SNMP `sysObjectID` a Recog fingerprint names. Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'LldpSysDescMatch': An operating system matched in the system description an LLDP neighbour advertised for itself (`lldpRemSysDesc`). Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'SshBannerMatch': An operating system matched in an SSH server's identification string, such as the `Ubuntu-3ubuntu13` a distribution's OpenSSH package appends.
      - 'HttpServerMatch': An operating system matched in an HTTP `Server` header, such as `Microsoft-IIS/10.0`.
      - 'X509SubjectMatch': A device or OS matched in the subject of a TLS certificate the host served, such as the `OU=RV042` a Linksys router's self-signed certificate carries.
      - 'X509IssuerMatch': A device or OS matched in the issuer of a TLS certificate the host served: an appliance whose factory certificate names its own maker as the CA.
      - 'HtmlTitleMatch': A device or OS matched in the `<title>` of a page the host's web server returned.
      - 'HttpWwwAuthMatch': A device or OS matched in the realm of an HTTP `WWW-Authenticate` challenge.
      - 'HttpCookieMatch': A device or OS matched in a cookie the host's web server set.
      - 'FaviconMatch': A device or OS matched by the MD5 hash of the host's `/favicon.ico`.
      - 'FtpBannerMatch': A device or OS matched in an FTP server's greeting.
      - 'TelnetBannerMatch': A device or OS matched in a Telnet banner.
      - 'RtspServerMatch': A device or OS matched in an RTSP server's `Server` header.
      - 'TcpStackMatch': An operating system family matched in the TCP/IP stack's reply to a connection: the initial TTL, window, MSS and TCP option layout of its SYN-ACK. The weakest match: it names only a family, and is applied only to a host nothing else names an OS for.
      - 'DnsSdDeviceInfoMatch': An operating system matched in an mDNS `_device-info._tcp` record, such as a Mac's `model=MacBookPro18,3`.
      - 'DnsSdAirPlayMatch': An operating system matched in the `model` an mDNS `_airplay._tcp` record carries, such as a Mac's `model=Mac17,2`. Macs that share nothing still advertise AirPlay.
      - 'InterfaceNameMatch': A subnet type guessed from the name of the interface that holds the range: `wg0` for a VPN tunnel, `br-guest` for a guest network. The name is the operating system's; the type is our reading of it.
      - 'DnsSdInstanceName': A DNS-SD instance label — the Chromecast `fn=Living Room TV`, typed by a person during device setup.
      - 'DnsSdHostname': A hostname a device announced for itself over mDNS: the SRV target, such as `chromecast-a1b2c3.local`. Machine-generated, unlike the instance label beside it.
      - 'DnsSdServicePort': A port a device advertised for one of its services in an mDNS SRV record, such as 631 for `_ipp._tcp`. Recorded where the port scan did not cover that port.
      - 'LldpChassisId': A chassis ID a neighbour advertised for itself.
      - 'Lldpd': An LLDP neighbour the `lldpd` service on the daemon's own host heard on one of its ports. Distinct from [`Self::LldpChassisId`], which is the identity a neighbour advertised: this names the listener that recorded the adjacency.
      - 'ReverseDns': Reverse DNS. A known speaker that is not the subject.
      - 'ForwardingTable': A router's `ipNetToMediaTable` cache, or a switch's bridge FDB. One variant for both: each is "a device telling us about a MAC that is not its own", with no basis to rank one above the other.
      - 'ArpReply': We broadcast an ARP request for a specific address and something replied claiming it.
      - 'IcmpEcho': We sent an ICMP echo request to the address and it answered.
      - 'PortScan': We opened a TCP connection to a port, or a UDP probe to it was answered. Stamps the port, and the address of a host found only this way.
      - 'DaemonSelfReport': The daemon reading its own host: NIC and routing configuration, its own hostname and its OS. `Native` for the reason [`Self::ProfinetDcp`] is: the host describes itself, first-hand, with no transport or third party between the reading and the machine. It outranks [`Self::ContainerRuntimeInfo`], whose engine may run in a VM on this machine.
      - 'ProfinetDcp': A PROFINET DCP Identify exchange: we sent the request and the transport correlated the reply to the station that sent it. `Native`, not merely `Queried` — like [`Self::Probe`] over [`ClientProbe::ModbusTcp`]/`EtherNetIp`/`OpcUa`, the protocol is the device's own rather than a generic MIB approximating it. A bare variant rather than `Probe(ClientProbe)` on purpose: [`ClientProbe`] is scoped to application probes reached over an already-open TCP/UDP port (`every_client_probe_variant_has_a_producer` enforces that every variant has an `AppProbe` producer), and DCP is raw Ethernet with no port at all.
      - 'ContainerRuntimeInfo': A container engine (Docker, Podman) reporting the machine it runs on, from its `info` endpoint: the host OS, its release and kernel. `Queried`, not `Native`: we chose the engine and authenticated to it, but the machine it describes is the host only when the engine runs on it directly. Docker Desktop, OrbStack, Colima, Rancher Desktop and `podman machine` run the engine in a Linux VM, and `info` describes that VM. A bare variant rather than `Probe(Docker)`, which is the container listing; this is a different exchange.
      - 'HypervisorConfig': The configuration of the hypervisor or container runtime that runs the guest, read through its API: the MAC of a Proxmox guest's virtual NIC or of a container's macvlan endpoint, and the hostname and distribution a Proxmox LXC container's config sets. `Native` for the reason [`Self::ProfinetDcp`] is: the hypervisor or runtime assigned that MAC, keeps it for the guest's or container's life and puts it on the wire for it, so its record is the NIC's own identity, not a third party's report of it. That is what lets a guest with no address still be identified by its NIC. A bare variant rather than `Probe(Proxmox)` or `Probe(Docker)`, which cover everything else those APIs report and stay `Reported`.
      - 'GuestAgent': Software inside a guest read this from the guest's own operating system and answered the hypervisor's API: the QEMU guest agent behind Proxmox, and the same role VMware Tools and Hyper-V integration services fill. `Native` for the reason [`Self::ProfinetDcp`] is: the guest describes itself, over a channel the hypervisor binds to that one guest, so it is first-hand, not the hypervisor's report of the guest (`Probe(Proxmox)`).
      - 'SshScript': A script the operator wrote, run on the host over SSH, printed it. Queried: we chose the host, authenticated to it and read the answer from its own shell. Human-authored, because the operator chose what the script reports, which is what puts it above the machine values SNMP and LLDP emit about the same fields.
      - object: A value the thing emitted about itself, over whatever transport [`ClientProbe`] names.
        - `Probe` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - object: A value a person entered into the thing we read it from, carried back over the same transport: SNMP `sysLocation`, a name set in a controller.
        - `Authored` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - 'Manual': A person asserted it in Scanopy. Nothing discovery reads displaces it.
    - `ip_address_id` string, uuid, nullable: FK to IPAddress entity - this port's IP assignment (must be on same host). Old daemons send this as "interface_id".
    - `ip_configured` boolean: Whether the device's own SNMP `ipAddrTable` lists this ifIndex as carrying one of its configured IP addresses. Independent of `ip_address_id`: that FK is set server-side and requires the interface's MAC to be unique on the host before it links anything (`plan_interface_ip_links`), so it stays `NULL` on exactly the hosts this field exists to help — a Windows NIC and its NDIS filter/LWF pseudo-interfaces sharing one MAC (GH #668). `ipAddrTable` only ever binds an address to a real IP-stack adapter; a filter driver is never a separate one, so this distinguishes the physical interface among MAC-sharing candidates. `#[serde(default)]` so a daemon predating this field is read as `false` on every row — never worse than today's behavior.
    - `native_vlan_id` string, uuid, nullable: Native/untagged VLAN entity ID on this port (resolved from Q-BRIDGE dot1qPvid)
    - `neighbor_candidates` InterfaceNeighborEvidence[]: Raw LLDP/CDP evidence this scan heard on the port — the wire shape a **current** daemon submits, one entry per distinct LLDP or CDP record. Drained into `interface_neighbor_ candidates` by the discovery ingest path (`InterfaceService::create_or_update_from_ discovery`); never read anywhere else. Not `skip_serializing`: this field is the daemon's *outgoing* discovery payload as much as it is the server's read model, and that attribute has no notion of direction — it silently dropped every daemon's submitted evidence before the request ever left the process (found investigating the GH #701 candidate-persistence regression; nothing downstream of the wire was ever at fault). Harmless for API responses: `create_or_update_from_discovery` takes this field via `mem::take` before returning or persisting `Interface`, and it is not a stored column, so nothing read back from the database or echoed in a response ever has it populated.
      - `cdp_address` string, nullable: Remote management IP from CDP (cdpCacheAddress). IPv4 or IPv6.
      - `cdp_device_id` string, nullable: Remote device ID from CDP (typically hostname, locally unique)
      - `cdp_platform` string, nullable: Remote platform from CDP (e.g., "Cisco IOS")
      - `cdp_port_id` string, nullable: Remote port ID from CDP
      - `evidence_source` union: How a discovered value reached us. Every variant here has something that writes it. Sources with no producer are deliberately absent: a rung the applier can never see is a rung nothing can be tested against, and the tier decision is better made by whoever writes the reader than guessed in advance. **Do not derive `Ord`.** A derive compares the variant and then the payload, which would make `Probe(Docker) < Probe(Snmp)` on declaration order alone. Ordering is only ever [`Self::rank`]. **Externally tagged**, which is serde's default and is left unstated for that reason. Thirty-three of these variants carry nothing, and a tag on a variant with no content is a key that distinguishes nothing — `"Unspecified"`, not `{"type":"Unspecified"}`, in every row of every column. The two that do carry a [`ClientProbe`] keep it under their own name, `{"Probe":"Snmp"}`, which tells them apart from each other and from every bare name.
        - 'Unspecified': Provenance unknown: a payload from a daemon predating the rung, a row predating the column, or a source this binary does not recognise. Below everything, so it never displaces a value we know the origin of and anything may improve on it.
        - 'OwnAddress': The host's own address, standing in for a name it does not have. Nothing on this server writes it any more: an address is an identifier, and the display ladder shows it without a copy in `name`. Daemons up to v0.17.14 still send it, and it is kept so their payloads deserialise before ingest drops the copy.
        - 'ServiceMatch': Implied by a matched service definition.
        - 'LldpNeighbourAddress': A /24 (or /64) convention around an address a neighbour advertised. LLDP carries no netmask TLV, so the range is our invention rather than the neighbour's claim.
        - 'CipVendorId': A manufacturer string synthesised from a numeric CIP vendor ID, because we ship no ODVA vendor table. Distinct from [`Self::Probe`] over the same transport for the reason the module doc gives: the variant names what was read, not how it arrived, and `"CIP vendor 1"` is our own construction rather than anything the device emitted.
        - 'SysDescrMatch': An operating system matched in SNMP `sysDescr` against a Recog fingerprint. The text is the device's own, but the OS is our reading of it, so it ranks below anything read off the host.
        - 'SysObjectIdMatch': An operating system implied by an SNMP `sysObjectID` a Recog fingerprint names. Inferred for the same reason as [`Self::SysDescrMatch`].
        - 'LldpSysDescMatch': An operating system matched in the system description an LLDP neighbour advertised for itself (`lldpRemSysDesc`). Inferred for the same reason as [`Self::SysDescrMatch`].
        - 'SshBannerMatch': An operating system matched in an SSH server's identification string, such as the `Ubuntu-3ubuntu13` a distribution's OpenSSH package appends.
        - 'HttpServerMatch': An operating system matched in an HTTP `Server` header, such as `Microsoft-IIS/10.0`.
        - 'X509SubjectMatch': A device or OS matched in the subject of a TLS certificate the host served, such as the `OU=RV042` a Linksys router's self-signed certificate carries.
        - 'X509IssuerMatch': A device or OS matched in the issuer of a TLS certificate the host served: an appliance whose factory certificate names its own maker as the CA.
        - 'HtmlTitleMatch': A device or OS matched in the `<title>` of a page the host's web server returned.
        - 'HttpWwwAuthMatch': A device or OS matched in the realm of an HTTP `WWW-Authenticate` challenge.
        - 'HttpCookieMatch': A device or OS matched in a cookie the host's web server set.
        - 'FaviconMatch': A device or OS matched by the MD5 hash of the host's `/favicon.ico`.
        - 'FtpBannerMatch': A device or OS matched in an FTP server's greeting.
        - 'TelnetBannerMatch': A device or OS matched in a Telnet banner.
        - 'RtspServerMatch': A device or OS matched in an RTSP server's `Server` header.
        - 'TcpStackMatch': An operating system family matched in the TCP/IP stack's reply to a connection: the initial TTL, window, MSS and TCP option layout of its SYN-ACK. The weakest match: it names only a family, and is applied only to a host nothing else names an OS for.
        - 'DnsSdDeviceInfoMatch': An operating system matched in an mDNS `_device-info._tcp` record, such as a Mac's `model=MacBookPro18,3`.
        - 'DnsSdAirPlayMatch': An operating system matched in the `model` an mDNS `_airplay._tcp` record carries, such as a Mac's `model=Mac17,2`. Macs that share nothing still advertise AirPlay.
        - 'InterfaceNameMatch': A subnet type guessed from the name of the interface that holds the range: `wg0` for a VPN tunnel, `br-guest` for a guest network. The name is the operating system's; the type is our reading of it.
        - 'DnsSdInstanceName': A DNS-SD instance label — the Chromecast `fn=Living Room TV`, typed by a person during device setup.
        - 'DnsSdHostname': A hostname a device announced for itself over mDNS: the SRV target, such as `chromecast-a1b2c3.local`. Machine-generated, unlike the instance label beside it.
        - 'DnsSdServicePort': A port a device advertised for one of its services in an mDNS SRV record, such as 631 for `_ipp._tcp`. Recorded where the port scan did not cover that port.
        - 'LldpChassisId': A chassis ID a neighbour advertised for itself.
        - 'Lldpd': An LLDP neighbour the `lldpd` service on the daemon's own host heard on one of its ports. Distinct from [`Self::LldpChassisId`], which is the identity a neighbour advertised: this names the listener that recorded the adjacency.
        - 'ReverseDns': Reverse DNS. A known speaker that is not the subject.
        - 'ForwardingTable': A router's `ipNetToMediaTable` cache, or a switch's bridge FDB. One variant for both: each is "a device telling us about a MAC that is not its own", with no basis to rank one above the other.
        - 'ArpReply': We broadcast an ARP request for a specific address and something replied claiming it.
        - 'IcmpEcho': We sent an ICMP echo request to the address and it answered.
        - 'PortScan': We opened a TCP connection to a port, or a UDP probe to it was answered. Stamps the port, and the address of a host found only this way.
        - 'DaemonSelfReport': The daemon reading its own host: NIC and routing configuration, its own hostname and its OS. `Native` for the reason [`Self::ProfinetDcp`] is: the host describes itself, first-hand, with no transport or third party between the reading and the machine. It outranks [`Self::ContainerRuntimeInfo`], whose engine may run in a VM on this machine.
        - 'ProfinetDcp': A PROFINET DCP Identify exchange: we sent the request and the transport correlated the reply to the station that sent it. `Native`, not merely `Queried` — like [`Self::Probe`] over [`ClientProbe::ModbusTcp`]/`EtherNetIp`/`OpcUa`, the protocol is the device's own rather than a generic MIB approximating it. A bare variant rather than `Probe(ClientProbe)` on purpose: [`ClientProbe`] is scoped to application probes reached over an already-open TCP/UDP port (`every_client_probe_variant_has_a_producer` enforces that every variant has an `AppProbe` producer), and DCP is raw Ethernet with no port at all.
        - 'ContainerRuntimeInfo': A container engine (Docker, Podman) reporting the machine it runs on, from its `info` endpoint: the host OS, its release and kernel. `Queried`, not `Native`: we chose the engine and authenticated to it, but the machine it describes is the host only when the engine runs on it directly. Docker Desktop, OrbStack, Colima, Rancher Desktop and `podman machine` run the engine in a Linux VM, and `info` describes that VM. A bare variant rather than `Probe(Docker)`, which is the container listing; this is a different exchange.
        - 'HypervisorConfig': The configuration of the hypervisor or container runtime that runs the guest, read through its API: the MAC of a Proxmox guest's virtual NIC or of a container's macvlan endpoint, and the hostname and distribution a Proxmox LXC container's config sets. `Native` for the reason [`Self::ProfinetDcp`] is: the hypervisor or runtime assigned that MAC, keeps it for the guest's or container's life and puts it on the wire for it, so its record is the NIC's own identity, not a third party's report of it. That is what lets a guest with no address still be identified by its NIC. A bare variant rather than `Probe(Proxmox)` or `Probe(Docker)`, which cover everything else those APIs report and stay `Reported`.
        - 'GuestAgent': Software inside a guest read this from the guest's own operating system and answered the hypervisor's API: the QEMU guest agent behind Proxmox, and the same role VMware Tools and Hyper-V integration services fill. `Native` for the reason [`Self::ProfinetDcp`] is: the guest describes itself, over a channel the hypervisor binds to that one guest, so it is first-hand, not the hypervisor's report of the guest (`Probe(Proxmox)`).
        - 'SshScript': A script the operator wrote, run on the host over SSH, printed it. Queried: we chose the host, authenticated to it and read the answer from its own shell. Human-authored, because the operator chose what the script reports, which is what puts it above the machine values SNMP and LLDP emit about the same fields.
        - object: A value the thing emitted about itself, over whatever transport [`ClientProbe`] names.
          - `Probe` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
        - object: A value a person entered into the thing we read it from, carried back over the same transport: SNMP `sysLocation`, a name set in a controller.
          - `Authored` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
        - 'Manual': A person asserted it in Scanopy. Nothing discovery reads displaces it.
      - `lldp_chassis_id` union: LLDP Chassis ID subtypes per IEEE 802.1AB. The chassis ID identifies the remote device. Different network equipment may use different subtypes depending on configuration and capabilities.
        - object: Subtype 1: Chassis component (e.g., backplane serial number)
          - `subtype` 'ChassisComponent', required
          - `value` string, required: Subtype 1: Chassis component (e.g., backplane serial number)
        - object: Subtype 2: Interface alias (ifAlias from IF-MIB)
          - `subtype` 'InterfaceAlias', required
          - `value` string, required: Subtype 2: Interface alias (ifAlias from IF-MIB)
        - object: Subtype 3: Port component (e.g., backplane port number)
          - `subtype` 'PortComponent', required
          - `value` string, required: Subtype 3: Port component (e.g., backplane port number)
        - object: Subtype 4: MAC address (most common)
          - `subtype` 'MacAddress', required
          - `value` string, required: Subtype 4: MAC address (most common)
        - object: Subtype 5: Network address (IP address stored as string)
          - `subtype` 'NetworkAddress', required
          - `value` string, required: Subtype 5: Network address (IP address stored as string)
        - object: Subtype 6: Interface name (ifName from IF-MIB)
          - `subtype` 'InterfaceName', required
          - `value` string, required: Subtype 6: Interface name (ifName from IF-MIB)
        - object: Subtype 7: Locally assigned (device-specific identifier)
          - `subtype` 'LocallyAssigned', required
          - `value` string, required: Subtype 7: Locally assigned (device-specific identifier)
      - `lldp_mgmt_addr` string, nullable: Remote management IP from LLDP neighbor (lldpRemManAddr). IPv4 or IPv6.
      - `lldp_port_desc` string, nullable: Remote port description from LLDP neighbor (lldpRemPortDesc)
      - `lldp_port_id` union: LLDP Port ID subtypes per IEEE 802.1AB. The port ID identifies the specific port on the remote device.
        - object: Subtype 1: Interface alias (ifAlias from IF-MIB)
          - `subtype` 'InterfaceAlias', required
          - `value` string, required: Subtype 1: Interface alias (ifAlias from IF-MIB)
        - object: Subtype 2: Port component (e.g., backplane port number)
          - `subtype` 'PortComponent', required
          - `value` string, required: Subtype 2: Port component (e.g., backplane port number)
        - object: Subtype 3: MAC address
          - `subtype` 'MacAddress', required
          - `value` string, required: Subtype 3: MAC address
        - object: Subtype 4: Network address (IP address stored as string)
          - `subtype` 'NetworkAddress', required
          - `value` string, required: Subtype 4: Network address (IP address stored as string)
        - object: Subtype 5: Interface name (ifName from IF-MIB)
          - `subtype` 'InterfaceName', required
          - `value` string, required: Subtype 5: Interface name (ifName from IF-MIB)
        - object: Subtype 6: Agent circuit ID (used by some providers)
          - `subtype` 'AgentCircuitId', required
          - `value` string, required: Subtype 6: Agent circuit ID (used by some providers)
        - object: Subtype 7: Locally assigned (device-specific identifier)
          - `subtype` 'LocallyAssigned', required
          - `value` string, required: Subtype 7: Locally assigned (device-specific identifier)
      - `lldp_sys_desc` string, nullable: Remote system description from LLDP neighbor (lldpRemSysDesc) - platform info
      - `lldp_sys_name` string, nullable: Remote system name from LLDP neighbor (lldpRemSysName)
    - `oper_status` 'Up' | 'Down' | 'Testing' | 'Unknown' | 'Dormant' | 'NotPresent' | 'LowerLayerDown': SNMP ifOperStatus values per IF-MIB RFC 2863
    - `site_id` string, uuid, required: The site this entity belongs to.
    - `speed_bps` integer, nullable: Interface speed from ifSpeed/ifHighSpeed in bits per second
    - `vlan_ids` string[], nullable: Tagged VLAN entity IDs on this port (resolved from Q-BRIDGE dot1qVlanCurrentEgressPorts)
    - `vlan_membership_source` union: How a discovered value reached us. Every variant here has something that writes it. Sources with no producer are deliberately absent: a rung the applier can never see is a rung nothing can be tested against, and the tier decision is better made by whoever writes the reader than guessed in advance. **Do not derive `Ord`.** A derive compares the variant and then the payload, which would make `Probe(Docker) < Probe(Snmp)` on declaration order alone. Ordering is only ever [`Self::rank`]. **Externally tagged**, which is serde's default and is left unstated for that reason. Thirty-three of these variants carry nothing, and a tag on a variant with no content is a key that distinguishes nothing — `"Unspecified"`, not `{"type":"Unspecified"}`, in every row of every column. The two that do carry a [`ClientProbe`] keep it under their own name, `{"Probe":"Snmp"}`, which tells them apart from each other and from every bare name.
      - 'Unspecified': Provenance unknown: a payload from a daemon predating the rung, a row predating the column, or a source this binary does not recognise. Below everything, so it never displaces a value we know the origin of and anything may improve on it.
      - 'OwnAddress': The host's own address, standing in for a name it does not have. Nothing on this server writes it any more: an address is an identifier, and the display ladder shows it without a copy in `name`. Daemons up to v0.17.14 still send it, and it is kept so their payloads deserialise before ingest drops the copy.
      - 'ServiceMatch': Implied by a matched service definition.
      - 'LldpNeighbourAddress': A /24 (or /64) convention around an address a neighbour advertised. LLDP carries no netmask TLV, so the range is our invention rather than the neighbour's claim.
      - 'CipVendorId': A manufacturer string synthesised from a numeric CIP vendor ID, because we ship no ODVA vendor table. Distinct from [`Self::Probe`] over the same transport for the reason the module doc gives: the variant names what was read, not how it arrived, and `"CIP vendor 1"` is our own construction rather than anything the device emitted.
      - 'SysDescrMatch': An operating system matched in SNMP `sysDescr` against a Recog fingerprint. The text is the device's own, but the OS is our reading of it, so it ranks below anything read off the host.
      - 'SysObjectIdMatch': An operating system implied by an SNMP `sysObjectID` a Recog fingerprint names. Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'LldpSysDescMatch': An operating system matched in the system description an LLDP neighbour advertised for itself (`lldpRemSysDesc`). Inferred for the same reason as [`Self::SysDescrMatch`].
      - 'SshBannerMatch': An operating system matched in an SSH server's identification string, such as the `Ubuntu-3ubuntu13` a distribution's OpenSSH package appends.
      - 'HttpServerMatch': An operating system matched in an HTTP `Server` header, such as `Microsoft-IIS/10.0`.
      - 'X509SubjectMatch': A device or OS matched in the subject of a TLS certificate the host served, such as the `OU=RV042` a Linksys router's self-signed certificate carries.
      - 'X509IssuerMatch': A device or OS matched in the issuer of a TLS certificate the host served: an appliance whose factory certificate names its own maker as the CA.
      - 'HtmlTitleMatch': A device or OS matched in the `<title>` of a page the host's web server returned.
      - 'HttpWwwAuthMatch': A device or OS matched in the realm of an HTTP `WWW-Authenticate` challenge.
      - 'HttpCookieMatch': A device or OS matched in a cookie the host's web server set.
      - 'FaviconMatch': A device or OS matched by the MD5 hash of the host's `/favicon.ico`.
      - 'FtpBannerMatch': A device or OS matched in an FTP server's greeting.
      - 'TelnetBannerMatch': A device or OS matched in a Telnet banner.
      - 'RtspServerMatch': A device or OS matched in an RTSP server's `Server` header.
      - 'TcpStackMatch': An operating system family matched in the TCP/IP stack's reply to a connection: the initial TTL, window, MSS and TCP option layout of its SYN-ACK. The weakest match: it names only a family, and is applied only to a host nothing else names an OS for.
      - 'DnsSdDeviceInfoMatch': An operating system matched in an mDNS `_device-info._tcp` record, such as a Mac's `model=MacBookPro18,3`.
      - 'DnsSdAirPlayMatch': An operating system matched in the `model` an mDNS `_airplay._tcp` record carries, such as a Mac's `model=Mac17,2`. Macs that share nothing still advertise AirPlay.
      - 'InterfaceNameMatch': A subnet type guessed from the name of the interface that holds the range: `wg0` for a VPN tunnel, `br-guest` for a guest network. The name is the operating system's; the type is our reading of it.
      - 'DnsSdInstanceName': A DNS-SD instance label — the Chromecast `fn=Living Room TV`, typed by a person during device setup.
      - 'DnsSdHostname': A hostname a device announced for itself over mDNS: the SRV target, such as `chromecast-a1b2c3.local`. Machine-generated, unlike the instance label beside it.
      - 'DnsSdServicePort': A port a device advertised for one of its services in an mDNS SRV record, such as 631 for `_ipp._tcp`. Recorded where the port scan did not cover that port.
      - 'LldpChassisId': A chassis ID a neighbour advertised for itself.
      - 'Lldpd': An LLDP neighbour the `lldpd` service on the daemon's own host heard on one of its ports. Distinct from [`Self::LldpChassisId`], which is the identity a neighbour advertised: this names the listener that recorded the adjacency.
      - 'ReverseDns': Reverse DNS. A known speaker that is not the subject.
      - 'ForwardingTable': A router's `ipNetToMediaTable` cache, or a switch's bridge FDB. One variant for both: each is "a device telling us about a MAC that is not its own", with no basis to rank one above the other.
      - 'ArpReply': We broadcast an ARP request for a specific address and something replied claiming it.
      - 'IcmpEcho': We sent an ICMP echo request to the address and it answered.
      - 'PortScan': We opened a TCP connection to a port, or a UDP probe to it was answered. Stamps the port, and the address of a host found only this way.
      - 'DaemonSelfReport': The daemon reading its own host: NIC and routing configuration, its own hostname and its OS. `Native` for the reason [`Self::ProfinetDcp`] is: the host describes itself, first-hand, with no transport or third party between the reading and the machine. It outranks [`Self::ContainerRuntimeInfo`], whose engine may run in a VM on this machine.
      - 'ProfinetDcp': A PROFINET DCP Identify exchange: we sent the request and the transport correlated the reply to the station that sent it. `Native`, not merely `Queried` — like [`Self::Probe`] over [`ClientProbe::ModbusTcp`]/`EtherNetIp`/`OpcUa`, the protocol is the device's own rather than a generic MIB approximating it. A bare variant rather than `Probe(ClientProbe)` on purpose: [`ClientProbe`] is scoped to application probes reached over an already-open TCP/UDP port (`every_client_probe_variant_has_a_producer` enforces that every variant has an `AppProbe` producer), and DCP is raw Ethernet with no port at all.
      - 'ContainerRuntimeInfo': A container engine (Docker, Podman) reporting the machine it runs on, from its `info` endpoint: the host OS, its release and kernel. `Queried`, not `Native`: we chose the engine and authenticated to it, but the machine it describes is the host only when the engine runs on it directly. Docker Desktop, OrbStack, Colima, Rancher Desktop and `podman machine` run the engine in a Linux VM, and `info` describes that VM. A bare variant rather than `Probe(Docker)`, which is the container listing; this is a different exchange.
      - 'HypervisorConfig': The configuration of the hypervisor or container runtime that runs the guest, read through its API: the MAC of a Proxmox guest's virtual NIC or of a container's macvlan endpoint, and the hostname and distribution a Proxmox LXC container's config sets. `Native` for the reason [`Self::ProfinetDcp`] is: the hypervisor or runtime assigned that MAC, keeps it for the guest's or container's life and puts it on the wire for it, so its record is the NIC's own identity, not a third party's report of it. That is what lets a guest with no address still be identified by its NIC. A bare variant rather than `Probe(Proxmox)` or `Probe(Docker)`, which cover everything else those APIs report and stay `Reported`.
      - 'GuestAgent': Software inside a guest read this from the guest's own operating system and answered the hypervisor's API: the QEMU guest agent behind Proxmox, and the same role VMware Tools and Hyper-V integration services fill. `Native` for the reason [`Self::ProfinetDcp`] is: the guest describes itself, over a channel the hypervisor binds to that one guest, so it is first-hand, not the hypervisor's report of the guest (`Probe(Proxmox)`).
      - 'SshScript': A script the operator wrote, run on the host over SSH, printed it. Queried: we chose the host, authenticated to it and read the answer from its own shell. Human-authored, because the operator chose what the script reports, which is what puts it above the machine values SNMP and LLDP emit about the same fields.
      - object: A value the thing emitted about itself, over whatever transport [`ClientProbe`] names.
        - `Probe` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - object: A value a person entered into the thing we read it from, carried back over the same transport: SNMP `sysLocation`, a name set in a controller.
        - `Authored` 'Docker' | 'Gnmi' | 'Podman' | 'Snmp' | 'UnifiController' | 'InstantOn' | 'Proxmox' | 'ModbusTcp' | 'OpcUa' | 'EtherNetIp' | 'Sip' | 'Ssh' | 'Ftp' | 'Telnet' | 'Rtsp' | 'Nut' | 'EpicsCa' | 'ZabbixAgent' | 'CheckMkAgent' | 'Smb' | 'Ldap' | 'Kerberos' | 'MySql' | 'PostgreSql' | 'MsSql' | 'MongoDb' | 'Redis' | 'Cassandra' | 'Kafka' | 'Amqp' | 'Mqtt' | 'OracleTns' | 'Rdp' | 'Nfs' | 'DnsTcp' | 'DockerSwarm' | 'Tls' | 'Ike' | 'OpenVpn' | 'Zmtp' | 'Bacula' | 'BeszelAgent' | 'H323' | 'SnmpEngine' | 'DockerPing' | 'PodmanPing' | 'Ipp' | 'Lpd' | 'SpotifyConnect' | 'Vnc' | 'AppleLockdown' | 'DnsUdp' | 'Ntp' | 'Dhcp' | 'Bacnet' | 'Tftp' | 'Mgcp' | 'GoogleWifi', required: Types of client probes that run before service matching. The probe result (success/failure) is pre-computed; Pattern::ClientResponse just checks whether it succeeded. Two types of producer fill this: the credentialed `DiscoveryIntegration`s, and the non-credentialed [`AppProbe`](crate::daemon::utils::app_probe::AppProbe)s. Every variant needs one — a variant nothing produces gives a service definition a pattern that can never match, and `every_client_probe_variant_has_a_producer` is what now says so.
      - 'Manual': A person asserted it in Scanopy. Nothing discovery reads displaces it.
    - `created_at` string, date-time, required: When this record was first created.
    - `display_name` string, nullable: What to call this interface when it has no `if_alias`/`if_descr`: the MAC it was identified by, or "Interface" when it has neither. Read-only and computed from [`Interface::display_name`] — the same ladder topology port labels an interface with, so it cannot be called one thing in a list and another on the map. Set on every interface read from storage, so every endpoint that returns one carries it; absent on a daemon's own submission, and ignored on write.
    - `first_discovery_id` string, uuid, nullable: The discovery that first observed this entity.
    - `id` string, uuid, required: Server-assigned unique identifier.
    - `last_discovery_id` string, uuid, nullable: The most recent discovery that observed this entity.
    - `last_seen_at` string, date-time: When a discovery last observed this entity.
    - `lineage_id` string, uuid, nullable: Stable identifier shared by every revision of the same entity across its history.
    - `updated_at` string, date-time, required: When this record was last modified.
    - `valid_from` string, date-time: Start of the interval this revision was current for (SCD2 history).
    - `valid_to` string, date-time, nullable: End of the interval this revision was current for. `null` while it is the live revision.
  - `error` string, nullable: Not sent on a successful response. Failure messages arrive in an `ApiErrorResponse`.
  - `meta` ApiMeta, required: API metadata included in all responses
    - `api_version` integer, required: API version (integer, increments on breaking changes)
    - `server_version` string, required: Server version (semver)
  - `success` boolean, required: Always `true` on a successful response.

## Other responses

- `404`: Interface not found

## Changes

- **2026-10-31** `c94279effef3`: 10 warning
  - added the new `Lpd` enum value to the `data/allOf[#/components/schemas/InterfaceBase]/allOf[#/components/schemas/FdbMacs]/fdb_macs_source/oneOf[subschema #40: Probe]/Probe` response property for the response status `200`
  - added the new `Lpd` enum value to the `data/allOf[#/components/schemas/InterfaceBase]/allOf[#/components/schemas/FdbMacs]/fdb_macs_source/oneOf[subschema #41: Authored]/Authored` response property for the response status `200`
  - added the new `Lpd` enum value to the `data/allOf[#/components/schemas/InterfaceBase]/allOf[#/components/schemas/MacEvidence]/mac_address_source/oneOf[subschema #40: Probe]/Probe` response property for the response status `200`
  - added the new `Lpd` enum value to the `data/allOf[#/components/schemas/InterfaceBase]/allOf[#/components/schemas/MacEvidence]/mac_address_source/oneOf[subschema #41: Authored]/Authored` response property for the response status `200`
  - …6 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/scanopy/apis/scanopy-api/changes/api/v1/interfaces/:id/get.md)

---

[API](https://skmtc.dev/scanopy/apis/scanopy-api.md) - [All operations](https://skmtc.dev/scanopy/apis/scanopy-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scanopy/apis/scanopy-api/revisions/966ba786bdb5?raw)
