API reference
Backhauls
Backhaul links: endpoints, capacity, usage and cross-link pings
- List backhauls
GET /v1/backhauls - Get a backhaul
GET /v1/backhauls/{bhid} - Get a backhaul's health
GET /v1/backhauls/{bhid}/health - Get a backhaul's history
GET /v1/backhauls/{bhid}/history/{series}
List backhauls
Your backhaul links: the router and radio at each end, the capacity Swift Fox uses for the link and where it comes from (fixed by hand, bandwidth tests or the radios), the latest traffic, the latest ping across the link, and alert_state: ok, recovering (alerted recently but back to good), or the severity of the worst open issue. Filter by site or region (matching any end) or search names with q. While ping monitoring is on, backhauls are pinged router to router almost continuously, so get_backhaul_history (series pings) has detailed history. Directions are named for the link's ends: ap_to_su is toward the SU end (down) and su_to_ap is from the SU end (up). The ap_router/ap_radio and su_router/su_radio objects say which devices those ends are.
Parameters
-
ispstring queryISP code from GET /isps. Optional when the key reaches exactly one ISP.
-
siteinteger or string queryRestrict to backhauls with any end at this site: site_id or site code
-
regioninteger queryRestrict to backhauls with any end in this region: region_id from
list_regions -
qstring querySubstring match on backhaul name
-
limitinteger queryMax rows (default 100, max 300)
-
cursorstring querynext_cursor from the previous page
Response
Also available as CSV: add format=csv. Columns follow the field order below, with nested fields as dotted columns
(ap.name).
Paged: pass next_cursor back as cursor for the next page.
-
countinteger -
next_cursorstring nullablePass as cursor to get the next page; null on the last page
-
backhaulsarray of objectsEach item: 13 fields
-
bhidinteger -
namestring -
link_typestringe.g. wireless, wired
-
ap_routerobject nullableThe router at the AP end
3 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
-
su_routerobject nullableThe router at the SU end
3 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
-
ap_radioobject nullableThe radio at the AP end
3 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
-
su_radioobject nullableThe radio at the SU end
3 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
-
capacityobject3 fields
-
sourcestringWhere the capacity figure comes from: fixed (set by hand), tcptest (bandwidth tests) or wireless (the radios' link rate)
-
current_mbpsobject nullableThe capacity Swift Fox uses now: the fixed figure, or the latest measurement
2 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable
-
-
measured_atdate-time nullableWhen current_mbps was measured; null when it's fixed
-
-
traffic_mbpsobject nullableLatest traffic across the link (Mbps)
2 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable
-
-
speedtest_enabledboolean -
ping_enabledboolean -
pingobject nullableLatest cross-link ping; null when ping monitoring is off or has no data
2 fields
-
latency_msnumber -
loss_pctnumber
-
-
alert_stateone of: "ok", "recovering", "info", "warning", "outage", "critical"ok (no issues), recovering (alerted recently, back to good), or the worst open issue's severity
-
Example
curl -H "Authorization: Bearer $SWIFTFOX_KEY" \
"https://api.swiftfox.net/v1/backhauls?isp=yourisp" Response (example data):
{
"count": 1,
"next_cursor": null,
"backhauls": [
{
"bhid": 12,
"name": "RB-HT",
"link_type": "wireless",
"ap_router": {
"infid": 101,
"name": "Core Router",
"site": {
"site_id": 3,
"code": "RB-CORE",
"name": "Riverbend Data Centre"
}
},
"su_router": {
"infid": 214,
"name": "Hilltop Router",
"site": {
"site_id": 7,
"code": "HT",
"name": "Hilltop Tower"
}
},
"ap_radio": {
"infid": 215,
"name": "RB-HT AP",
"site": {
"site_id": 3,
"code": "RB-CORE",
"name": "Riverbend Data Centre"
}
},
"su_radio": {
"infid": 216,
"name": "RB-HT SU",
"site": {
"site_id": 7,
"code": "HT",
"name": "Hilltop Tower"
}
},
"capacity": {
"source": "tcptest",
"current_mbps": {
"ap_to_su": 612.4,
"su_to_ap": 598.1
},
"measured_at": "2026-10-08T22:06:26Z"
},
"traffic_mbps": {
"ap_to_su": 534.2,
"su_to_ap": 38.2
},
"speedtest_enabled": true,
"ping_enabled": true,
"ping": {
"latency_ms": 1.12,
"loss_pct": 0
},
"alert_state": "warning"
}
]
} Get a backhaul
Everything about one backhaul: the router and radio at each end, how its capacity is set and each source's latest reading (the bandwidth test's, with the traffic during the test, and the radios'), the latest traffic, ping across the link, and open issues. A router end's speedtest_ip is the address bandwidth tests and link pings use on that end, not a management address; each end's ip is the device's own address. History: get_backhaul_history with series pings, traffic or capacity. Directions are named for the link's ends: ap_to_su is toward the SU end (down) and su_to_ap is from the SU end (up). The ap_router/ap_radio and su_router/su_radio objects say which devices those ends are.
Parameters
-
bhidinteger path requiredBackhaul id from
list_backhauls -
ispstring queryISP code from GET /isps. Optional when the key reaches exactly one ISP.
Response
-
bhidinteger -
namestring -
link_typestring -
ap_routerobject nullableThe router at the AP end
8 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
ipstring nullable -
hardware_typeobject nullableThe kind of device, which decides how Swift Fox collects from it
2 fields
-
idstringe.g. mikrotik, ubiquiti, cambium, snmp (any standard-SNMP device), generic
-
namestringAs the app shows it
-
-
modelstring nullable -
interfacestring nullableThe backhaul's interface on this router
-
speedtest_ipstring nullableThe address bandwidth tests and link pings target on this end; not a management address
-
-
su_routerobject nullableThe router at the SU end
8 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
ipstring nullable -
hardware_typeobject nullableThe kind of device, which decides how Swift Fox collects from it
2 fields
-
idstringe.g. mikrotik, ubiquiti, cambium, snmp (any standard-SNMP device), generic
-
namestringAs the app shows it
-
-
modelstring nullable -
interfacestring nullableThe backhaul's interface on this router
-
speedtest_ipstring nullableThe address bandwidth tests and link pings target on this end; not a management address
-
-
ap_radioobject nullableThe radio at the AP end
6 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
ipstring nullable -
hardware_typeobject nullableThe kind of device, which decides how Swift Fox collects from it
2 fields
-
idstringe.g. mikrotik, ubiquiti, cambium, snmp (any standard-SNMP device), generic
-
namestringAs the app shows it
-
-
modelstring nullable
-
-
su_radioobject nullableThe radio at the SU end
6 fields
-
infidinteger -
namestring -
siteobject nullableThe site
3 fields
-
site_idinteger -
codestringThe ISP's short site code
-
namestring
-
-
ipstring nullable -
hardware_typeobject nullableThe kind of device, which decides how Swift Fox collects from it
2 fields
-
idstringe.g. mikrotik, ubiquiti, cambium, snmp (any standard-SNMP device), generic
-
namestringAs the app shows it
-
-
modelstring nullable
-
-
capacityobject6 fields
-
sourcestringWhere the capacity figure comes from: fixed (set by hand), tcptest (bandwidth tests) or wireless (the radios' link rate)
-
current_mbpsobject nullableThe capacity Swift Fox uses now: the fixed figure, or the latest measurement
2 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable
-
-
measured_atdate-time nullableWhen current_mbps was measured; null when it's fixed
-
fixed_mbpsobject nullableThe figure set by hand (used when source is fixed)
2 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable
-
-
tcptestobject nullableThe latest bandwidth test
4 fields
-
ap_to_su_mbpsnumber nullable -
su_to_ap_mbpsnumber nullable -
used_during_test_mbpsobject nullableTraffic already on the link while the test ran
2 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable
-
-
atdate-time nullable
-
-
wirelessobject nullableThe radios' latest link rate
3 fields
-
ap_to_su_mbpsnumber nullable -
su_to_ap_mbpsnumber nullable -
as_ofdate-time nullable
-
-
-
traffic_mbpsobject nullableLatest traffic across the link (Mbps)
3 fields
-
ap_to_sunumber nullable -
su_to_apnumber nullable -
as_ofdate-time nullable
-
-
speedtest_enabledboolean -
speedtest_streamsinteger nullableTCP streams per bandwidth test
-
pingobject nullable3 fields
-
latency_msnumber -
loss_pctnumber nullable -
recent_avg_latency_msnumber
-
-
issuesarray of objectsEach item: 7 fields
-
metricstring -
detailsstring -
severityone of: "ok", "info", "warning", "outage", "critical"ok while recovering, otherwise info, warning, outage or critical
-
sincedate-time nullableWhen the issue started
-
statusone of: "active", "pending", "recovering" -
recovered_atdate-time nullablerecovering only: when the metric went back to good
-
resolves_atdate-time nullablerecovering only: when the issue clears if it stays good
-
Example
curl -H "Authorization: Bearer $SWIFTFOX_KEY" \
"https://api.swiftfox.net/v1/backhauls/42?isp=yourisp" Response (example data):
{
"bhid": 12,
"name": "RB-HT",
"link_type": "wireless",
"ap_router": {
"infid": 101,
"name": "Core Router",
"site": {
"site_id": 3,
"code": "RB-CORE",
"name": "Riverbend Data Centre"
},
"ip": "10.10.0.1",
"hardware_type": {
"id": "mikrotik",
"name": "Mikrotik"
},
"model": "CCR2116-12G-4S+",
"interface": "sfp1-HT",
"speedtest_ip": "10.10.250.1"
},
"su_router": {
"infid": 214,
"name": "Hilltop Router",
"site": {
"site_id": 7,
"code": "HT",
"name": "Hilltop Tower"
},
"ip": "10.10.7.1",
"hardware_type": {
"id": "mikrotik",
"name": "Mikrotik"
},
"model": "CCR2004-16G-2S+",
"interface": "sfp1-RB",
"speedtest_ip": "10.10.250.2"
},
"ap_radio": {
"infid": 215,
"name": "RB-HT AP",
"site": {
"site_id": 3,
"code": "RB-CORE",
"name": "Riverbend Data Centre"
},
"ip": "10.10.250.10",
"hardware_type": {
"id": "ubiquiti",
"name": "Ubiquiti"
},
"model": "airFiber 60 LR"
},
"su_radio": {
"infid": 216,
"name": "RB-HT SU",
"site": {
"site_id": 7,
"code": "HT",
"name": "Hilltop Tower"
},
"ip": "10.10.250.11",
"hardware_type": {
"id": "ubiquiti",
"name": "Ubiquiti"
},
"model": "airFiber 60 LR"
},
"capacity": {
"source": "tcptest",
"current_mbps": {
"ap_to_su": 612.4,
"su_to_ap": 598.1
},
"measured_at": "2026-10-08T22:06:26Z",
"fixed_mbps": null,
"tcptest": {
"ap_to_su_mbps": 612.4,
"su_to_ap_mbps": 598.1,
"used_during_test_mbps": {
"ap_to_su": 498.3,
"su_to_ap": 35.6
},
"at": "2026-10-08T22:06:25Z"
},
"wireless": {
"ap_to_su_mbps": 1850,
"su_to_ap_mbps": 1850,
"as_of": "2026-10-08T22:09:40Z"
}
},
"traffic_mbps": {
"ap_to_su": 534.2,
"su_to_ap": 38.2,
"as_of": "2026-10-08T22:09:45Z"
},
"speedtest_enabled": true,
"speedtest_streams": 3,
"ping": {
"latency_ms": 1.08,
"loss_pct": 0,
"recent_avg_latency_ms": 1.12
},
"issues": [
{
"metric": "Backhaul:Usage Percent Down",
"details": "Warning - 87.2% down used - 534 / 612 mbit",
"severity": "warning",
"since": "2026-10-08T21:55:03Z",
"status": "active",
"recovered_at": null,
"resolves_at": null
}
]
} Get a backhaul's health
The live monitored metrics for one device, backhaul or CPE: each metric's latest value and unit, its threshold state and severity, and any open issue. It's the same list as get_device's health, for backhauls and CPEs too. For devices, entries with has_history have history in get_device_history (series = the metric name). An issue's status is active (alerting now), pending (alerting, but still inside its grace period, so not alert-worthy yet) or recovering (back to good, but held open a while in case it comes back: recovered_at is when it went good, and resolves_at is when it clears if it stays good).
Parameters
-
bhidinteger path requiredinfid / bhid / cpeid
-
ispstring queryISP code from GET /isps. Optional when the key reaches exactly one ISP.
Response
Also available as CSV: add format=csv. Columns follow the field order below, with nested fields as dotted columns
(ap.name).
-
typestringdevice, backhaul or cpe; more types may be added
-
idinteger -
metricsarray of objectsEach item: 10 fields
-
metricstring -
substring optionalWhich value of a metric with several on one entity (a radio chain, a vulnerability)
-
descriptionstring optional -
valuenumber nullableLatest collected value
-
unitstring optional -
statestringThreshold state name for the value, e.g. Good, Warning, Down; Inactive = the metric has no thresholds set
-
severityone of: "ok", "info", "warning", "outage", "critical" nullableok, info, warning, outage or critical for the state's level; null when the metric has no thresholds
-
value_ttl_secondsinteger nullableSeconds until the value is considered stale; -1 = no expiry set
-
issueobject nullable6 fields
-
detailsstring -
severityone of: "ok", "info", "warning", "outage", "critical"ok while recovering, otherwise info, warning, outage or critical
-
sincedate-time nullableWhen the issue started
-
statusone of: "active", "pending", "recovering" -
recovered_atdate-time nullablerecovering only: when the metric went back to good
-
resolves_atdate-time nullablerecovering only: when the issue clears if it stays good
-
-
has_historyboolean optionalDevices: true when the metric's history is available (REST: /devices/{infid}/history/{metric})
-
Example
curl -H "Authorization: Bearer $SWIFTFOX_KEY" \
"https://api.swiftfox.net/v1/backhauls/42/health?isp=yourisp" Response (example data):
{
"type": "backhaul",
"id": 12,
"metrics": [
{
"metric": "Backhaul:Ping Loss",
"description": "The percentage packet loss from a high-res ping test between routers on each side of a backhaul",
"value": 0,
"unit": "%",
"state": "Good",
"severity": "ok",
"value_ttl_seconds": 604798,
"issue": null
},
{
"metric": "Backhaul:Usage Percent Down",
"description": "Percentage of the link's capacity in use toward the SU end",
"value": 87.2,
"unit": "%",
"state": "Warning",
"severity": "warning",
"value_ttl_seconds": 604798,
"issue": {
"details": "Warning - 87.2% down used - 534 / 612 mbit",
"severity": "warning",
"since": "2026-10-08T21:55:03Z",
"status": "active",
"recovered_at": null,
"resolves_at": null
}
}
]
} Get a backhaul's history
History for one device, backhaul or CPE, rolled up into time buckets (up to 200, or max_points up to 500), so long ranges stay small. Series: devices have pings, quality, signal, traffic (with interface), or a health metric name from get_device whose has_history is true; backhauls have pings, quality, traffic or capacity; CPEs have pings, traffic, plan, quality or signal. Each point has its bucket's start time (at), the values for the series and how many readings went into it (samples). pings: loss_avg_pct, loss_max_pct, latency_avg_ms, latency_min_ms, latency_max_ms. traffic, capacity and plan: avg and max Mbps per direction (an interface's in/out, a backhaul's ap_to_su/su_to_ap, a CPE's down/up). quality: quality_avg, quality_min (0 down to 6 perfect). signal: one point per radio chain per bucket. Health metrics: value_avg, value_min, value_max in unit. A missing bucket means nothing was recorded then.
Parameters
-
bhidinteger path requiredThe infid, bhid or cpeid
-
seriesstring path requiredWhich history; see the operation's description
-
ispstring queryISP code from GET /isps. Optional when the key reaches exactly one ISP.
-
sourceone of: "tcptest", "wireless" queryBackhaul capacity only: which measurement (default: the backhaul's own capacity source)
-
periodone of: "1hour", "4hours", "day", "week", "month", "year" queryLookback from now (default day). Use from/to instead for a past window
-
frominteger or string queryRange start: unix seconds or 'YYYY-MM-DD HH:MM:SS' UTC
-
tointeger or string queryRange end (default: now)
-
max_pointsinteger queryPoint budget (default 200, max 500); buckets are sized to stay under it
Response
Also available as CSV: add format=csv. Columns follow the field order below, with nested fields as dotted columns
(ap.name).
-
typestringdevice, backhaul or cpe; more types may be added
-
idinteger -
seriesstring -
interfacestring optionalDevice traffic: the interface
-
sourcestring optionalBackhaul capacity: the measurement shown
-
unitstring nullableHealth metrics: the value's unit. Other series carry the unit in their field names
-
fromdate-time -
todate-time -
bucket_secondsinteger -
point_countinteger -
pointsarray of objectsEach item: 2 fields
-
atdate-timeBucket start
-
chainstring optionalsignal only: the radio chain
-
Example
curl -H "Authorization: Bearer $SWIFTFOX_KEY" \
"https://api.swiftfox.net/v1/backhauls/42/history/series?isp=yourisp" Response (example data):
{
"type": "backhaul",
"id": 12,
"series": "pings",
"unit": null,
"from": "2026-10-08T21:00:00Z",
"to": "2026-10-08T22:00:00Z",
"bucket_seconds": 1800,
"point_count": 2,
"points": [
{
"at": "2026-10-08T21:00:00Z",
"loss_avg_pct": 0,
"loss_max_pct": 0,
"latency_avg_ms": 1.11,
"latency_min_ms": 0.93,
"latency_max_ms": 14.2,
"samples": 180
},
{
"at": "2026-10-08T21:30:00Z",
"loss_avg_pct": 0.4,
"loss_max_pct": 5,
"latency_avg_ms": 2.48,
"latency_min_ms": 0.94,
"latency_max_ms": 79.6,
"samples": 180
}
]
}