Appearance
probes
66 endpoints at a glance
| Method | Path | Summary |
|---|---|---|
POST | /atlas/measurements-probes/refresh/ | Refresh Measurements Probes |
POST | /atlas/probe-measurement-health/snapshot/ | Snapshot Probe Measurement Health |
POST | /atlas/probes-archive/refresh/ | Refresh Probes Archive |
POST | /atlas/probes-health/snapshot/ | Snapshot Probes Health |
POST | /atlas/probes/refresh/ | Refresh Probes |
GET | /graphs/probes/new/ | Get Probes New |
GET | /graphs/probes/new/list/ | Get Probes New List |
GET | /graphs/probes/new/map/ | Get Probes New Map |
GET | /measurements-probes/ | List Measurements Probes |
GET | /measurements-probes/{measurement_id}/{probe_id}/ | Get Pair |
POST | /measurements-probes/admin/clear/ | Clear Collection |
POST | /measurements-probes/admin/refresh/run | Run Refresh |
GET | /measurements-probes/admin/runs/ | List Admin Runs |
GET | /measurements-probes/admin/stats/ | Get Admin Stats |
GET | /measurements-probes/by-measurement/{measurement_id}/ | List For Measurement |
GET | /measurements-probes/by-probe/{probe_id}/ | List For Probe |
GET | /probes-archive/{date}/ | Get For Date |
GET | /probes-archive/daily/ | List Daily |
GET | /probes-archive/daily/{date}/ | Get Daily |
POST | /probes-archive/daily/{date}/recompute-stats | Recompute Daily Stats |
POST | /probes-archive/daily/{date}/run | Run Daily |
POST | /probes-archive/daily/{date}/stop | Stop Daily |
POST | /probes-archive/daily/backfill | Submit Backfill |
POST | /probes-archive/daily/backfill-stale-stats | Backfill Stale Daily Stats |
POST | /probes-archive/daily/backfill/recover-stale | Recover Stale Backfill |
GET | /probes-archive/daily/backfill/status | Get Backfill Status |
POST | /probes-archive/daily/recompute-all | Recompute All Daily Stats |
POST | /probes-archive/daily/recompute-stats-range | Recompute Daily Stats Range |
POST | /probes-archive/daily/seed-first-seen | Seed First Seen |
GET | /probes-archive/daily/stats-coverage | Daily Stats Coverage |
GET | /probes-archive/deployment-filters/ | Get Deployment Filters |
GET | /probes-archive/deployment-movers/ | Get Deployment Movers |
GET | /probes-archive/deployment-series/ | Get Deployment Series |
GET | /probes-archive/overview-stats/ | Get Overview Stats |
GET | /probes-archive/probes/{probe_id}/ | Get For Probe |
GET | /probes-archive/series/ | Get Series |
GET | /probes-health/ | List Problem Probes |
GET | /probes-health/{probe_id}/ | Get Probe Health |
POST | /probes-health/admin/clear/ | Clear Collections |
GET | /probes-health/admin/runs/ | List Admin Runs |
GET | /probes-health/admin/stats/ | Get Admin Stats |
GET | /probes-health/connectivity-debug | Connectivity Debug |
GET | /probes-health/events/ | List Probe Health Events |
GET | /probes-health/measurements/ | List Probe Measurement Health |
GET | /probes-health/measurements/{probe_id}/ | Get Probe Measurement Health |
POST | /probes-health/measurements/{probe_id}/recheck/ | Recheck Probe Measurement Health |
POST | /probes-health/measurements/recheck-stale/run | Recheck Stale Probe Measurement Health |
GET | /probes-health/measurements/stats/ | Get Probe Measurement Health Stats |
GET | /probes-health/series/ | Get Probes Health Series |
POST | /probes-health/snapshot/run | Run Snapshot |
GET | /probes-health/stats/ | Get Probes Health Stats |
GET | /probes-result-health/ | List Problem Probes |
GET | /probes-result-health/{probe_id}/ | Get Probe Result Health |
GET | /probes-result-health/events/ | List Result Health Events |
GET | /probes-result-health/series/ | Get Result Health Series |
POST | /probes-result-health/snapshot/run | Run Snapshot |
GET | /probes-result-health/stats/ | Get Result Health Stats |
GET | /probes/ | List Probes |
GET | /probes/{probe_id}/cached/ | Get Probe Cached |
GET | /probes/{probe_id}/changes/ | Get Probe Changes |
GET | /probes/{probe_id}/nearest/ | Get Nearest Probes |
GET | /probes/firmwares/ | List Probe Firmwares |
GET | /probes/stats/ | Get Probe Stats |
POST | /probes/stats/refresh | Refresh Probe Stats |
GET | /probes/tags/ | List Probe Tags |
GET | /trends/hbase/ | Get Latest Speed |
Get Probes New
GET
/graphs/probes/new/
New-probes graph — Mongo-backed.
Replaces the legacy CouchDB implementation. Same wire surface,
same envelope shape; filters and group dimensions that depend on
data not yet in Mongo are accepted but ignored, with their names
echoed in dropped_filters / dropped_groups so the UI can
surface a notice.
Parameters
Query Parameters
start
stop
date
group
Default
"days"country
city
region
asn
status
firmware_version
anchors
explain
Type
boolean
Default
falsequery_field
limit
Type
integer
Default
10000version
reporting
hardware
eyeballs
report_2024
Responses
Successful Response
application/json
JSON
[
]
Get Probes New List
GET
/graphs/probes/new/list/
New-probes flat list — Mongo-backed.
Companion to :func:get_probes_new; shares the same selector
semantics but returns one rows entry per matching probe (no
grouping) with the table columns: id, description, country, ASN,
status, type, city, first_connected. No group parameter — this
isn't a grouping view.
Parameters
Query Parameters
start
stop
date
country
city
region
asn
status
firmware_version
anchors
query_field
limit
Type
integer
Default
10000version
reporting
hardware
eyeballs
report_2024
Responses
Successful Response
application/json
JSON
[
]
Get Probes New Map
GET
/graphs/probes/new/map/
New-probes geographic projection — Mongo-backed.
Companion to :func:get_probes_new; shares the same selector
semantics so the bar-chart and the map tab in the frontend stay
coherent. Returns one points entry per matching probe that
has a public location. Probes with data.geometry == null
are excluded; the omitted count is surfaced separately so the
frontend can render a "X have no public location" caption.
No group parameter — this isn't a grouping view; the bar-chart
endpoint owns that.
Parameters
Query Parameters
start
stop
date
country
city
region
asn
status
firmware_version
anchors
query_field
limit
Type
integer
Default
10000version
reporting
hardware
eyeballs
report_2024
Responses
Successful Response
application/json
JSON
[
]
List Probe Tags
GET
/probes/tags/
Distinct {slug, name} pairs across the tags carried by
every probe in db.probes. Powers the tag dropdown in the
probe-list view; declared before any /{probe_id}/...
route so the literal tags segment doesn't get matched as
an int id and 422'd by FastAPI's path coercion.
Responses
Successful Response
application/json
JSON { "additionalProperties": "string" }
[
]
List Probe Firmwares
GET
/probes/firmwares/
Distinct firmware-version integers in use across
db.probes, newest first. Powers the firmware dropdown in the
probe-list view so the operator sees only versions that exist
on at least one probe. Same path-ordering caveat as
/probes/tags/ — declared before any /{probe_id}/...
catch.
Responses
Successful Response
application/json
JSON 0
[
]
Get Probe Stats
GET
/probes/stats/
Whole-fleet distribution stats over db.probes (current
state).
No filters → the cached rollup snapshot (lazy-populated on first
miss, so the public page is never empty), carrying
computed_at. Any of status / anchors_only / country
→ a live, uncached recompute with an extra $match (live: true). Public read — aggregate counts over public RIPE probe
metadata, same posture as /statistics/anchors.
Declared before the /{probe_id}/... routes so the literal
stats segment isn't coerced to an int id (same caveat as
/probes/tags/ and /probes/firmwares/). Wrapped in
:func:asyncio.to_thread — the aggregation is blocking PyMongo.
Parameters
Query Parameters
status
anchors_only
country
Responses
Successful Response
application/json
JSON
[
]
Refresh Probe Stats
POST
/probes/stats/refresh
Recompute the whole-fleet stats snapshot now (DB-only, no
RIPE). Heavy at fleet scale, so it's off the hot path and wrapped
in :func:run_and_record (lands in db.task_history). Returns
the freshly-written rollup doc. The same refresh also runs on
every probe-refresh cron tick / manual probe refresh.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Probe Changes
GET
/probes/{probe_id}/changes/
Most-recent-first change events for a probe from
db.probes_history.
Logged-in only — matches the :class:probes_archive reader.
Each row is one refresh-tick where at least one tracked field
changed, with the diff under changes. Distinct from the
legacy /{probe_id}/history/ endpoint above, which still
talks to CouchDB.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
since_ts
until_ts
skip
Type
integer
Default
0limit
Type
integer
Default
100Responses
Successful Response
application/json
JSON { "additionalProperties": "string" }
[
]
Get Nearest Probes
GET
/probes/{probe_id}/nearest/
N probes closest (great-circle) to the given probe.
Public read — probe locations are already exposed via the
new-probes / probe-list map views; nothing new disclosed here.
Excludes the target probe from the result. Returns [] when
the target is missing or has no usable geometry.
Parameters
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
limit
Type
integer
Default
10Responses
Successful Response
application/json
JSON
[
]
Get Probe Cached
GET
/probes/{probe_id}/cached/
Mongo-first single-probe lookup over db.probes.
Serves the cached envelope whenever the probe exists in
db.probes — the hourly fleet cron (which paginates the whole
public /probes/ set) keeps it current, so the common path is a
pure Mongo read and never touches RIPE. Only a genuine cache-miss
(a probe registered since the last fleet pass) or
?refresh=true refetches this one probe from RIPE, applying
the same diff/probes_history/new-probe-announcer/city-enrichment
a cron refresh would.
Public (the probe-detail page + measurement-map markers are
public — same posture as the legacy RIPE-proxied lookup it
replaces). 404 when RIPE doesn't know a not-yet-cached id, 403 when
the probe is private (both pass-through — never negatively cached),
502 on a transient RIPE failure. Returns {source, data, meta, enrichments} (source = cache | ripe); the wrapper
unwraps data for the existing RipeProbe consumers.
Wrapped in asyncio.to_thread — the Mongo read is blocking
PyMongo, and the rare cache-miss adds a synchronous RIPE
round-trip (bounded by the RIPE HTTP timeout).
Parameters
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
refresh
Type
boolean
Default
falseResponses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Probes
GET
/probes/
Filtered list of probes — Mongo-backed.
Replaces the historical CouchDB-backed implementation; envelope
shape is preserved (count / time / query / results).
Filters that depend on data not yet in Mongo
(version / dnsmon / controller) are accepted but
ignored, with the requested names echoed in a dropped_filters
array so the UI can surface a notice. reporting is now
Mongo-native — the refresh job persists
enrichments.reporting and the selector matches it directly.
Parameters
Query Parameters
limit
Type
integer
Default
1000probe_id
status
start
stop
status_since
asn
tag
anchor
first_connected
last_connected
firmware
region
country
city
public
reporting
search
count_only
field
explain
Type
boolean
Default
falseversion
dnsmon
controller
date
path
Responses
Successful Response
application/json
JSON
[
]
List Daily
GET
/probes-archive/daily/
Newest-first list of daily-summary rows.
Admin-gated because the rows carry error tracebacks. Optional
since / until are inclusive YYYY-MM-DD bounds; limit
clamped to 1000 by the storage layer.
lite=true projects away the heavy stats block and the
error traceback — useful for whole-year fetches like the
admin calendar view where only the per-day status pill is
rendered. Drops a year-wide payload from ~3 MB to ~50 KB.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
since
until
limit
Type
integer
Default
100lite
Type
boolean
Default
falseResponses
Successful Response
application/json
JSON { "additionalProperties": "string" }
[
]
Get Daily
Stop Daily
POST
/probes-archive/daily/{date}/stop
Stop a queued or running daily import (cooperative).
queued → import_day's entry-check writes a terminal
stopped row without importing. running → the per-batch
checkpoint bails, finishing as stopped with the probe rows
that already landed preserved (stats deliberately not recomputed
over a partial import — re-backfill the date for a clean stats
block). Already-terminal / missing → 409 / 404.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
date*
Type
Requiredstring
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Run Daily
POST
/probes-archive/daily/{date}/run
Synchronous import-run for one date — admin cookie-session.
Blocks for the duration of the import (~minutes for ~50k probes).
Same audit wiring as the api-key-gated
POST /atlas/probes-archive/refresh/ endpoint in
:mod:api.main — both go through :func:run_and_record so
db.task_history and db.probes_archive_daily stay in sync.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
date*
Type
Requiredstring
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Recompute Daily Stats
POST
/probes-archive/daily/{date}/recompute-stats
Rebuild the stats block for one date from saved archive rows.
No RIPE call — reads only db.probes_archive. Useful when the
stats schema gains new fields (e.g. cross-tabs added later) and
historical rows need backfilling, or when an operator just wants
fresh numbers without paying the import cost.
Fast (~seconds) — runs synchronously and returns the updated
daily summary directly. Wrapped in :func:run_and_record so the
operation lands in db.task_history alongside the normal
import runs.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
date*
Type
Requiredstring
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Recompute Daily Stats Range
POST
/probes-archive/daily/recompute-stats-range
Rebuild the stats block for every date in a window.
No RIPE call — reads only db.probes_archive and rewrites each
daily summary's stats / probes_count / stats_recomputed_at
in place. Loops :meth:ProbesArchive.recompute_stats across the
range; dates with no archive rows or no daily-summary row are
surfaced as skipped entries rather than aborting the run.
Synchronous on purpose — per-date recompute is ~seconds (it's
just $group aggregations against an already-indexed
collection), and the
:attr:ProbesArchive.RECOMPUTE_RANGE_MAX_DAYS cap keeps the
worst-case request inside the frontend's long-running HTTP
timeout. Operators wanting a wider rebuild chunk the submission.
Wrapped in :func:run_and_record so the bulk job lands as a
single entry in db.task_history (one row per range, not one
per date — the per-date trail lives in stats_recomputed_at
on each daily-summary row).
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "since": "string", "until": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Recompute All Daily Stats
POST
/probes-archive/daily/recompute-all
Unconditionally recompute every daily-stats row across the
full history — fire-and-forget.
The "fix everything" lever, distinct from the stale-drain: it
rebuilds all days regardless of their schema/freshness
classification, so days wrongly stamped current under an
earlier/incomplete first_seen (the cause of a flat new_probes
history after a seed) actually get corrected — something
backfill-stale-stats and the drain cron can't do, since they only
touch days still classified stale.
No RIPE call (DB-only $group recompute), idempotent, and empty
days seal as they go. A full ~10-year rebuild runs well past the
gateway timeout, so it's handed to a background task — one
recompute_probes_archive_stats_all row in db.task_history —
and returns immediately. Poll
GET /probes-archive/daily/stats-coverage (or watch the
New-probes graph fill in) for progress. The 15-min drain cron keeps
it current afterwards.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Seed First Seen
POST
/probes-archive/daily/seed-first-seen
One-time backfill of db.probes_archive_first_seen from the
full archive.
Required after deploy because the daily stats' new_probes /
by_country_new now read from this cache instead of the
full-collection $group that was hitting the Mongo socket-
timeout cliff. Walks year by year (each $group bounded to one
year's slice) and $min-upserts into the cache — idempotent
and safe to re-run.
Fire-and-forget: a full-archive rebuild scans many years of rows
and runs well past the gateway timeout (a single full year already
does), so the work is handed to a background task — wrapped in
:func:run_and_record as one seed_probes_archive_first_seen
(trigger=manual) row — and the request returns {"status": "started"} immediately. Poll
GET /task-history/?task_name=seed_probes_archive_first_seen
for the result counters / completion.
since / until (YYYY or YYYY-MM-DD) narrow the seed
to a sub-range; a bare year is widened to that year's full span.
A malformed bound is rejected synchronously (400) before the job
is scheduled.
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "since": "string", "until": "string"
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Daily Stats Coverage
GET
/probes-archive/daily/stats-coverage
Per-class daily-stats coverage over the retained window.
Pure read — one indexed date-range scan, no recompute.
Returns the :meth:ProbesArchive.stats_coverage blob
(schema_version + counts of
missing/stale_schema/stale_data/current +
stale_dates). 400 on a bad / inverted range.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
since
inclusive start, YYYY-MM-DD
until
inclusive end, YYYY-MM-DD
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Backfill Stale Daily Stats
POST
/probes-archive/daily/backfill-stale-stats
Force an immediate newest-first recompute of stale daily-stats.
The on-demand burst counterpart to the drain cron — use right
after a deliberate STATS_SCHEMA_VERSION bump to converge now
rather than waiting for the cron to grind through. DB-only,
idempotent, bounded (max_days server-clamped). Wrapped in
:func:run_and_record so it lands in db.task_history.
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "max_days": 1000
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Submit Backfill
POST
/probes-archive/daily/backfill
Queue a date range for serial backfill.
Returns immediately with the list of dates that were queued.
status: "queued" rows are pre-inserted into
db.probes_archive_daily so the admin dashboard's heatmap
reflects the submission right away. The in-process worker then
pulls one date at a time and runs import_day against it; each
run audits to db.task_history with trigger: "backfill".
The queue lives in process memory — a backend restart drops
pending entries, but the pre-inserted queued rows survive,
and re-submitting the same range picks up where the worker left
off (the dates that already succeeded are filtered out by
only_missing=true).
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "since": "string", "until": "string", "only_missing": true
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Backfill Status
GET
/probes-archive/daily/backfill/status
Worker queue depth, currently-importing date, and liveness.
All three fields are best-effort snapshots — by the time the
response reaches the client the worker may have advanced. The
dashboard already polls daily rows for status transitions; this
endpoint is for the queue-depth badge and the worker-alive
tripwire that surfaces the recovery button.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "queued": 0, "in_flight": "string", "worker_alive": true
{
}
Recover Stale Backfill
POST
/probes-archive/daily/backfill/recover-stale
Re-queue any rows stuck in running / queued state.
The in-process worker's queue lives in memory — a backend
restart drops it, but the queued / running rows it was
tracking persist in db.probes_archive_daily. The same
recovery runs automatically at worker startup; this endpoint
covers the rare follow-up case where the worker task died
silently while the backend kept running, leaving the queue
stranded.
Safe to call any time. :meth:ProbesArchive.import_day is
idempotent (per-(probe, day) upserts plus a daily-summary
rewrite), so re-running over a date that's part-imported
completes it; re-running over a fully-imported date is a no-op
against the per-probe collection and a fresh recompute of the
stats block.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Series
GET
/probes-archive/series/
Daily stats blob across a date range, oldest-first.
Drives the operator-facing /graphs/probes-archive trends
view. Each entry in results is one probes_archive_daily
doc with its pre-computed stats block — the trend view's
eight charts (status / capability / ASN-count / new probes /
anchors / country / hardware-generation / region) all hang off
this single fetch.
include_asn=true opts in to the heavy stats.by_asn
distribution (tens-of-thousands of entries per row in the worst
case); default omits it. The scalar stats.asn_count_v4 /
asn_count_v6 counters are always included regardless.
include_missing=true opts in to the
stats.missing_countries + stats.missing_cities coverage
lists. The cities list is ~80 KB per row at the 500k-population
threshold; default omits it to keep the series payload small.
The single-day detail route (/daily/{date}/) always carries
both.
No auth gate — the data is aggregate population counts over
public RIPE info; matches the existing pattern for
/graphs/probes/new and /events/buckets/.
Declared before /{date}/ further down so the literal
series segment can't be mis-routed to the per-day reader.
Parameters
Query Parameters
since
until
include_asn
Type
boolean
Default
falseinclude_missing
Type
boolean
Default
falseResponses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Deployment Series
GET
/probes-archive/deployment-series/
Probe count over time — multi-select filters + optional split.
Backs /graphs/probes-archive/deployment. Auto-routes between
the daily-stats fast path (a multi-year fleet line is cheap) and a
bounded raw-aggregation fallback for filter combos the stored
crosstabs can't answer (source says which). Gap days
(missing / non-success import) come back as null so a bad
import never reads as a fleet collapse.
No auth gate — aggregate counts over public RIPE info, same as
/series/. Declared before /{date}/ so the literal segment
can't be mis-routed. 400 on a bad / inverted / over-cap range or
an unsupported metric/dimension combo.
Parameters
Query Parameters
since
until
country
region
status
asn
split
Type
string
Default
"none"metric
Type
string
Default
"count"smooth
Type
integer
Default
0top_n
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Deployment Filters
GET
/probes-archive/deployment-filters/
Selector option lists for the deployment view (countries /
regions / top ASNs from the latest daily row + the fixed RIPE
status set). Single-doc read — instant, no scan. No auth gate.
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Deployment Movers
GET
/probes-archive/deployment-movers/
Biggest growers / shrinkers for a dimension over the window
(first-vs-last non-gap day delta from the stored marginals). Pure
daily-stats read, no auth gate. 400 on a bad range / dimension.
Parameters
Query Parameters
since
until
dimension
Type
string
Default
"country"limit
Type
integer
Default
15Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Overview Stats
GET
/probes-archive/overview-stats/
Whole-collection top-line for the admin panel — date range,
coverage, total rows, storage size, latest import, probes-per-day
aggregates. See :meth:ProbesArchive.get_overview_stats.
Declared before /{date}/ below so the literal
overview-stats segment doesn't get matched as a date string
and routed to the per-day reader. FastAPI tries routes in
declaration order — keep this above the date-catch.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get For Date
GET
/probes-archive/{date}/
Per-day list of every probe row.
Capped server-side — full daily list is ~50k rows; limit
clamps to 5000. Use skip for pagination if you really need
everyone.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
date*
Type
Requiredstring
Query Parameters
skip
Type
integer
Default
0limit
Type
integer
Default
1000Responses
Successful Response
application/json
JSON { "additionalProperties": "string" }
[
]
Get For Probe
GET
/probes-archive/probes/{probe_id}/
Per-probe history, oldest-first.
Optional since / until (YYYY-MM-DD) bound the date
range; without them the full history is returned.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
since
until
Responses
Successful Response
application/json
JSON { "additionalProperties": "string" }
[
]
Get Probes Health Stats
Get Probes Health Series
GET
/probes-health/series/
Hourly fleet-health snapshots over an inclusive YYYY-MM-DD
window (oldest-first) — drives the probe-health trends view. Each
point carries severity / issue counts + active + connected totals
for that UTC hour.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
since*
Type
Requiredstring
until*
Type
Requiredstring
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Probe Health Events
GET
/probes-health/events/
Paginated event feed (newest first). All filters AND-compose.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
since
until
probe_id
issue_key
severity
Filter on issue severity.
state
Filter on event state.
limit
Type
integer
Default
50offset
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Connectivity Debug
GET
/probes-health/connectivity-debug
One-shot connectivity-pass diagnostic. Runs the real
classify_fleet pass live (fast — no full snapshot) and returns
event counts, what it classified, the per-flag breakdown, samples,
and any error. Use this to see why the connectivity_* issues are
or aren't firing without digging through task_history.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Run Snapshot
POST
/probes-health/snapshot/run
Cookie-auth manual snapshot trigger. Fire-and-forget: a full-fleet
snapshot (stream ~all recent connection events + rule-eval + per-probe
upserts across the connected fleet) routinely runs longer than the
gateway timeout, so running it inline returned a 504 even though the
work completed. We hand it to a background task and return immediately;
the dashboard polls /stats/ for the new last_snapshot_ts and
refreshes when it lands. Still wrapped in :func:run_and_record so it
shows up in db.task_history (with the connectivity diagnostics)
alongside the scheduled runs.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Problem Probes
GET
/probes-health/
Paginated list of active probes currently carrying issues.
?issue=<key> / ?severity=<tier> narrow it; joined
description / country / status name is inlined per row so the
table needs no per-row fetch.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
issue
severity
Filter on issue severity.
limit
Type
integer
Default
50offset
Type
integer
Default
0sort
recent = most-recently-changed first; oldest = longest-stable first
Type
string
Valid values
"recent""oldest"Default
"recent"Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Admin Stats
List Admin Runs
GET
/probes-health/admin/runs/
Recent runs of the snapshot task with their full counters
blob. Limit capped server-side at 200.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
limit
Type
integer
Default
50Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Clear Collections
POST
/probes-health/admin/clear/
Wipe db.probes_health + db.probes_health_events.
Destructive — the next tick repopulates from scratch (and the
first such tick is a whole-fleet bootstrap). task_history
untouched. Requires confirm: true.
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "confirm": false
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Probe Measurement Health Stats
List Probe Measurement Health
GET
/probes-health/measurements/
Paginated stored measurement-health results, newest-checked
first. Optional ?verdict=critical narrows to the failing
probes.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
verdict
Filter on the stored verdict.
limit
Type
integer
Default
50offset
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Recheck Stale Probe Measurement Health
POST
/probes-health/measurements/recheck-stale/run
Cookie-auth bulk "re-check stale now" burst — re-checks every
connected works-tagged probe whose stored result is missing/older
than the TTL (oldest-first), server-clamped to MANUAL_MAX.
Same op as the api-key POST /atlas/probe-measurement-health/snapshot/; duplicated so the
admin button works on the session cookie. run_and_record-
wrapped so it lands in db.task_history (trigger="manual").
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "max_probes": 0
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Probe Measurement Health
GET
/probes-health/measurements/{probe_id}/
Stored measurement-health result for one probe. Powers the
ProbeLookupView Health-tab "Measurement results" panel. Read access
is any logged-in user (the Health tab is logged-in-gated); the
re-check write below stays staff-only. 404 when
the probe hasn't been checked yet (the UI then shows a "not
checked yet" placeholder + offers the re-check button).
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
probe_id*
Type
Requiredinteger
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Recheck Probe Measurement Health
POST
/probes-health/measurements/{probe_id}/recheck/
Re-check + persist one probe right now (the per-probe "Re-check
now" button), returning the refreshed stored doc — same shape as
GET /measurements/{probe_id}/. 404 when there's no such probe
in db.probes. Off-loaded to a worker thread so the RIPE calls
never block the event loop.
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
probe_id*
Type
Requiredinteger
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Probe Health
GET
/probes-health/{probe_id}/
Current state + recent events for one probe. Powers the
ProbeLookupView "Health" surface — read access is any logged-in
user (the tab is logged-in-gated). 404 when the probe has no health
record yet (never snapshotted — e.g. a probe that's never been
connected and has had no issue, before any bootstrap).
Parameters
Header Parameters
authorization
x-api-key
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
events_limit
Type
integer
Default
50Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Result Health Stats
Get Result Health Series
GET
/probes-result-health/series/
Hourly fleet aggregates over an inclusive YYYY-MM-DD window
(oldest-first) — drives the trend chart. Each point carries grade +
per-flag counts + score-bucket distribution for that UTC hour.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
since*
Type
Requiredstring
until*
Type
Requiredstring
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Result Health Events
GET
/probes-result-health/events/
Flag-transition feed (newest first). A row exists only where a
probe's flag flipped on or off, so this is the sparse change log.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
probe_id
flag
state
Filter on flag transition direction.
limit
Type
integer
Default
50Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Run Snapshot
POST
/probes-result-health/snapshot/run
Cookie-auth manual snapshot trigger. Fire-and-forget — the pass
scans every well-known channel's cached results across the connected
fleet and can run past the gateway timeout, so it's handed to a
background task (recorded in db.task_history). The dashboard polls
/stats/ for the new last_snapshot_ts and refreshes.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Problem Probes
GET
/probes-result-health/
Worst probes first (score ascending). flag / country filter
AND-compose; only_flagged (default) hides healthy probes.
Parameters
Header Parameters
authorization
x-api-key
Query Parameters
flag
country
only_flagged
Type
boolean
Default
truelimit
Type
integer
Default
100skip
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Probe Result Health
List Measurements Probes
GET
/measurements-probes/
Paginated participation catalog. Either or both of
measurement_id / probe_id narrow the result set. Hides
tombstoned pairs by default.
Parameters
Query Parameters
measurement_id
probe_id
limit
Type
integer
Default
100offset
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List For Measurement
GET
/measurements-probes/by-measurement/{measurement_id}/
Every probe currently participating in one measurement.
Default limit is generous (1000) — mesh measurements run
~700 anchors and the typical caller wants the full list in one
response. Bump offset for pagination if the call ever exceeds
the cap.
Parameters
Path Parameters
measurement_id*
Type
Requiredinteger
Query Parameters
limit
Type
integer
Default
1000offset
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List For Probe
GET
/measurements-probes/by-probe/{probe_id}/
Every measurement one probe currently participates in. Reverse
of the per-measurement lookup — useful for probe-detail drill-downs.
Parameters
Path Parameters
probe_id*
Type
Requiredinteger
Query Parameters
limit
Type
integer
Default
1000offset
Type
integer
Default
0Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Admin Stats
GET
/measurements-probes/admin/stats/
Combined run-stats + collection-stats blob for the admin panel.
Both sub-queries run in parallel worker threads via
:func:asyncio.to_thread so the FastAPI event loop stays
responsive — see the matching anchors-mesh-health admin/stats
endpoint for the round-trip-consolidation rationale.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
List Admin Runs
Run Refresh
POST
/measurements-probes/admin/refresh/run
Cookie-auth manual refresh trigger.
Fire-and-forget — mirrors the shape of the api-key-gated
POST /atlas/measurements-probes/refresh/ so reverse-proxy
timeouts can't cut the refresh mid-walk. The work runs in a
background thread under :func:run_and_record and the eventual
summary lands in db.task_history; the admin panel polls
GET /admin/runs/ for completion.
Returns one of two shapes:
{"status": "started", ...}— the run was spawned.{"status": "already_running", ...}— another refresh is in
flight in this process; nothing was spawned.
Parameters
Header Parameters
authorization
x-api-key
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Clear Collection
POST
/measurements-probes/admin/clear/
Wipe db.measurements_probes. Destructive — the next refresh
tick rebuilds from RIPE. Requires confirm: true.
Parameters
Header Parameters
authorization
x-api-key
Request Body
application/json
JSON "confirm": false
{
}
Responses
Successful Response
application/json
JSON "additionalProperties": "string"
{
}
Get Pair
Get Latest Speed
Refresh Probes
POST
/atlas/probes/refresh/
Pull every probe from RIPE Atlas and upsert into db.probes.
Synchronous from the caller's perspective — the request blocks for
the duration of the refresh (~1–3 min for ~50k probes). Used as a
bootstrap (the first hourly tick may be up to an hour away on a
fresh deploy) and as a manual recovery handle when the scheduled
job fails. Returns the summary dict from
:meth:Probes.refresh_all.
Routed through :func:run_and_record so this manual run lands in
db.task_history next to the scheduled ones, distinguishable by
the trigger="manual" field.
Authorizations
APIKeyQuery
Type
API Key (query: api-key)
or
APIKeyHeader
Type
API Key (header: x-api-key)
Responses
Successful Response
application/json
JSON
[
]
Refresh Measurements Probes
POST
/atlas/measurements-probes/refresh/
Kick a fresh db.measurements_probes refresh and return
immediately.
Fire-and-forget by design — the refresh walks every live anchor
measurement with one RIPE round-trip each (5–10 min even with the
8-way concurrency inside :meth:MeasurementsProbes.refresh_all),
which is well past any reverse-proxy timeout. The work runs in
a background thread under :func:run_and_record, so the eventual
success / failure / counters land in db.task_history and can
be polled via GET /measurements-probes/admin/runs/.
Returns one of two shapes:
{"status": "started", ...}— the run was spawned.{"status": "already_running", ...}— another refresh is in
flight in this process; nothing was spawned. Operator should
wait for the in-flight run to finish and poll the runs endpoint.
Authorizations
APIKeyQuery
Type
API Key (query: api-key)
or
APIKeyHeader
Type
API Key (header: x-api-key)
Responses
Successful Response
application/json
JSON
[
]
Snapshot Probes Health
POST
/atlas/probes-health/snapshot/
Run the probe-health snapshot pass now.
Evaluates the candidate probe set against the issue-rule registry
(see :mod:api.atlas.probes_health), upserts current state into
db.probes_health, and appends state-transition events to
db.probes_health_events. Manual companion to the hourly
snapshot_probes_health cron — the first manual call after a
fresh deploy runs the one-time bootstrap (whole-fleet) pass so the
dashboard isn't empty until the next cron tick.
Routed through :func:run_and_record so the run lands in
db.task_history next to the scheduled ones,
trigger="manual".
Authorizations
APIKeyQuery
Type
API Key (query: api-key)
or
APIKeyHeader
Type
API Key (header: x-api-key)
Responses
Successful Response
application/json
JSON
[
]
Snapshot Probe Measurement Health
POST
/atlas/probe-measurement-health/snapshot/
Run the probe measurement-result health drain now (bulk burst).
Re-checks every connected, system-ipvX-works-tagged probe whose
stored db.probe_measurement_health result is missing or older
than the TTL (oldest-first), up to the server-side
ProbeMeasurementHealthSettings.MANUAL_MAX ceiling. Manual
companion to the 15-min drain_probe_measurement_health cron —
bootstrap a fresh deploy or force convergence instead of waiting
for the drain to grind through. Idempotent + safe to spam
(bounded; a fresh probe is a no-op re-check).
Routed through :func:run_and_record so the run lands in
db.task_history next to the scheduled ones,
trigger="manual".
Authorizations
APIKeyQuery
Type
API Key (query: api-key)
or
APIKeyHeader
Type
API Key (header: x-api-key)
Responses
Successful Response
application/json
JSON
[
]
Refresh Probes Archive
POST
/atlas/probes-archive/refresh/
Import the RIPE probe-archive for one date (default: yesterday).
Synchronous from the caller's perspective — the request blocks for
the duration of the import (~minutes for ~50k probes). Routed
through :func:run_and_record so the run lands in both
db.task_history (operational view) and
db.probes_archive_daily (per-date business view).
Authorizations
APIKeyQuery
Type
API Key (query: api-key)
or
APIKeyHeader
Type
API Key (header: x-api-key)
Parameters
Query Parameters
date
Responses
Successful Response
application/json
JSON
[
]