BGPScout MCP - 185 tools

Connect an AI assistant to BGPScout's internet-routing intelligence: search ASNs/IXPs/facilities/CDNs/traceroutes, look up IPs & prefixes, find sales prospects, and take account actions.

Connect (Claude / Claude Desktop): add a custom connector with URL https://bgpscout.io/mcp → authorize (OAuth).
Connect (OpenWebUI / OpenAPI): add an OpenAPI tool server, URL https://bgpscout.io/mcp (spec at /mcp/openapi.json), Auth = Bearer with an API key from /account (or header {"X-API-Key":"KEY"}).
Tip: call list_tools from your assistant to enumerate everything on demand.

Tools by category

Discovery 1

list_toolsDiscover all available BGPScout tools, grouped by category. Call this first to see the full capability set (search, lookup, prospecting, intelligence, account actions). Optional: category to filter.

ASN lookup & compare 10

lookup_asnLook up detailed information about an ASN, including its PoP/facility count and IXP count. Location caveat: the record's latitude/longitude are the centroid of the registered POSTAL CODE, never the street address; the `location` field gives the resolved point with its provenance and precision, which may be a geocoded address, a data-centre facility, an exchange, or a country centroid. Do not report an approximate position as an address.
search_asnsSearch ASNs with rich filters (name/asn, country, state, city, rir, traffic level, IPv6, on-IX, MANRS, RPKI, network type, asn_type flag, CDN provider, min/max PoPs/IXPs/peers/downstreams). PEERS CAVEAT (#264/#422): peer/downstream bounds and their sorts read counts of observed BGP AS_PATH adjacencies, which is NOT a peer list - it conflates transit, settlement-free peering and sibling relationships. Counts come from a curated multi-collector RouteViews + RIPE RIS build (#208); get_asn_neighbours returns the exact collector set and build date in observed_from. They are FLOORS, not censuses, and more collectors does not lift that ceiling much: a RIB holds the best path per prefix per collector peer, so peering that is never the best path anywhere (the normal case for IXP route-server peering) is invisible to every collector. Measured 2026-08-24: ASNs that are route-server peers at a single exchange with 200+ other route-server peers on it show a mean of 6.69 observed adjacencies here. Do not state a peer count as a fact without that caveat. An ASN with no observed adjacency at all is UNOBSERVED, not zero - it is silently excluded from min/max peer and downstream filters rather than being treated as zero, and both sorts place unobserved ASNs last regardless of direction (#67). Downstream direction means observed nearer-to-origin AS_PATH adjacency; it is not proof of a commercial customer relationship.
bulk_lookup_asnsSummarize several ASNs at once (name, country, traffic, PoPs, IXP counts and domestic share) in one call. IXP fields are null with an ixp_data note where the ASN has no PeeringDB record - null means not surveyed, never zero exchanges (#366)
compare_asnsCompare multiple ASNs side by side - PoPs, IXPs, prefixes, routing quality, announced IPv4 address total, BGP downstream count and the owning registry organisation. Same columns as the /compare page. CAVEATS: `ipv4_addresses` is the merged union of announced space (more-specifics collapsed), and null means the network announces no IPv4 - it is not zero. `bgp_downstream_networks` comes from AS_PATH adjacency, which does NOT label relationships: an adjacency may be transit OR peering, and it is not proven hierarchy. It is a FLOOR, not a census - a RIB holds only the best path per prefix per collector peer, so adjacencies that are never anyone's best path (typical of settlement-free IXP peering) are missing regardless of collector count (#208) - and it is null, not 0, when this ASN was never observed adjacent to anything by any configured collector (#67). `org` is resolved through the RIR allocation record, not asn.org_id. `org.org_url` is the canonical browser link for that organisation (models/org-slug.js), null when it could not be resolved; it replaces the old `org.url`, which was the /orgs/{registry}/{org_key} fallback form rather than the canonical slug. `boomerang_rate` and `crossing_rate` are DIFFERENT measurements and are returned separately: crossing_rate is traces that left the country, boomerang_rate is traces that left and came back (#126, #485). `pop_count` and `ixp_count` are null, never 0, when PeeringDB has no record or an empty one, with the reason in `pop_count_note` / `ixp_count_note` (#496). Every ASN you ask for comes back in the order you asked, and one we hold no row for carries an `error` field rather than being dropped (#498).
get_asn_historyHistorical trends for an ASN: facility/IXP counts, total IXP capacity, and prefix counts over time
get_route_historyHistorical view of an ASN's observed adjacency set (monthly, since 2001-10-26) or a prefix's origin-set changes (daily, since the series started - no backfill). THREE states throughout and they must not be collapsed: `gap` (no observation covering that period - we did not look), observed-absent (we looked and it was not there), observed-present. A gap is NOT a withdrawal. Prefix history before `series_start` is `unknown`, never 'not announced'. AS_PATH change points are NOT available: raw MRT is not retained, so `path_history` returns not_available rather than an empty array.
get_bgp_stateCurrent visible origin-set for an ASN, a prefix or an IP address, from the platform's nightly internal snapshot - NOT a live query (this platform has no live BGP feed access). Every response carries a `snapshot` block stating freshness (fresh/stale/unavailable) and provenance, read at request time. MOAS-aware: a prefix's `origins` array is never reduced to one row. `path_observation` is always `not_available` (raw AS_PATH is never retained). `at` (an ISO date) replays a prefix or IP's origin-set history to that date and is NOT supported for an ASN resource (returns a structured refusal, not approximated current data). `limit`/`cursor` paginate an ASN's prefix list.
get_asn_neighboursEvery ASN observed adjacent to this one in BGP AS_PATHs, in BOTH directions - this is the tool for "who does X peer with". CAVEATS: AS_PATH does NOT label relationships, so an adjacency may be transit OR settlement-free peering OR a sibling; it is not proof of a commercial arrangement. Direction is "seen nearer/further from the origin", an observation and not proven hierarchy. Built from a curated multi-collector RouteViews + RIPE RIS set; the response's observed_from field names the exact collectors and the build date, so do not describe the coverage from memory. A sparse result is mostly a statement about collector visibility, not about the network, and it stays that way at any collector count: a RIB carries only the best path per prefix per collector peer, so IXP route-server peering is largely invisible here (#208). For networks that merely share an exchange - opportunity rather than observation - use get_asn_ixp_colocated instead.
get_asn_ixp_colocatedNetworks present on at least one of the same internet exchanges as this ASN, from PeeringDB membership, ranked by shared exchanges. NOT A PEER LIST: co-presence on a fabric is a peering OPPORTUNITY, and two networks can share an exchange and exchange no traffic. Covers only ASNs with a PeeringDB record and a listed port. For neighbours actually observed in BGP, use get_asn_neighbours.
get_asn_peersDEPRECATED ALIAS for get_asn_ixp_colocated - despite the name it returns IXP co-presence, not peers. Prefer get_asn_neighbours for observed BGP adjacency, or get_asn_ixp_colocated for shared exchanges.

ASN presence 8

get_asn_facilitiesList the data-center facilities/PoPs a network (ASN) is present in, with a total count. Use this to answer 'how many PoPs/facilities does ASN X have'. Sourced from PeeringDB, which is SELF-REPORTED. `pop_count` is null, never 0, when the network has no PeeringDB record or has one that lists no facilities, and `pop_count_note` says which - large carriers routinely leave the section empty (AS3356 Lumen is the reference case, #487). A null here means not disclosed; it never means the network has no PoPs. PAGING (#350/#562): `pop_count` is the FULL disclosed total and is never affected by `filter` or paging; `matched_count` is how many facilities match the current `filter` (or equals `pop_count` when no filter is given); `returned` is how many are in THIS page, and `truncated`/`next_offset` say whether more remain - a page is never passed off as a total (#501). Default limit 200 - AS6939 has 339 facilities, past the point of a useful single reply, so page through with `limit`/`offset`. FILTER: `filter` is a free-text, case- and diacritic-insensitive, multi-token AND search over name/address/city/state/country - country accepts a full name ("Canada") as well as the ISO code ("CA") - the exact matching the /asns/:asn web page's Interconnection Facilities panel runs server-side (models/panel-search.js), so this tool and that page cannot disagree about which facilities are Canadian. `filter_applied` echoes what was searched back in the response so a caller relaying a filtered count (e.g. "16 Canadian exchanges") cannot drop the qualifier.
get_asn_ixpsList the Internet Exchange Points (IXPs) an ASN peers at, with port speeds and total interconnection capacity. One row per DISTINCT exchange, with its individual ports nested under `ports` - a network commonly has several connections to the same exchange, so `ixp_count` (exchanges) and `port_count` (connections) are different numbers and `ixp_count` is the one that matches lookup_asn (#482). `total_capacity_gbps` sums ports. `ixp_count` is null, never 0, when PeeringDB has no record or an empty one, with the reason in `ixp_count_note` (#496). Counts only ports PeeringDB flags operational=true by default; pass include_non_operational to include down ports (#502). PAGING (#350/#562): `ixp_count` is the FULL disclosed total and is never affected by `filter` or paging; `matched_count` is how many exchanges match the current `filter` (or equals `ixp_count` when no filter is given); `returned` is how many are in THIS page, and `truncated`/`next_offset` say whether more remain - a page is never passed off as a total (#501). Default limit 200 - AS6939 is on 335 exchanges, which used to come back as a single ~112KB reply with no way to narrow it. FILTER: `filter` is a free-text, case- and diacritic-insensitive, multi-token AND search over exchange name/city/country (country accepts a full name like "Canada" as well as the ISO code "CA") and each exchange's peering-LAN IPv4/IPv6 addresses - the exact matching the /asns/:asn web page's Exchange Points panel runs server-side (models/panel-search.js), so `filter: "Canada"` here returns the same 16-of-335 set the page does. `filter_applied` echoes what was searched back in the response so a caller relaying a filtered count cannot drop the qualifier.
get_asn_cdn_cachesList the CDN edge caches hosted inside an ASN, grouped by provider with cache locations. Located providers: Google GGC, Netflix OCA, Meta FNA, Akamai. AWS CloudFront, Microsoft and Apple caches are reported separately in providers_present_without_locations - we know the ASN hosts them but never collected node locations (#191). total_caches counts LOCATED nodes only, so an ASN hosting only Apple caches reports 0 there and names Apple in that list; do not read total_caches: 0 as 'no caches'.
get_transit_providersAn ASN's upstreams from two sources: traceroute-observed Tier-1 handoffs (narrow, ~490 ASNs, but carries the handoff city) and BGP AS_PATH adjacency (far wider coverage, no location - the response's bgp_upstreams note gives the real shape rather than a number that would go stale). AS_PATH does not label relationships, so a BGP adjacency may be transit or peering.
find_ddos_protectedNetworks observed sitting behind a blanket DDoS scrubbing provider (Akamai Prolexic, Cloudflare Magic Transit, Global Secure Layer, Path, Imperva). Their routes were seen transiting a provider whose product IS the BGP announcement, so the service was live in the routing snapshot - this is evidence, not a contract, and absence does not mean unprotected. Distinct from the 'ddosm' tag, which means a network SELLS mitigation. Set exclusive=true for networks whose only upstreams are scrubbers.
get_asn_prefixesPaginate IPv4/IPv6 prefixes observed with an ASN as origin. Snapshot counts are true totals, not the size of this page. Missing or inconsistent coverage is explicit; private/reserved ASNs are labelled as anomalous collector observations, not registered networks.
get_prefix_countsGet IPv4/IPv6 prefix counts with history
get_asn_ipv6_reachabilityEvidence that a network's IPv6 actually WORKS, not just that it announces v6 space (#54). Returns the strongest level observed and every supporting observation with its date and vantage point. Levels, weakest to strongest: announced (announces v6 prefixes - NOT reachability evidence) < ixp_port (v6 configured on an IXP port, PeeringDB self-report) < aaaa (a name of theirs resolves AAAA) < path (a router in their own v6 space answered a traceroute) < icmp6 (their own space answered our ping) < tcp6 (a TCP handshake completed into their own space). An unconfirmed result means we have not observed it working - most ASNs have never been probed - and NEVER means the network has no IPv6.

Peering recommendations 3

get_recommended_ixpsIXPs this ASN should consider joining: exchanges seen in its traceroute paths, filtered to ones it can actually reach - a facility this ASN already has a presence in (tier 'facility'), or a city it already has a facility in (tier 'metro'). A candidate that clears neither is DROPPED, not ranked lower, however often it appears in a traceroute; traceroute-hop frequency is only a tie-break WITHIN a tier. An empty result with a non-zero raw_candidate_count means real candidates existed but none were physically reachable - a real finding, not missing data. Same ranking function as the ASN detail page's Recommended IXPs panel.
get_recommended_peersNetworks this ASN should consider peering with: candidates ranked by shared-infrastructure tier (shares a facility > already on a shared exchange > reachable via an IXP from get_recommended_ixps), with PeeringDB's disclosed peering policy (open/selective/restrictive/no, plus whether a balanced traffic ratio or a signed contract is required) as a secondary ranking signal and traceroute-hop frequency only as the final tie-break. A candidate clearing no tier is DROPPED, not ranked lower. peering_policy is null (not 'Restrictive') when PeeringDB has no disclosed answer - never treat null as a refusal. Same ranking function as the ASN detail page's Recommended Peers panel.
recommend_transitRank candidate Tier-1 transit providers by MEASURED round-trip latency from a source city to named destinations (Amazon, Google, Cloudflare, a named ISP, a literal ASN, an IP address, or a hostname) - answers 'from here, what transit gets me the best path to X'. RTT comes from the last RESPONDING hop of each matching traceroute (never from geolocating the destination IP - anycast destinations like Cloudflare/Google/Amazon geolocate to a head office, not to the site that actually answered, so this tool never reads destination geography at all). A candidate only appears under `ranked` for a target once it clears an evidence floor (min_observations distinct traces from min_sources distinct source ASNs, each with a usable RTT) - below that it is listed under `insufficient_evidence` with the exact shortfall, never silently ranked on a thin sample (#336/#337/#514). `no_data` lists candidates with zero matching traces at all - absence here means 'not measured', not 'no good path' (#67). `buyer_reachable` is set from your org's declared facility footprint (get_seller_profile) when you belong to one, else null - it is a cross-connect availability signal, not part of the ranking. An IP or hostname target is resolved LIVE (DNS + currently-announced covering BGP prefix, up to 10 per call, run in parallel) rather than from a corpus, so the resolved network is current as of the call - each such target's `resolution` field says how and when. This is evidence for a buying decision, not the decision itself: the platform holds no pricing, contract terms or port availability.

IP & prefix (whois) 7

lookupEverything we know about one IPv4 address, IPv6 address, CIDR or hostname, in a single call. Type is detected - no separate tool per input shape - and IPv6 is first-class. sections filters the payload: routing (covering prefix, origin ASN, more-specifics, bogon status - IANA special-use/reserved targets like documentation ranges resolve immediately, #480), geo (resolved location with EVERY candidate source and which one won), registration (RIR allocation, registered org with a method/confidence/evidence field - null with a reason rather than an unrelated org when the registry's opaque id is ambiguous across resource types, #489 - and contacts), rpki (Valid/Invalid/NotFound against the ROA set), rdns (PTR for an address; for a prefix, `forward_domains` is one row per registrable domain with a subdomain count and a `likely_wildcard` flag, so one wildcard record cannot crowd out every other domain and the payload stays small. The per-hostname `forward_records` list is OPT-IN via include_forward_records and is absent by default; `forward_records_included` says which you got, #488). Every section carries its own source and observation date so you can say how confident you are rather than presenting a guess as fact. Prefer this over lookup_ip and lookup_prefix, which answer narrower slices of the same question.
lookup_ipGeolocate an IP address (city/country/coordinates) and, when available, the ASN that announces it. `bogon` is set (and `geo`/`asn` are null) for IANA special-use/reserved space such as documentation ranges or RFC 1918 - these resolve immediately rather than paying for a routing-table scan guaranteed to miss (#480).
lookup_prefixFor an IPv4 CIDR (e.g. 8.8.8.0/24), the ASN that announces the covering prefix. `bogon` is set (and `announced_by` is null) for IANA special-use/reserved ranges - these resolve immediately rather than scanning the routing table for an announcement that cannot exist (#480).
get_asn_bogonsBogon prefixes an ASN announces - IANA special-use space (RFC 1918, loopback, documentation, multicast, …) or space no RIR has delegated. Omit asn to list the ASNs announcing the most bogons. severity: high (special-use) | medium (undelegated) | low (registry holds it reserved; advisory only)
get_asn_rpki_statusRPKI route-origin validation summary for one ASN, from the bulk validation of announced_prefix against rpki_roa (#551 slice 1). Four states: valid, invalid, notfound (the majority state - no ROA covers the prefix, NOT a failure), unavailable (could not be evaluated). Never presents notfound as invalid. Not incident detection - no baseline, no history, just the current verdict per prefix. See get_rpki_validation_history for the change-over-time series built on top of this.
get_rpki_validation_historyRPKI validation-state TRANSITIONS - when a prefix's verdict (valid/invalid/notfound/unavailable) or invalid REASON (wrong_asn/too_long/both) genuinely differed between two consecutive nightly runs of the bulk RPKI validator. This is a change-series over ROA/configuration drift, and it is explicitly NOT incident detection: the validator samples once per ~24h, so `detected_at` on every transition is when the DIFFERENCE was first noticed, never when the underlying ROA or announcement actually changed - the real change could have happened, and fully resolved, at any point inside that window. An event that both starts and ends between two nightly samples produces ZERO rows here, structurally, forever; that is the sampling rate, not a bug, and an empty `transitions` list must never be read as 'nothing happened' without also checking `latest_comparison_run` (see below). Never call a transition a hijack or an incident: per rpki_invalid_breakdown.py's own finding on the corpus, an RPKI-invalid announcement is usually a stale or misconfigured ROA, not an attack, and a transition INTO invalid inherits that same caveat. `latest_comparison_run.has_baseline` is a FIRST-CLASS FACT, distinct from an empty result (#67): has_baseline=0 means no prior observation existed for ANY prefix when that run executed (a from-cold-start seed, e.g. the very first run) - genuinely different from has_baseline=1 with transitions_found=0, which means a real comparison ran and found nothing to report. As of 2026-08-26 exactly two comparison runs exist (run 1: has_baseline=0, the cold start; run 2: has_baseline=1, transitions_found=0, a real quiet comparison) and BOTH will legitimately return an empty `transitions` array for any filter - that is correct given only one underlying nightly rpki_validate_announced.py execution has happened, not evidence this tool is broken. Keyed on (asn, cidr), never announced_prefix_id - that id is reassigned nightly by a rebuild-and-swap and is not stable across runs (verified: 1,392,531 distinct (asn,cidr) pairs for 1,392,531 announced_prefix rows). Pass asn alone for every transition touching that ASN's prefixes; add cidr for one exact prefix (and current_state is then also returned, the LATEST known baseline verdict for that pair); pass neither for the global recent-transitions feed. state/reason filter on the NEW (destination) state/reason of the transition.
get_rpki_comparison_runsAudit trail of backend/rpki_validation_history.py executions - one row per run, always exactly one regardless of how many prefixes exist, so this answers 'has the RPKI change-detection job actually been running' independent of whether it found anything. Each row's `has_baseline` is the #67 distinction get_rpki_validation_history depends on: 0 means no prior observation existed for ANY prefix when THAT run executed (first-run/cold-start), 1 means a real prior baseline existed and `transitions_found` is a genuine comparison result (0 there means 'compared, found nothing', not 'did not compare'). `prefixes_new`/`prefixes_vanished`/`prefixes_compared` describe that run's (asn,cidr) coverage against the prior baseline. This is diagnostic/meta - most callers asking about a specific prefix or ASN want get_rpki_validation_history instead.

IRR / RPSL 4

get_irr_objectsLook up IRR/RPSL objects (route, route6, aut-num, as-set) directly from the public IRR registries - RADB, RIPE, APNIC, ARIN, LEVEL3, NTTCOM - live, on demand (short-TTL cache; not a bulk mirror). Give ONE of: `prefix` (route/route6 exact-match), `asn` (aut-num plus an inverse origin lookup across route/route6), or `object_name` (an as-set/route-set/aut-num/maintainer primary key, e.g. "AS-EXAMPLE"). EVERY requested source is queried INDEPENDENTLY and every object it returns is kept separate - two sources both holding the same name are NEVER merged, because IRR data is genuinely contradictory across registries (measured live: RADB and RIPE hold two different "AS-GOOGLE" as-set objects with different members). `source_status` reports what happened for EACH requested source on EACH sub-query - `ok` (answered with data), `not_found` (answered "no entries", a real positive answer), `error` (answered but the reply was rejected), or `unreachable` (did not answer at all, e.g. connect timeout) - these are different facts and are never collapsed into one (#67); do not read a `not_found` on one source as evidence the object doesn't exist anywhere, and do not read a source missing from `objects` as "empty" without checking whether it was actually `unreachable`. Each returned object carries its raw RPSL (`raw_rpsl`), parsed `attributes` (each value is an array - RPSL attributes like `members`/`mnt-by`/`remarks` legitimately repeat), the object's OWN `source:` attribute (`source_attr`) alongside which registry you asked (`source`), and `source_authority` flagging any mismatch between the two. `history` is accepted but NOT supported in this build (no NRTM-fed mirror exists) - passing it returns an explicit `history_note` rather than silently ignoring it or fabricating history; the response is always the object as-of right now. `matched_count`/`returned`/`truncated` bound a large result (an inverse origin lookup on a big network can be thousands of route objects) - `cursor` is always null, since a single whois query answers in one response with nothing to page yet.
expand_as_setRecursively expand an AS-SET (or route-set) into every member ASN, from the public IRR registries, with a HARD depth limit, a hard member-count limit, and cycle detection - real as-sets nest, and some are self-referential. FAIL-CLOSED, per #554: `complete` is false, with an explicit `incompleteness_reasons` list, whenever the depth limit truncated a branch, the member limit was reached (further ASNs are NOT added once hit - never silently capped and called done), a nested set could not be resolved from any requested source, or a source query errored/was unreachable. A caller MUST check `complete` before treating `asns` as authoritative for anything filter-shaped - an incomplete expansion that looks like a normal-sized result is exactly the case that black-holes legitimate traffic if used to build a prefix filter (this build does not generate filters - #554 slice 1/2 only). A CYCLE is reported in `cycles` but, once detected, is NOT itself a reason for `complete: false` - the traversal simply does not re-descend into an ancestor, which is the correct, complete answer for a self-referential set (verified against a synthetic 3-cycle fixture; confirmed live against real registries that none of the as-sets sampled while building this - AS-EXAMPLE, AS-HURRICANE, AS-NTT, AS-GTTCUST, AS-TELIANET/AS1299 - contain one, so a live-observed cycle example does not exist yet in this dataset). MEASURED LIVE 2026-08-25: real customer-cone as-sets are large - GTT's AS-GTTCUST alone has 500+ direct member ASNs AND ~766 nested per-peer sets in ONE object; Arelion/Twelve99's AS-TELIANET reached 2,436 further nested sets just three levels down. Expanding either FULLY would run for a projected tens of minutes to hours even at a good-citizen one-query-per-second-per-host pace - this tool bounds the work instead of attempting it, and `query_count` on every response tells you exactly how many registry queries THIS call made. `sources` is a PRECEDENCE list, not a fan-out: for each nested set, the first source in the list that has the object is used (mirrors the whois `-s SOURCE1,SOURCE2` convention) - this tool does not query every source for every node, unlike get_irr_objects, which does. `address_family` is accepted but informational only in this build (as-set membership is not family-specific in RPSL); see `address_family_note` in the response.
compare_bgp_irr_rpkiPuts FOUR independent evidence classes side by side for an ASN or prefix (#554): what is actually ANNOUNCED (announced_prefix, real BGP RIB data), what IRR SAYS (live route/route6 objects via the same registries get_irr_objects queries), what RPKI SAYS (announced_prefix_rpki's bulk nightly validation, or an ad hoc rpki_roa coverage check when the prefix is not currently announced), and who the RIR DELEGATED FILES SAY the space belongs to (rir_allocation/rir_org - `matching` / `sibling` / `unrelated` / `unknown` relative to the registry organisation holding the origin AS). The product is the disagreement matrix: `matrix.all_agree` (the three-class bucket: announced, IRR origin match, RPKI valid), `matrix.announced_no_irr` (on the wire, no registered route object), `matrix.irr_not_announced` (registered in IRR, not seen on the wire), `matrix.rpki_invalid` (announced and RPKI-invalid) - each a `{count, prefixes}` list - plus `matrix.rir_matching` / `rir_sibling` / `rir_unrelated` / `rir_unknown` and `matrix.all_four_agree`, which carry `{count, cidrs}` (cidrs only; the full per-prefix evidence is always in `prefixes[].rir`). NONE of these buckets is mutually exclusive by design (an announced prefix can be BOTH missing from IRR AND rpki-invalid at once - that is two real facts, not a contradiction). Every row in `prefixes[]` keeps all four verdicts independently (`announced`, `irr`, `rpki_state`, `rir`) rather than collapsing them. NEVER CALL A MISMATCH A HIJACK: a prefix announced by an AS other than its allocation holder is usually a legitimate delegation, transfer or customer announcement, and `rir_unrelated` means only 'these two registry records do not identify the same organisation to us' - `rir_coverage.interpretation_note` restates this on every response. The RIR org resolution goes through the same corroborated resolver get_asn_allocations and lookup_rir_org use (#508/#489), and a `sibling` verdict is a byte-identical registered name under a DIFFERENT org id - a disclosure carrying `confidence: 'low'`, never a merge. Give ONE of `asn` (samples its announced prefixes, bounded by `sample_size` - default 200, max 2000; `announced_sample.sample_truncated` says if the sample is partial; the IRR side is a SINGLE inverse-origin query per source regardless of ASN size, same as get_irr_objects) or `prefix` (exact-match on both sides; if the prefix is not currently announced, RPKI falls back to an ad hoc rpki_roa coverage check, flagged in `rpki_coverage`). #67 applies throughout: `irr_coverage.query_complete` is false whenever a requested IRR source did not answer ok/not_found or the IRR result was truncated (`irr_coverage.incompleteness_reasons` says which); an announced prefix's `rpki_state` is `not_validated` when no row exists in announced_prefix_rpki (the nightly job has not scored it yet), which is NEVER the same fact as `notfound` (scored, no covering ROA exists); and `prefixes[].rir.status` has FOUR values that are never collapsed - `resolved` (a delegation record was read), `no_allocation_record` (checked, none covers this prefix), `lookup_failed` (the query failed, so it is unknown rather than absent) and `not_checked` (beyond `rir_sample_size`, unparseable, or `include_rir_allocation: false` - never queried). Do not treat a clean-looking matrix as complete without checking `announced_sample.sample_truncated`, `irr_coverage.query_complete` and `rir_coverage.sample_truncated`/`not_checked` first.
generate_prefix_filterSAFETY-CRITICAL: generates a router-pasteable prefix list for an AS-SET or a single ASN, sourced from live IRR route/route6 objects. PREFERS REFUSING OVER GUESSING (#554) - `refused: true` with no `filter` field and explicit `refusal_reasons` whenever: the AS-SET expansion (expand_as_set) is not `complete`; the resolved member-ASN count exceeds `max_asns` (default 50, hard ceiling 100 - refuses rather than silently truncating the ASN list); ANY requested IRR source did not answer ok/not_found for ANY member ASN, or that ASN's route lookup was truncated (irrObjectLookup's own 500-object cap - a single very large network, e.g. a big transit provider, WILL refuse under this, measured live against AS13335); or the resulting prefix list would be empty (an empty filter is a deny-all on most routers) unless `allow_empty: true` is passed explicitly. A refusal still returns full `provenance` - which registries, what each answered, when - so a human can see exactly what was tried. On success, `filter.prefixes` is EXACTLY what IRR registers - no ge/le broadening to shorter/longer masks is applied (a router-vendor convention, e.g. bgpq4's default "up to /24", that this tool does not assume on your behalf; see `note_no_ge_le`). Default `sources` excludes LEVEL3 (measured chronically unreachable, #554) so this tool is not refusing by default on a registry that never answers; pass it explicitly to include it, which also makes the call fail-closed on it like any other requested source. Every call, success or refusal, is logged to `prefix_filter_generation_run` (migration 191) for audit. `human_review_required: true` and `human_review_note` are always present, refused or not - THIS OUTPUT REQUIRES HUMAN REVIEW BEFORE USE ON A PRODUCTION ROUTER.

BGP communities 2

get_bgp_communitiesBGP community reference: definitions grouped by well-known (RFC-registered), operator-specific, IXP/route-server-specific, and historical (out of validity window). BGPScout holds ONLY the RFC well-known set today - operator_specific and ixp_specific are empty for every ASN, and `operator_specific_note` says so explicitly when you pass `asn` (absence of documentation, never evidence a network has no community policy). Every definition carries its source_url/source_type/confidence and validity window - nothing here is inferred from the community's numbers.
decode_bgp_communitiesDecode a list of BGP communities (standard "A:B", large "A:B:C" RFC 8092, or extended "rt:GA:LA"/"soo:GA:LA"/six raw hex bytes RFC 4360), one result per input, preserving order. Never invents a meaning from the numbers: each result is either a cited definition (source_url, source_type, confidence, validity window) or an explicit `status: 'unknown'`/`'invalid'` with a `reason` - most commonly "No documentation on file for AS<n>'s communities", because BGPScout holds no per-ASN community documentation today (#553 phase 1 - RFC well-known set only). `ambiguous: true` when multiple equally-authoritative definitions exist; never silently picks one. `context_match` says whether the community's own candidate-owner ASN agrees with `context_asn`, but the input is never rewritten by that context. Four-byte ASNs (large communities, and rt:/soo: with a Global Administrator > 65535, auto-selecting the RFC 5668 four-octet-AS encoding) round-trip exactly.

Registry allocations 6

search_allocationsSearch RIR address allocations - every IPv4/IPv6/ASN delegation the five registries published, with the date each block was handed to an organisation. Use for 'what has ARIN allocated recently', 'which blocks were assigned in <country> since <date>', or to date a prefix. Newest first by default. Each row carries org_key (the registry's opaque organisation id) and org_url, the canonical browser link for that organisation (models/org-slug.js). org_url is null where the registry published no organisation id for the block, which means the holder is unknown to us and not that the org has no page; measured 2026-08-22 that is 0 of the 434,076 allocated/assigned rows this tool can return.
get_asn_allocationsPaged IPv4/IPv6 blocks delegated to an ASN's registry organisation. Totals and transfer/direct summaries cover the complete inventory, not only the returned page. IPv4 and IPv6 have independent cursors so one family cannot crowd out the other. SCOPE: every total is for ONE registry org handle, and a company routinely holds several - AS16509 resolves to an ARIN handle with 5 IPv4 blocks while an identically-named sibling handle holds 1,807. When siblings exist, `related_orgs` names them with the extra block counts; walk them with lookup_rir_org's org_key. `org_resolution` is 'resolved', 'unresolved' (the ASN sits in a delegation range carrying no organisation id, so the holder is unknown - counts come back null, NOT zero) or 'absent' (no delegation record at all).
search_transfersThe RIR transfer logs: IPv4/IPv6 blocks and ASNs that changed hands between organisations, naming both parties. transfer_type distinguishes a market transfer (the block was bought or leased) from a merger/acquisition (the holding company itself was acquired). Use for 'who has been buying address space', 'where did this prefix come from', 'what has <company> sold', or 'which ASNs were acquired in <year>'. Covers ARIN, RIPE NCC, APNIC, LACNIC and AFRINIC.
lookup_rir_orgRegistry organisations and their independently paged ASN, IPv4 and IPv6 inventories. Every family reports total, returned, truncated and next_cursor so large holders are never silently incomplete. SCOPE: a registry org handle is not a company. Totals are `scope: 'this registry org handle only'`; RIRs issue a company several handles over mergers and transfers, and 643 registered names in the corpus are carried by more than one org. `related_orgs` discloses the handles sharing this one's exact registered name plus the extra blocks they hold - disclosed, deliberately not merged, because a registry name string is not proof of common ownership. When an ASN matches no organisation, `org_resolution` separates 'unresolved' (a delegation range exists but carries no organisation id) from 'absent' (no delegation record at all). Also returns `ipv4_utilization`, the org's allocated/advertised/DORMANT IPv4 address counts (#564) - see search_dormant_ipv4's description for what 'dormant' measures and its caveats, which apply here too.
search_dormant_ipv4Find registry organisations holding significant unadvertised ("dormant") IPv4 space - the lease/transfer/sales prospecting signal #175 and #302 built for the /orgs page, now reachable from MCP (#564). WHAT 'DORMANT' MEASURES, EXACTLY: an address is dormant if it was NOT covered by any BGP route we observed in ANY of the last `window_days` nightly snapshots (7 by default). It is a MEASUREMENT, not a verdict - dormant is not the same as unused or available: the space can be internal-only, reserved, mid-migration, or announced solely to peers outside our DFZ view. Every result carries `nights_observed` (how many of those nights actually contributed - render this, not just window_days, #67) and `measured_at`. ORG-LEVEL BY DESIGN, NOT ASN-LEVEL (#175): the announcing ASN is irrelevant to whether an org's address is routed at all - summing per-ASN figures undercounts an org whenever its org-to-ASN linkage is incomplete, which #175 measured making Amazon read as 20.8% dormant (an artifact of only 4 of its ASNs being linked) versus the correct org-level 84.8%. So this tool returns organisations, never ASNs; to ask 'how much dormant space is behind ASN X', call get_asn_allocations or lookup_rir_org for that ASN's org_key, which each carry the same ipv4_utilization figures attributed to the ORG. DISTINCT FROM get_org_asns's filter=dormant: that means an ASN never observed announcing IPv4 at all (a fact about the ASN), completely different from address-space dormancy (a fact about the org's allocated blocks) - an org can be 100% utilized and still hold a dormant ASN, or fully-announcing ASNs and still sit on a dormant /12. COVERAGE (#67): every response carries `coverage.orgs_computed` vs `coverage.orgs_holding_ipv4` - an org the nightly job has not reached yet is NOT a 0%-dormant org, it is unmeasured, and cannot appear in these results at all until it is computed. `country` filters/returns rir_org.country, which is DERIVED FROM THE ORG'S OWN ASNs (#399) - it is not the registered country of any one block, and only resolves for orgs holding at least one named ASN.
get_dormancy_by_registryGlobal IPv4 dormancy totals grouped by registry (ARIN/RIPE NCC/APNIC/LACNIC/AFRINIC) - the 'which RIR has the most dormant space' rollup (#564), for a headline or a per-registry comparison rather than a per-org search (see search_dormant_ipv4 for that, and for what 'dormant' measures - the same 7-night-window definition and caveats apply here). Five rows, computed at request time from org_ipv4_utilization (already indexed on registry, no new collection). Each row reports orgs measured, allocated/advertised/dormant address totals and dormant-of-allocated percent. `coverage` states orgs measured vs orgs holding IPv4 GLOBALLY (#67) - a registry with a low measured-org count is understated in this rollup, not actually low-dormancy; check coverage before ranking registries against each other.

Geographic search 8

find_nearFind facilities, IXPs and CDN caches within a radius of a location (latitude/longitude in degrees, radius in km)
find_networks_nearNetworks (ASNs) with IP address presence in an area - the geolocated IP footprint behind the IP-density heatmap. Use for 'which networks have IPs in/around <place>'. Ranked by number of geolocated IPs. Give either latitude+longitude (+radius_km) or a city and/or country. Coverage: ~6.5k ASNs with enough geolocated space to map; a network absent here may still operate there.
get_asn_densityThe per-location IP-density breakdown behind the prospect map for one ASN. Requires Sales access. Locations are geolocated address-space observations, not registered offices or facilities.
get_asn_geo_prefixesWhich address space an ASN has in a place, at PREFIX granularity - the inverse of find_networks_near (which goes place -> ASNs). Give an asn alone for its full per-location prefix breakdown, or add city/country or latitude+longitude+radius_km to constrain it. Returns the announced CIDRs with the geolocated IP count of each, not just totals. Coverage differs by field: coordinates and ip_count come from the per-prefix footprint (79,121 ASNs), while city/region/country come from the per-ASN city footprint (6,515 ASNs) - so an ASN can have located prefixes with NO city label, and a city filter cannot see it. An empty result means we have no geolocated space for that ASN, NEVER that the network is absent from the area. Coordinates are a 0.1-degree grid cell (~11km), not a precise centroid. Each row also carries an anycast verdict: is_anycast true means that prefix answers from many sites at once, so its coordinate is one sample, not a place the network is uniquely in - never report such a row as evidence of presence there; is_anycast null means unknown (a mixed-type ASN with no prefix-level anycast fact), not confirmed unicast.
find_transit_nearNetworks (ASNs) observed taking transit handoffs in an area, and from which Tier-1, derived from traceroute data. Use for 'which ASNs have transit locations in/around <place>'. Give latitude+longitude (+radius_km) or a city/country. Default grain is one row per asn/transit_asn/city - an asn/transit pair seen handing off in five cities returns five rows, not one row summed across all of them. Pass aggregate_by: 'provider_pair' for a national rollup instead: one row per asn/transit_asn with `observations` summed, `city_count`, and a `cities` breakdown; `city`/`country` are only present on that row when city_count is 1. Coverage is narrow - only ~490 ASNs across 11 Tier-1 providers currently have observed handoffs, so absence is not evidence of absence.
find_upstreams_nearNetworks (ASNs) present in an area together with their BGP upstreams. Use for 'which networks around <place> buy transit, and from whom', or with upstream_asn for 'who near <place> is behind <provider>'. Far wider coverage than find_transit_near, but the two halves come from different sources: location is PeeringDB facility presence, upstreams are BGP AS_PATH adjacency - an upstream listed here was NOT observed handing off in that city, and AS_PATH cannot distinguish transit from peering, and the coverage is a floor that does not grow much with more collectors (#208). Use find_transit_near instead when the handoff location itself must be real.
find_networks_at_facilities_nearNetworks (ASNs) with a PeeringDB data-centre/PoP presence in an area, and which facilities. Use for 'who is in a data centre in/around <place>' or to find cross-connect candidates in a metro. Give latitude+longitude (+radius_km) or a city/country. COVERAGE (#515): the radius can only be tested against facilities that have stored coordinates - a facility with memberships but no lat/long is left out of `networks`, not because it is outside the radius but because it cannot be evaluated. The response's `coverage` field reports how many candidate facilities exist, how many were geocoded, and (when you passed city/country) the specific `unlocated_matches` omitted - treat those as unresolved, not absent.
find_networks_on_ixps_nearNetworks (ASNs) peering at IXPs in an area, with port capacity. Use for 'who is reachable on an exchange in/around <place>' or to find peering candidates in a metro. IXPs are located via their facilities. Give latitude+longitude (+radius_km) or a city/country. COVERAGE (#515): an IXP present only in un-geocoded facilities cannot be placed in the radius and is left out of `networks`, not ruled outside it. The response's `coverage` field reports the same facility/membership omission accounting as find_networks_at_facilities_near, and `unlocated_matches` when you passed city/country.

Change feed 1

get_eventsThe change feed: ASNs newly registered, IP blocks newly allocated, resources transferred between organisations, networks joining/leaving IXPs, IXP port-speed changes, facility presence added/removed by a NETWORK, an EXCHANGE becoming present at or leaving a facility, a NETWORK gaining or losing a CDN cache, an EXCHANGE first appearing in or being delisted from PeeringDB, and a FACILITY doing the same (all #150). Filter by ASN, country, IXP, facility, event type and date range. Use for 'what changed for AS X', 'who joined IXPs in <country> recently', 'who bought address space recently', or 'what new networks appeared since <date>'. CAVEATS you must pass on: ixp_facility_added/ixp_facility_removed start EMPTY - ix_facility has no date column, so the history table took its first observation on 2026-07-27 and zero events means 'nothing has moved since we started looking', not 'no exchange has ever gained a facility'. cdn_cache_added/cdn_cache_removed start EMPTY for the same reason - cdn_cache_node is current state only, its first baseline was taken on 2026-07-27, and its granularity is the (ASN, programme) pair, so a cache farm growing from 3 nodes to 4 emits nothing. ixp_first_seen/ixp_delisted and facility_first_seen/facility_delisted are the EXCEPTION and do NOT start empty - they are derived from the monthly CAIDA PeeringDB archive and carry 2,347 events from 2010-08-01, though the series is monthly with three gaps so 111 delistings have a window up to five months wide. The facility pair adds 6,978 events on the same basis, derived from a first-seen/last-seen WINDOW rather than per-snapshot presence, which means it cannot express a gap and has no 'relisted' - measured at 6 disagreements in 1,965 when the same method is checked against exchanges. And ixp_speed_changed's 1,364 existing rows were all derived on 2026-07-25 from a membership table that has since been replaced; the current builder re-derives none of them.

Growth & trends 2

find_growing_networksNetworks ranked by how fast they are GROWING or DECLINING - net new data-centre facility presence, new IXP presence, and new address space over a 30/90/365-day window. Combine with a location (latitude+longitude+radius_km, or city/country) to answer the sales question directly: 'which fast-growing networks have a presence where I can reach them'. Set direction=declining to find networks contracting. Caveat: IXP membership history only starts 2026-04, so IXP figures are not yet a true year-over-year comparison.
get_asn_growthGrowth/decline detail for one ASN: net facility and IXP presence change and new address space over 30/90/365 days, with current totals for context.

IXP & facility 6

get_ixp_infoSearch Internet Exchange Points by name/city/country/operator, with min_peers/max_peers/min_facilities filters - this IS the /ixps browse listing (#350), not a lookup that requires already knowing the PeeringDB id. Each result carries its operator (the PeeringDB organisation that runs it - always present), where we could establish one the registry organisation behind it with the method and confidence that link rests on, and a `virtual` classification (score/tier/reasons) saying how likely the exchange is a virtual fabric rather than a physical one. DEFAULTS: min_peers = 1, so exchanges with no membership recorded in PeeringDB are excluded - pass min_peers=0 to include them (they are often defunct rather than never-real, which is itself informative). exclude_virtual defaults to FALSE: virtual exchanges are returned, labelled, unless you ask for them to be dropped. The website's /ixps page applies the same min_peers default. operator_org.org_url is the canonical browser link for that registry organisation (models/org-slug.js) - the same page a person clicking it on the site lands on; it is null when the org's registry identity could not be resolved, and operator_org itself is null when no registry link was established at all. It replaces the old `url` field, which was hand-built as /orgs/{registry}/{org_key} - the documented fallback form, which resolves but is not the canonical link.
get_ixp_membersList the ASNs that peer at a given IXP (by its PeeringDB id from get_ixp_info). ONE ROW PER MEMBER, with that member's ports nested under it - a member with two ports is one row, not two. Each port carries its IPv4/IPv6 peering-LAN address and, where the operator declared one in PeeringDB, the facility (building) that port terminates in. A port with no facility is UNDECLARED, not "in no facility". PAGING: `member_count` is the FULL membership, `returned` is how many are in this page, and `truncated`/`next_offset` say whether there are more - a page is never passed off as the total (#501). OPERATIONAL: members and capacity count only ports PeeringDB flags operational=true, so a member whose every port is down is absent; pass include_non_operational for the historical shape (#502).
get_facility_infoSearch data centers/facilities by name/country/city, with a count of how many ASNs are present - this IS the /facilities browse listing (#350), not a lookup that requires already knowing the PeeringDB id.
get_facility_membersList the ASNs present in a data-center facility (by its PeeringDB id from get_facility_info). Returns an OBJECT, not a bare array: `members` plus `member_count` (the full total), `returned`, `limit`, `offset`, `truncated` and `next_offset`. It used to return a bare array that silently stopped at the limit, so a 721-ASN facility came back as 200 rows with nothing saying so (#501). `member_count` now matches get_facility_info's asn_count exactly; a tenant we hold no ASN record for is returned with `asn: null` and its PeeringDB net id rather than being dropped.
get_facility_eventsOne building's change feed and the exchanges inside it - the same data as the /facilities/<id> page (#27). Returns the facility record, the IXPs physically in it, and the merged event log for both, with counts so a capped feed is never mistaken for the total. Events reached via an exchange are labelled: an IXP join at a multi-site exchange is not a statement about this one building.
find_nearFind facilities, IXPs and CDN caches within a radius of a location (latitude/longitude in degrees, radius in km)

CDN 1

search_cdn_cachesFind CDN edge caches by country/provider/city. provider: ggc | oca | fna | akamai | aws_cloudfront | microsoft | apple. Node-level LOCATIONS exist only for ggc, oca, fna, akamai, aws_cloudfront; for the rest we know which ASNs host their caches but never collected node locations (#191), so those providers return the hosting ASNs with location_data='not_collected' instead of an empty list. An empty result for them means WE DID NOT COLLECT IT, never that the caches do not exist.

Traceroutes & analysis 13

search_traceroutesSearch traceroutes by source/dest ASN, country, destination host, platform, category, boomerang, detour country, severity, address family, or quality score. NOTE `hop_count` in these rows counts RESPONDING hops, not path length, and understates any path containing a timeout - get_traceroute returns path_length_hops for a real comparison (#497). platform (ripe-atlas | linux) is the real collector/vantage-point filter - use it for "give me RIPE Atlas traces". category is a granular PER-TARGET label the collector assigns (241 distinct values as of 2026-08-21, e.g. "Cross-border - US to tranco_ca", "ISP - TELUS Communications AS852"), NOT a platform selector - category="RIPE Atlas" only matches the literal legacy label used before the collector switched to per-target labels in April 2026 and will look empty-ish for current data (#254). category matches as a case-sensitive substring so a family like "Cross-border" or "TELUS" can be matched without knowing every exact label. Rows carry `left_source_country`, not the legacy Canada-only `leaves_canada` - a French or Brazilian domestic trace can have left_source_country=1 while never touching Canada (#363). ipv6=true restricts to af=6 traces (#424) - the RIPE Atlas importer only started writing this flag once af=6 measurements existed, so a trace older than that has ipv6=0 regardless of its real address family; a colon in dest_host/dest_ip is the fallback tell for older rows. #362: detour_country and severity filter on traceroute_boomerang_detail (migration 098) - only boomerang=1 traces ever have a row there, so passing either narrows to boomerang traces even without boomerang=true set explicitly. Rows also now carry detour_country/severity/detour_distance_km (all null on a non-boomerang row, or on a boomerang row the backfill has not yet reached).
get_tracerouteGet one traceroute with hop geolocation provenance and a first-class domestic, left_country or undetermined crossing verdict. Legacy booleans are null when the verdict is undetermined. On path length: `hop_count` counts only hops that REPLIED and is kept for compatibility - use `path_length_hops` (the last TTL reached) to compare path lengths and `responding_hops` / `missing_hops` to see how complete the path is (#497). When boomerang=1, `boomerang_detail` (#362) carries WHERE the detour went (detour_countries, furthest_detour_country), detour_distance_km, severity_tier, severity_weight/gravity_index (a continuous 0-1 / 0-100 distance-weighted severity, same formula get_boomerang_stats aggregates - null, not 0, when detour_distance_km was not_collected, #67), destination_tier (top_1k/top_10k/unranked/null from Tranco rank - unranked means checked and not in the top 10,000, null means never checked, coverage is partial), latencyPenaltyMs (#362's fourth field - this trace's own RTT minus the median RTT of domestic, non-boomerang traces to the same destination, migration 176 - null with latencyPenaltyNotCollectedReason set to no_own_rtt/no_dest_host/insufficient_baseline/not_collected when it could not be measured; measured coverage 2026-08-25 is 126 of 699 boomerang traces, 18%, so null is the common case, never 0, #67) and #364 fault attribution - null if this trace is not a boomerang or the backfill has not reached it yet (#67). #523: each hop carries `reply_data`, per-packet Atlas responder detail from traceroute_hop_reply (migration 106) alongside the hop's own primary-responder ip/rtt_min/avg/max. `reply_data.reply_data_state` is 'observed' (with `responders`: an array, primary first, each with its own rtt_min/avg/max and reply_indexes) or 'not_collected' (`responders`: null) - NEVER read a missing/null responders as "this hop had one responder": only 10,122 of 3,304,540 traceroute_hop rows (0.3%, measured 2026-08-25) have any per-packet data, because it predates migration 106 for everything else and that history is unrecoverable. `reply_data.ecmp_divergence` is true only when more than one distinct responder ip was actually observed at that hop (57 such hops exist in the corpus today). Trace-level `reply_data_coverage` summarizes how many of this trace's hops have reply data at all.
get_my_traceroutesYour own submitted traceroute batches, or the traces in one owned batch (pass batch_id). Unlike search_traceroutes, this reads your private submission corpus and always scopes by your user_id. category (only meaningful with batch_id, since a batch listing has no per-trace category) matches like search_traceroutes does (#254): a case-sensitive substring against the per-target label (241 distinct values as of 2026-08-21), not an exact match - an exact "RIPE Atlas" only hits the legacy label used before the collector switched to per-target labels in April 2026.
get_asn_tracesGet traceroute data for an ASN
get_route_heatmapBusiest city-to-city links observed in traceroute data (internet route heatmap). Pass from_city (and optionally from_country, to disambiguate a repeated city name) to answer a different question - not "what are the busiest links overall" but "where do paths go NEXT from this specific city" (#350) - the traceroutes.js /analysis/city-links gap this closes. from_city matches the merged/normalized spelling this tool already returns in from_city/to_city, not raw traceroute_hop.city.
get_country_scoreboardCountries ranked by routing quality (boomerang rate, cross-border rate) [BETA: the underlying calculation is still settling - treat the result as directional, not yet safe to quote as a stated fact. See /traceroutes/analysis/country-leaderboard on the site for the current caveats.]
get_tier1_comparisonThe 11 curated Tier-1 transit providers, ranked by BGP-wide downstream network count (RIB-derived, so the order does not depend on where our probes are). Reads the same durable connectivity_snapshot_run/connectivity_asn_metric/interconnect_provider snapshot as the /traceroutes/analysis/tier1 page (models/tier1-snapshot.js) rather than running its own live query, so this tool and that page cannot disagree about the same named comparison (#528, one level up from the fix #78/#438 already made for population/window/ranking here). transit_traces, avg_rtt, avg_hops etc are all frozen at the snapshot's own window - see the returned snapshot.window_start/window_end, not a rolling "as of now" figure. tier1_peers_observed and cloud_interconnects_observed are TIER1<->TIER1 and TIER1<->cloud/CDN handoff EVIDENCE from that same snapshot; the old customer_networks/handoff_cities/observations figures (pulled live from a separate asn_transit_handoffs table on its own 180-day window, never shown on the page at all) are retired by this migration - see notes.retired. Returns available:false with an empty providers list if no connectivity snapshot has completed yet. Traceroute counts are corpus floors, not traffic shares.
get_tier1_city_viewTier 1 x Tier 1 peering and Tier 1 x cloud handoffs actually observed in traceroutes through one city or metro area, over the snapshot's window - the server-side equivalent of the By City section on /traceroutes/analysis/tier1. Reads the same durable connectivity snapshot as get_tier1_comparison (models/tier1-snapshot.js's getTier1Snapshot()) rather than a live query, so this tool and that page cannot disagree. A city with nothing here means this corpus has no probe traffic through it, NOT that no Tier 1 is present there (#67) - check get_tier1_comparison for what the corpus does cover. `city` is matched as a case-insensitive substring against the snapshot's own city names, same as the page's search box.
get_asn_connectivity_profilePrecomputed connectivity profile for ANY ASN, not just the curated Tier-1 eleven (#528 generalises #527's Tier-1 snapshot into a per-ASN model). Reads only a durable, versioned snapshot - the same connectivity_snapshot_run/connectivity_asn_metric/connectivity_observed_handoff/interconnect_provider tables get_tier1_comparison also reads - and never falls back to a live aggregate, so a stale or failed refresh is visible as staleness rather than silently substituted with a different computation. `measured` means this ASN was in the precomputed population for that snapshot with real observations; `unobserved` means it was not selected or had no evidence - absence is not zero (#67), never report an unobserved ASN as having no connectivity. observed_handoffs are consecutive-ASN-transition EVIDENCE, not a commercial relationship claim (transit vs settlement-free peering vs sibling cannot be told apart from adjacency alone). This profile does not read asn_adjacency/PeeringDB directly, so it does not carry the collector geographic bias documented on get_asn_neighbours/#208 - but that also means it currently has NO population beyond whatever the curated seed list covers until #528's broader population and priority-score work lands. If available is false, no completed snapshot exists (or the requested snapshot_id does not); that is a fault on our side, not evidence about the ASN. Three further sections share this same snapshot, each with its own three-state `state` (measured / measured_none_observed / unobserved) and `note` exactly like the top-level fields above - measured_none_observed means this ASN WAS measured and simply had no such evidence in this window, never collapse that with unobserved (not in the precomputed population at all): `cdn_cloud_interconnects` (observed handoffs to a curated cloud/CDN interconnect_provider ASN, canonical multi-ASN operators like AWS/Google/Microsoft merged into one entry); `metro_path_diversity` (distinct metros with observed handoff evidence - metro BREADTH only, never a redundancy claim); and `observed_path_diversity` (#528 section 3, per-handoff interface/IXP/temporal-path evidence from connectivity_handoff_interface/connectivity_handoff_path - labelled Observed Path Diversity, never Redundancy, since traceroutes cannot prove contractual, physical or operational redundancy. Two tiers kept separate: WEAK is distinct interface IPs, which may be two routers or two interfaces on ONE router since alias resolution is not collected; STRONG is an IXP actually observed on the crossing, sparse by measurement (only 20 of 500 handoff rows with interface data, 2026-08-25/26). Concurrency is REQUIRED, not assumed - a handoff's `paths.concurrent_overlapping_pairs` only counts path pairs whose own first_seen/last_seen windows actually overlap; a path used last year and a replacement used today do not count. connectivity_handoff_path is CURRENTLY EMPTY for the whole snapshot - every handoff reads `paths.state: 'no_path_rows'` right now, which is a snapshot-build gap, not a finding of 'one path' or 'no diversity').
get_common_routesMost frequently observed source-ASN → destination-ASN traffic flows [BETA: the underlying calculation is still settling - treat the result as directional, not yet safe to quote as a stated fact. See /traceroutes/analysis/routes on the site for the current caveats.]
get_boomerang_statsGet boomerang routing stats for a country. Returns per-ASN rates (asns, each with an attribution breakdown - avoidable/conditional/structural/unknown, #364 - or null if not yet computed for that ASN), plus by_detour_country and by_severity (regional/intercontinental/extreme/not_collected) breakdowns for the whole country - #362: a boomerang is where it went and how severe, not one blended rate. Gravity has both halves now: each ASN carries distance_gravity (avg_one_way_km, gravity_index 0-100, measured/unmeasured split per #67) and destination_gravity (top_1k/top_10k/unranked/not_collected counts from Tranco rank, #141 - coverage partial, unranked != not_collected, popularity not traffic volume), plus country-wide distance_gravity_overall/destination_gravity_overall. See destination_gravity_note in the response for the coverage and popularity-vs-traffic caveats. [BETA: the underlying calculation is still settling - treat the result as directional, not yet safe to quote as a stated fact. See /traceroutes/analysis/boomerang on the site for the current caveats.]
get_asn_routing_qualityASNs ranked by traceroute-observed routing quality (boomerang rate) among traces THEY SOURCED in the last 180 days - existing evidence, not a peering candidate suggestion (see get_recommended_peers for that). Same DOMESTIC_TRACE eligibility floor as get_country_scoreboard (#130/#179): only traces confirmed domestic-or-crossing count toward eligible_traces, never the raw total. classification is needs-more-data (below 200 eligible traces), poor-peering (>30% boomerang), moderate (>10%), or good - the SAME floor-then-threshold order the web page uses so colour/label cannot disagree (#249). Admin only (access_level >= 300); the web page also accepts a personal beta_features flag below that level, which this tool does not replicate.
get_dashboard_summaryPlatform-wide traceroute corpus stats - the same three cheap /dashboard widgets (stats, recent-traces, category-breakdown), combined into one call. NOT per-user: every signed-in caller sees the same numbers, same as the web widgets they mirror. `stats` is total_traces/boomerangs/unique_asns/countries across the whole approved corpus. `recent_traces` is the 15 most recently active dest_host+dest_country pairs (NOT per-trace or per-batch - grouped by destination, distinct from get_my_traceroutes/get_asn_traces). `category_breakdown` is traceroute counts grouped by target_category (uncategorized traces are labelled 'Uncategorized', not dropped).

Relationships 3

find_co_locatedNetworks that share a data-center facility with a given ASN (cross-connect / peering candidates)
find_transit_customersNetworks observed DOWNSTREAM of a given transit ASN (reverse of get_transit_providers). Returns traceroute-observed handoffs (with cities) and BGP AS_PATH downstreams (far wider coverage, no location). NEITHER list proves a commercial relationship: both are routing observations, and a downstream position is equally consistent with paid transit, settlement-free peering, a sibling network, or transit supplied by an upstream on that network's behalf. Do not report these networks as customers of, or as buying transit from, the queried ASN - only as observed downstream of it (#499). The tool name is retained for compatibility and overstates what the data shows.
get_org_asnsList all ASNs under the same organization. Pass an asn (finds its siblings via the registry allocation record, same identity the /orgs pages use) or an org_id (asn.org_id - a shorter, registry-specific handle like ARIN's 'MCICS', NOT the same identifier as the /orgs URL's opaque_id; used only as a fallback when no asn is given). Same sort/filter/pagination #288 added to the org detail page: sort (advertised|prefixes|peers|asn|name, default advertised), dir (asc|desc), filter (all|announcing|dormant - 'announcing' means observed announcing IPv4 in the DFZ, not merely delegated), page. NOTE (#564): filter=dormant here means an ASN NEVER OBSERVED ANNOUNCING IPv4 - a fact about the ASN's activity, not about address space. It is unrelated to search_dormant_ipv4's dormant_addresses, which measures unadvertised IPv4 address space held by the org regardless of which (if any) ASN announces the rest. An org can be 100% address-utilized and still have a dormant ASN here, or have every ASN announcing and still hold a dormant /12 there. advertised_ipv4/prefix_count/peer_count are null (not zero) for an ASN never observed announcing or with no peer-count row - a registry delegation is not evidence of activity. org_url is the canonical browser link (models/org-slug.js) when the org's registry identity could be resolved, else null.

Sales & prospecting 13

find_prospectsFind sales-prospect networks by use case. use_case: transit | colocation | ixp | ixp_competitive | network_health. Same engine as the web prospecting tool. Dismissed/tagged leads are hidden by default, matching /prospect; set hide_dismissed=false to include them. target_ixp changes what use_case=ixp MEANS: without it you get networks on no domestic exchange at all, with it you get candidates for THAT exchange - anyone already peering there on a working port is excluded, and the rest are ranked by how many of the exchange's own facilities they are already present in, because a network in the building can be cross-connected and one three cities away cannot (#504). An unknown target_ixp is an error, not a silent fallback. `country` (the PROSPECT network's registered country, e.g. "US" or "BR") is REQUIRED and has no default - it used to silently fall back to CA (#363), so an omitted country now returns an error instead of a Canadian answer to a non-Canadian question. For use_case=transit specifically, `country` filters the prospect's own registry, not the probe location (it used to conflate the two and return networks from other countries, #491); `source_country` filters where the traces were measured FROM, if you want that instead. crossing_rate is computed from left_source_country, the general column, not the legacy Canada-only leaves_canada - for CA that is 34,406 crossings rather than 10,093, so rankings and the 10% inclusion threshold differ from before.
find_long_haul_customersNetworks with long-haul routes (potential transport/backbone customers)
find_transportNetworks observed carrying long-haul traffic between two regions (transport/backbone providers). Filter by from/to country or city.
get_cloud_connect_prospectsNetworks that are candidates for cloud on-ramp / direct connect, best first. Ranked by prospect_score, then cloud_peering_score, then ASN - the cap is applied AFTER ranking (#492), so a smaller limit returns the best N rather than an arbitrary N.
get_prospect_tagsYour saved prospect tags (customer/prospect/not_interested) on ASNs. A dismissed lead is stored as the not_interested tag, so this is also the review list for anything dismissed at /prospect.
get_clientsYour CRM clients/accounts and their member ASNs and IXPs - the list behind /prospect/clients. This is where a client_id for add_asn_to_client comes from. Scoped to your own clients plus your sales org's, exactly as the web page is.
get_search_templatesThe seller profile, linked assets and target countries used to personalize /templates search recommendations. Requires access level 100, matching the page.
generate_outreach_templatesGenerate the personalized routing, peering and general outreach copy shown by /sales-lab/outreach for an ASN. Admin only, matching that page.
get_asn_lead_scoreSales lead score and opportunity signals for an ASN
get_lead_reasonsWhy an ASN is flagged as a sales lead - opportunity type and signal breakdown
get_buy_signalsNetworks showing ready-to-buy signals, ranked by lead score (sales lab)
get_rpki_opportunitiesNetworks where RPKI ROV has NOT BEEN OBSERVED. Read the name as a legacy label: this is NOT a list of networks without RPKI. The source is bgp.tools's "Validating RPKI ROV" tag, which is positive evidence when set and silence when not - the measurement needs a RIPE Atlas probe behind the network, so most nulls are unmeasured rather than negative (21 of 623 Canadian ASNs are observed). It also says nothing about whether these networks publish ROAs for their own prefixes. The response carries `coverage` and a `signal_note`; quote them with any list you produce, and never describe a listed network as insecure or as not validating (#490).
get_industry_verticalsNetworks by industry vertical with lead scores. vertical: isp | gov | cdn | corp | uni | biznet | mobile

Intelligence & ranking 5

get_new_networksRecently registered ASNs (new networks), optionally by country
get_growing_networksFastest-growing networks by facility/IXP expansion
get_prefix_growthNetworks with the largest IPv4 prefix growth between the latest two completed RIB snapshots. Returns both snapshot dates.
get_country_benchmarkPer-country network/routing benchmark stats (network counts, IPv6 adoption, IX presence). ipv6_pct is measured-only and reproducible: it is ipv6_networks / ipv6_measured_asns, NOT over total_asns. ipv6_unknown_asns is the population we have never measured and it is excluded from both sides of the percentage rather than counted as "no IPv6" (#495). on_ix_pct works the same way and matters more: asn_on_ix is unknown for 48% of networks, so networks_on_ix must NOT be read against total_asns.
get_top_networksTop networks in a country ranked by a metric. by: traffic | prefixes | facilities | ixps

Domains 4

domain_lookupTwo separate evidence classes for a domain, never one guessed ASN (#479). `website_associations` is a company's SELF-REPORTED website (PeeringDB/bgp.tools) - identity, not hosting. `dns_answers` is what actually resolves: observed A/AAAA records grouped by ASN from a completed domain intelligence scan, or a live DNS + routing-table resolution when the domain has never been scanned. `primary_network` is set only when dns_answers has a majority ASN, with a method/confidence/evidence field - it is null when the evidence does not support one, and it is NEVER taken from website_associations (Netflix owns AS55095 but is hosted on AWS; google.com's website row is a different ASN than the 173/174 DNS records observed for it).
search_domainsSearch the domain→ASN index (which networks host which domains). `country` filters on the hosting country OBSERVED in scan records, the same figure the coverage page counts - not the hosting network's country of registration, which is returned separately as asn_country. Only 51% of indexed domains have a scanned country, so absence from a country's results is not evidence the domain is not hosted there.
get_domain_intelDomain intelligence scan summary plus a deterministic page of records. Returns total_records, returned, truncated and next_cursor. Also returns dns_profile - nameserver/mail ASN, SPF provider and DMARC - when this domain has been profiled by the #340 DNS sweep. dns_profile is null, NOT zeros, for a domain not yet profiled, and only a small share of the scanned corpus is: do not read null as "no nameservers". dns_profile_history_count says how many snapshots exist, because one is a baseline and cannot show a change.
compare_domain_scansCompare two Domain Intelligence scans of the same domain (subdomains, IPs, ASNs, hosting type, country). Both scans must be visible to you - yours, your org's, or any if you are an admin; an id you cannot see and one that does not exist return the same error. Returns older/newer (whichever scan_id is actually more recent by created_at), plus added/removed/changed/unchanged record lists and totalOld/totalNew counts.

Exports 4

create_exportStart a reproducible asynchronous export job. Runs in the background - poll get_export(job_id) for progress; state starts "queued" then moves to "running" then a terminal state (completed/failed/cancelled). The response records the EXACT normalized filters, columns and source cutoff used, so the same call can be re-run later and compared - that is what "reproducible" means here. No arbitrary SQL: every dataset has a typed, allowlisted filter/column schema and an unknown filter or column is a validation error, not a silent no-op. Ten datasets ship today, and asns_search is the first one a web route serves from (POST /asns/exportSearch, #574) rather than duplicating: "asns" (public ASN directory), "prefixes" (announced routes), "rpki_validation" (per-prefix RPKI verdicts, joined on (asn,cidr) so withdrawn prefixes are excluded), "ixp_members" (one row per member, not per port), "traceroutes" (approved public traces only), "facility_members" (one row per facility membership, never grouped by resolved ASN - that would silently collapse memberships whose ASN did not resolve), "allocations", "transfers", "events", and "asns_search" (the full 52-column ASN search export, admin-only at access level 300 - the same gate the web route enforces). Call list_exports for the exact filters and columns of each. Unknown filter KEYS are rejected rather than ignored: a typo such as "cuontry" fails the request instead of silently exporting everything and writing the typo into the reproducibility manifest.
get_exportStatus and, once complete, the manifest and download link for an export job you created. Returns three DISTINCT outcomes, never collapsed (#67): a running job has no row_count yet and is not a failure; a completed job with row_count=0 is a genuine empty result, not an error; a failed job has error_class/error_detail and is never reported as a zero-row success. download_url is present only when state="completed". It is a SHORT-LIVED SIGNED link (GET /mcp/exports/:id/download?exp=&sig=) valid for 15 minutes - download_url_expires_at says exactly when - and it is minted fresh on every get_export call rather than stored, so an old response holds an expired link, not a permanent one. The signature is bound to the specific artifact, so it stops working the moment that artifact is replaced or reaped. Possession of the link is enough to download it within that window; the same path also still accepts your normal API-key/OAuth auth with no token at all, which is the safer way to fetch it if your client can set a header. A job id you do not own and one that does not exist return the identical "Export job not found."
list_exportsYour own export job history (never another caller's - job visibility is scoped to the principal that created each job), newest first, paginated.
cancel_exportCancel a queued or running export job you created. A job already in a terminal state (completed/failed/cancelled/expired) returns an explicit "already <state>" refusal rather than a silent no-op success. Cancellation here is LOCAL (this server's in-process runner checks for it between batches and cleans up the partial file) - there is no separate remote worker to signal, which the response's note field says explicitly.

On-demand measurements 4

create_measurementLaunch an on-demand ping, traceroute, or dns lookup from a Globalping vantage point (#552). Returns immediately with state="queued" - this does NOT wait for results; poll get_measurement(job_id). Requests are NEVER deduplicated against each other or against scheduled coverage: every call creates a fresh measurement, on purpose, so an incident-response retry always gets a real new probe. Pass idempotency_key to make a RETRY of the same logical request safe instead - a second call with the same key returns the original request (dedup="reused_idempotency_key") rather than spending quota twice. Guardrails, all enforced before submission: for ping/traceroute, the target is resolved and rejected if it (or any of its resolved addresses) falls in a private/loopback/link-local/multicast/reserved/cloud-metadata range; for dns, the target (the domain QUERIED) is only shape-checked - it is deliberately NOT pre-resolved/blocked, because a name that legitimately NXDOMAINs or has no A/AAAA record is a normal, valid dns target, not an error (#67) - but dns_resolver (see below), a real network endpoint the probe connects to, gets the SAME private-range rejection target does for ping/traceroute; a per-caller cap of 20 probes per rolling hour and at most 3 concurrent in-progress requests, both independent of Globalping's own platform-wide free allowance (one caller cannot exhaust that allowance for everyone else); budget_mode is fixed to "free_only" (credit spending is not available yet - passing "credits_allowed" is refused). address_families defaults to [4]; passing [4,6] submits one job per family (paired v4/v6), sharing one job_id/request group. probes_per_selector is capped at 5. For type="dns": the result carries a `dns_outcome` per answer - "resolved" (NOERROR, with `answers`/`resolved_addresses`), "nxdomain" (a real completed answer, not an error), or "dns_error" (SERVFAIL/REFUSED/etc, code preserved) - alongside the usual transport-level `status`, which is what actually failing to get any DNS response (timeout, resolver unreachable) reports; "not yet run" is the job/request state, polled via get_measurement. source REQUIRES at least one of countries[0]/asns[0]/cities[0] (a single Globalping location selector; there is no "any probe worldwide" option in this slice) plus any number of tags to narrow it - selecting several DISCRETE locations in one call (e.g. "3 different ISPs") is not built in this slice.
get_measurementStatus and results for a measurement job you created (#552). Three states, never collapsed (#67): "running" (still in progress at the provider), a terminal state with usable_result_count=0 / zero_usable_results=true (the job ran to completion but nothing came back "finished" - a real distinct outcome, not an error and not silently treated as success), and "failed" (a real submission/provider error, in `error` and per-job `last_error`). "partial" appears when a paired v4/v6 request had one address family succeed and the other fail or get cancelled. Every job (one per requested address family) reports its own state/attempts/last_error alongside the request-level rollup, and every result row keeps the RAW provider payload (`raw`) as well as a normalized `summary` - never a single collapsed value, so multiple per-hop responders are never reported as loss (#523). A job id you do not own and one that does not exist return the identical "Measurement job not found."
list_measurementsList the measurement jobs you created (#552), newest first. Scoped to you: another user's jobs are never returned, and a non-admin passing someone else's user_id gets the same "Measurement job not found." that get_measurement uses, so this cannot probe which job ids exist. Filters: state, measurement_type, target (exact match, not a substring), created_after / created_before. limit defaults to 25, clamped to 100. Each row carries the same rolled-up lifecycle state get_measurement reports, from one shared function, so a list can never disagree with a detail view.
cancel_measurementCancel a measurement job you created (#552). Local and provider outcomes are reported SEPARATELY and an upstream refusal is never reported as a successful cancel: a job not yet submitted to Globalping (still claimed in the ledger only) is genuinely cancelled and quota is never spent on it; a job already submitted cannot be cancelled - Globalping has no measurement-cancellation API - and the response says so explicitly (`provider_cancelled` is always false; `jobs_already_submitted_to_provider` counts what could not be stopped) rather than pretending the request went away. A job already in a terminal state (complete/failed/cancelled) returns that state with an explanatory note, not an error.

Your saved data 11

get_watchlistEverything you are watching. Each row carries subject_type ('asn', 'ixp', 'facility' or 'org') and subject_id; `asn` is filled in only on an ASN row and is null otherwise, which means 'not about a network', not AS0. Add or remove: add_to_watchlist/remove_from_watchlist (ASN), add_ixp_to_watchlist/remove_ixp_from_watchlist (IXP, #350), add_facility_to_watchlist/remove_facility_from_watchlist (facility, #350), add_org_to_watchlist/remove_org_from_watchlist (registry org, #350).
get_alertsYour recent alerts/notifications
get_notificationsYour unread in-app notifications (the notification bell), newest first. Distinct from get_alerts, which is watchlist alerts specifically - this is a separate table with its own writer. Dismiss one or all with dismiss_notification (#350).
get_saved_searchesYour saved searches
get_auto_scoutYour auto-scout (auto-run saved searches) with the latest result counts AND the identifiers that arrived or left since the previous run - so "3 new" can name the three (#153)
get_favoritesYour favorite ASNs. Add or remove with add_favorite/remove_favorite (#350).
get_trace_favoritesYour favorited traceroutes (the star on a trace-detail page), newest favorite first. Add or remove with add_trace_favorite/remove_trace_favorite (#350). This is a different favorites list from get_favorites, which is ASNs.
get_dashboard_pinsCards pinned to your dashboard (#240) - the same list /dashboard renders, decorated with name, country and a reason to watch each one.
get_dashboard_digestYour personal 7-day dashboard digest: facility/IXP count changes on YOUR watched ASNs, watchlist quality alerts, new traceroutes to/from YOUR watched ASNs, and new-match status of YOUR saved searches. Always scoped to the calling principal - never returns another user's watchlist or saved searches. watched_asn_count=0 means you have nothing on your watchlist, which is a real state, not a failure; the ASN/quality/trace sections are only populated when watched_asn_count > 0.
list_alert_destinationsYour alert delivery destinations. Never returns the webhook signing secret or a rotation's previous_secret - both are shown once, at creation/rotation time (create_alert_destination / update_alert_destination's rotate_secret), and never again after that. Each entry's enabled/verified/unsubscribed state and its type-specific target (webhookUrl for a webhook; emailAddress for email, though email cannot be created yet - see create_alert_destination) are included.
get_alert_deliveriesBounded delivery history for your alert destinations: state (pending | sent | dead | cancelled), attempt count, and the most recent attempt's outcome class - "delivered" (2xx), "endpoint returned 500" (retryable_http/permanent_http, with the real HTTP status in response_code), "endpoint unreachable" (timeout/connection_error/ssrf_rejected, response_code null), or "never attempted" (no attempt row exists yet at all - a distinct, absence-based fourth state, not a zero or a guess). Never returns request bodies, response bodies or secrets. Filter by destination_id and/or state; bounded by limit (default 50, max 200).

Org & seller 6

get_org_customersAuto-detected customers for your org, split by what the detection actually means. `customers` are networks downstream of the org's OWN ASNs - strength=observed is a traceroute-observed transit handoff (strongest), strength=adjacency is BGP AS_PATH only and MAY BE PEERING RATHER THAN TRANSIT. `nearby_networks` are ASNs at an IXP or facility the org linked: proximity, not commerce - prospects, not customers. An empty customers list means nothing was observed, not that the org has no customers.
get_org_prospectsGet performance targeting prospects
get_org_performance_targetsThe ranked Performance Targeting list from /prospect/performance (#350): precomputed improvement scores, TIER1 networks excluded (they don't buy transit), the org's own ASN excluded unconditionally (#432 - a company must never see itself as its own top lead), and not_interested-tagged leads hidden by default (hide_dismissed:false to include them, labelled). Requires the org's feature_performance_targeting flag - returns an error naming that if it is off, same as the web page's feature-disabled screen. Does NOT include the web page's geocoded radius search or its downstream-customer detection - see the response's not_included note. eligible_total/truncated describe the query's own cap honestly (#434) - a caller must not read `targets.length` as the whole population.
get_org_assetsGet linked ASNs, facilities, IXPs
get_seller_profileYour sales org seller profile and its full colo footprint (#56): facility-level service areas, metro/city-level service areas, and the buildings PeeringDB already places the org in as read-only suggestions. A footprint declared only by metro is a real footprint - do not read an empty service_areas as "none".
get_custom_facilityOne of your org's private (non-PeeringDB) custom facility locations (#384) - a telco central office, a headend, a private POP typed in rather than sourced from PeeringDB. Scoped to the caller's own org; a custom facility belonging to a different org returns 'not found', never another org's data. Distinct from get_facility_info, which only ever searches the public PeeringDB table and never sees these. Pass the id from the org's own list (routes/facilities.js's /facilities page under 'Your locations').

Actions (write) 57

add_to_watchlistAdd an ASN to your watchlist. Idempotent: calling this again for an ASN you already watch UPDATES its notes/share_with_org rather than duplicating the row - that is also how to change them later.
remove_from_watchlistRemove an ASN from your watchlist
add_ixp_to_watchlistFollow an IXP - alerts on membership joins/leaves and port-speed changes (#350). Same idempotent-update behaviour as add_to_watchlist: call again to change notes/share_with_org.
remove_ixp_from_watchlistUnfollow an IXP.
add_facility_to_watchlistWatch a facility (data center) - the same Watch button as a facility page (#350). Alerts on membership changes at that building. Idempotent: calling again updates notes/share_with_org.
remove_facility_from_watchlistUnwatch a facility.
add_org_to_watchlistWatch a registry organisation (RIR org) - the same Watch button as an org page (#350). org_key is the opaque_id from lookup_rir_org. Idempotent: calling again updates notes/share_with_org.
remove_org_from_watchlistUnwatch a registry organisation.
pin_to_dashboardPin an item to your dashboard (#240, #350). type: asn | ixp | facility | org.
unpin_from_dashboardRemove a pinned item from your dashboard.
add_favoriteFavorite an ASN - the same star button as the ASN page (#350).
remove_favoriteUn-favorite an ASN (#350).
add_trace_favoriteFavorite a traceroute - the same star as the trace-detail page (#350). trace_id is the id from search_traceroutes/get_my_traceroutes, not a batch_id.
remove_trace_favoriteUn-favorite a traceroute (#350).
report_data_issueReport incorrect or missing data on an ASN, IXP, facility or org, the same form as the page's "Report incorrect data" link (#350). subject_type: asn | ixp | facility | org. subject_id is the ASN number, PeeringDB id (ixp/facility), or org registry id/slug.
list_watch_rule_typesThe alert-rule vocabulary: every subject/event combination a rule can be built on, the optional conditions each supports, and - just as importantly - the combinations that are deliberately WITHHELD because nothing in the system emits the event, each with the silent table and the reason. Call this before create_watch_rule. A rule type that is not listed as offered cannot be created, and asking for one returns the reason rather than an empty result.
create_watch_ruleCreate an alert rule. rule_key comes from list_watch_rule_types; subject_value is the ASN, the PeeringDB exchange or facility id, or a registry key like "arin:C12345678"; predicate_key and predicate_value are optional and must be one of the conditions that rule type supports; frequency is daily | weekly | monthly. Evaluated by the nightly job, so the first result arrives with the next run - a new rule subscribes you to its subject's FUTURE and never replays history. Requires the Search Scout feature.
preview_watch_ruleDry-run an alert rule before creating it: what would it have matched over the last N days? Same fields as create_watch_rule (rule_key, subject_value, predicate_key, predicate_value), no rule is saved. A refusal (evaluable:false) means the preview could not be run - it does NOT mean the rule matches nothing (#350).
list_watch_rulesYour alert rules and your org-shared ones, each with the outcome of its last evaluation. A status of "unevaluable" means the rule could NOT be run - it is not zero matches. A status of "never_observed" means the rule's event types have never produced a row anywhere, which is different again.
delete_watch_ruleDelete one of your alert rules by id, with its evaluation history. Scoped to rules you own or your org shares; a rule you cannot see is reported as not found.
set_watch_rule_activeEnable or disable one of your alert rules by id, WITHOUT deleting its evaluation history the way delete_watch_rule + create_watch_rule would. Requires the Search Scout feature. #350.
update_watch_ruleChange an existing alert rule's settings by id: name, frequency, predicate_key/predicate_value, share_with_org, active. What the rule watches (its rule_key/subject) cannot be changed this way - delete_watch_rule + create_watch_rule for that. Fields you omit are left unchanged. Requires the Search Scout feature.
trigger_domain_scanQueue a new Domain Intelligence scan for a domain. Requires Domain Intelligence access and an organization (subject to your org's daily/monthly scan quota). Runs asynchronously - poll get_domain_intel(domain) for the result; status starts "queued".
rerun_domain_scanRe-scan a domain from a previous scan you can see (yours, your org's, or any if you are an admin), linked to it via previous_scan_id. Same quota and access rules as trigger_domain_scan.
delete_domain_scanDelete a Domain Intelligence scan and its records. Must be a scan you can see (yours, your org's, or any if you are an admin) - same not-found error either way for a foreign or nonexistent id. This is permanent; there is no undo.
tag_prospectTag an ASN as a sales prospect. tag: not_interested | prospected | customer | high_priority. Dismissing a lead at /prospect (the "Not interested" action) is the same write as tag_prospect(tag: 'not_interested') - there is no separate dismiss tool (#350).
untag_prospectRemove your prospect tag from an ASN, whatever it is. Scoped to your own row only. To specifically undo a not_interested dismissal - including one an org-mate applied - use undismiss_prospect instead (#350).
undismiss_prospectUndo a "not interested" dismissal on an ASN - yours or any dismissal by your sales org - without touching a different tag (customer/prospected/high_priority) that might also be set. Matches POST /prospect/undismiss exactly; NOT the same as untag_prospect, which only removes your own tag and is not restricted to the not_interested tag (#350).
save_searchSave a search by name and its URL (e.g. "/asns?country=CA&cdn=akamai")
delete_saved_searchDelete one of your saved searches by id (id from get_saved_searches). #350.
create_auto_scoutCreate an auto-scout that re-runs a saved search on a schedule and alerts when the result count changes
set_auto_scout_frequencyChange an auto-scout run frequency (daily | weekly | monthly) by its id
delete_auto_scoutDelete one of your auto-scouts by id. Requires access level 100 and is scoped to your user_id.
create_clientCreate a CRM client/account in your sales org. tag: customer | prospect | not_interested | partner | high_priority
add_asn_to_clientAdd an ASN to one of your CRM clients (client_id from get_prospect_tags or create_client)
remove_asn_from_clientRemove an ASN from one of your CRM clients, without deleting the client. #350.
delete_clientDelete one of your CRM clients/accounts and all its members. Scoped to clients you own or your sales org shares. #350.
mark_alerts_readMark your alerts read - all of them, or one by alert_id
archive_alertsArchive and mark read all alerts belonging to you and your sales org, matching /alerts/archive-all.
dismiss_notificationDismiss one of your in-app notifications by id (from get_notifications), or all of them if id is omitted.
archive_trace_batchArchive one of your submitted traceroute batches, matching the Archive button on /my/traceroutes. Archived batches are hidden from get_my_traceroutes unless archived:true is passed.
unarchive_trace_batchRestore an archived traceroute batch of yours.
exclude_trace_batch_from_transitInclude or exclude one of your traceroute batches from the Transit Analyser (#348), matching /my/traceroutes' per-batch toggle. exclude:true removes it from that wizard's candidate pool without deleting or archiving the batch.
update_seller_profileUpdate your sales org seller profile (sells_transit/colocation/transport/ixp/consulting/cloud_connect booleans; transit_max_speed, transit_focus, transit_regions, target_market_size, notes)
set_service_areaAdd/update or remove a facility-level service area for your sales org and synchronize the seller-profile map projection. Requires Sales access.
delete_custom_facilityDelete one of your org's custom (non-PeeringDB) facility locations, and its service-area settings with it - the same delete button as the location's page (#350). A location belonging to a different org, or one that does not exist, both return the SAME 'not found' error.
update_custom_facility_service_areaSet the radius/on-net service-area settings for one of your org's custom facility locations - the same settings form as the location's page (#350). radius_km clamps to 1-2000 (default 100) and is ignored when on_net_only is true.
update_org_assetLink or unlink an ASN, facility or IXP to your organization. Requires the same level-250 access as /org and rejects read-only org members.
update_org_customerAcknowledge or dismiss an auto-detected customer belonging to your organization. Requires the same level-250 access as /org and rejects read-only org members. Acknowledging also tags the network `prospected` unless you or your org already tagged it something (#437) - the same side effect POST /org/ack-customer has.
ack_all_org_customersAcknowledge every unacknowledged, undismissed auto-detected customer for your organization, and tag their underlying ASNs `prospected` (capped at 200 distinct ASNs, oldest-detected first - matching POST /org/ack-all exactly). A tag a human already chose for a network is never overwritten. Always succeeds, even with nothing left to acknowledge.
add_org_memberInvite an existing BGPScout user (by their exact account email) into your organization. Requires you to be an org admin or site admin. Only joins a user with no organization yet, or already in this one - never moves someone out of another org - and raises their access_level to at least 200 without ever lowering it. Always returns success regardless of whether the email matched a user or was eligible to join (matches POST /org/add-member's privacy behaviour - this cannot be used to enumerate registered emails).
remove_org_memberRemove a member from your organization by their user id. Requires you to be an org admin or site admin, and you cannot remove yourself. A user id that does not exist or belongs to a different org refuses with the identical message either way.
change_org_member_roleChange a member's role within your organization (admin | member | readonly). Requires you to be an org admin or site admin, and you cannot change your own role (prevents locking yourself out). A user id that does not exist or belongs to a different org refuses with the identical message either way.
create_alert_destinationRegister a new webhook alert destination. Created DISABLED (enabled:false) - never armed by the act of saving it; enable it explicitly via update_alert_destination once you have confirmed it with test_alert_destination. url is SSRF-validated at save time (HTTPS only; loopback/RFC1918/link-local/CGNAT/multicast/reserved/cloud-metadata ranges rejected for IPv4 and IPv6; no embedded credentials; port 443 only) and re-validated fresh on every future delivery attempt, since a DNS answer can change after the row is saved. Returns a one-time HMAC signing secret (webhook_secret) for verifying the BGPScout-Signature header on what you receive - shown ONLY on this call; if lost, rotate it via update_alert_destination's rotate_secret. type:"email" is refused: this deployment has no mail provider configured, so an email destination could never receive anything - only "webhook" is accepted.
update_alert_destinationChange one of your alert destinations by id. Fields you omit are left unchanged. url (webhook only) is SSRF-validated again at update time, and if it actually changes, the destination is automatically set back to disabled - the same "not armed until confirmed" rule create_alert_destination applies, since the delivery target itself has changed. rotate_secret:true issues a brand-new HMAC signing secret (returned once, as webhook_secret) while the previous one stays valid for 24h so an in-flight receiver update is not broken mid-rotation; it does not touch label/url/enabled and cannot be combined with changing them in a way that skips the disable - pass it alone if that is all you want to do. A destination_id you do not own is reported exactly like one that does not exist.
delete_alert_destinationPermanently delete one of your alert destinations by id: its signing secret, its watch_rule opt-ins (watch_rule_delivery), and - cancelling rather than erasing, so delivery history stays auditable - any still-pending queued deliveries for it. Already-delivered/dead delivery history (alert_delivery_queue / alert_delivery_attempt rows) is retained. A destination_id you do not own is reported exactly like one that does not exist.
test_alert_destinationSend a clearly-labelled synthetic test event (test:true in the envelope) to one of your webhook destinations and report the outcome. Does NOT create a real watchlist_alert and never touches the delivery queue, so it cannot be mistaken for a real alert on either end. Only ever sends to the destination's own already-validated, already-stored URL - never a caller-supplied one - so this cannot be used to probe an arbitrary address, and SSRF validation still re-runs fresh on every call regardless. Rate-limited per caller (5 per rolling 5 minutes), since this is the one tool in this group that reaches the network. A destination_id you do not own is reported exactly like one that does not exist.

Admin 6

run_sqlExecute a read-only SQL SELECT query (admin only). If your query already ends in its own LIMIT, that one is used and the `limit` argument is ignored; otherwise `limit` is appended. Either way results are capped at 200 rows, and a query whose own LIMIT exceeds that is rejected with a message saying so rather than silently truncated (#503).
get_system_statsOverall system statistics
get_pipeline_historyData-pipeline operations view (admin only) - the same three panels as /history: the last 20 data_refresh_log runs, IXP peer-count/speed changes between the latest two ix_peer_history snapshots, and ASN facility/IXP-count changes between the latest two asn_facility_history snapshots. Platform-wide, not scoped to any watchlist - distinct from get_dashboard_digest, which is the personal per-watched-ASN version of the facility/IXP change feed. Admin only (access_level >= 300); the web page also accepts a personal beta_features flag below that level, which this tool does not replicate.
get_mcp_usage_statsMCP adoption and usage from mcp_call_log (#457): calls/day split by principal type (api_key vs oauth) over the trailing window, distinct active principals, tool call counts (including never-called tools, by diffing against the live tool set - a strong deprecation signal), client mix from the initialize handshake, and error/denial counts by tool. Data only exists from when mcp_call_log started being written; an empty or short history is a fresh table, not zero usage.
get_data_coverageData coverage scores per country [BETA: the underlying calculation is still settling - treat the result as directional, not yet safe to quote as a stated fact. See /traceroutes/analysis/scoreboard on the site for the current caveats.]
get_sales_digest_previewAdmin-only preview of the weekly sales digest email: top-10 ASNs with lead_score >= 50, top-10 by boomerang_rate (routing-quality outliers, >15% with >= 5 recent traces), ASNs registered in the last 7 days, and recent new-IXP-join watchlist alerts. Same four queries as /sales-lab/digest-preview (#350). Every ingredient is separately available via other tools (get_buy_signals, get_boomerang_stats, get_new_networks, get_events) - this is the curated combined shape only.

Recommended subsets

With 185 tools, you can narrow what an assistant loads (e.g. OpenWebUI's Function Name Filter List):