API Migration: v1 → v2
The MANRS API has moved from api.manrs.org to observatory.manrs.org. V1 routes are still accessible at observatory.manrs.org/api for continuity, but are deprecated and will be removed in a future release.
All users are encouraged to update their base URL and migrate to the v2 routes at observatory.manrs.org/api/v2. This guide covers every v1 route, its v2 equivalent, and what has changed in the response.
V1 routes are intentionally excluded from the API reference docs. Only v2 routes are documented going forward.
Breaking Changes
These changes affect every request.
| Change | V1 | V2 |
|---|---|---|
| Host | api.manrs.org | observatory.manrs.org |
| Base path | https://api.manrs.org/... | https://observatory.manrs.org/api/v2/... |
| Month format | ?month=202501 (YYYYMM) | ?month=2025-01-01T00:00:00Z (RFC3339) |
| Field naming | snake_case (anti_spoofing, member_since) | camelCase (antiSpoofing, memberSince) |
| Participant ID | id: 42 (legacy integer) | id: "a3ffc8ac-…" (UUID string) |
| CSV export | Supported on net-ops and CDN conformance | Not supported |
| Auth | Authorization: Bearer <key> | Unchanged |
V1 parsed months as YYYYMM (e.g. 202501). V2 accepts a full RFC3339 timestamp. To request January 2025, pass ?month=2025-01-01T00:00:00Z. Only the year and month are used; the day and time components are ignored.
ASN Routes
List approved ASNs
GET /api/asns → GET /api/v2/asns
No change in behaviour or response shape. Returns { asns: [uint32] }.
List all ASN info
GET /api/asns/info → GET /api/v2/ases
V1 returned a slim { number, name, status, manrs, rir_status } shape per entry. V2 returns the full AS model. The combined rir_status field (sourced from NRO data) is no longer merged into the AS response — NRO allocation status is a separate concern. The manrs boolean flag is also absent in v2; use the participant directory instead.
Get single ASN info
GET /api/asns/info/{asID} → GET /api/v2/ases/{asn}
Same change as above — richer model, no rir_status or manrs boolean.
Get ASN conformance
GET /api/asns/conformance/{asn}?month=YYYYMM
→
GET /api/v2/scores/detailed?asn={asn}&month=2025-01-01T00:00:00Z
V1 returned category scores as integer percentages (0–100) plus trend directions. V2 /scores/detailed is a superset: category scores remain 0–100 integers in score.scores, per-action scores (M1–M9) are raw 0–1 floats in score.actions, and the full routing breakdown, ROV samples, and six-month history are included.
| V1 field | V2 equivalent |
|---|---|
scores.filtering.value | score.scores.filtering.value (0–100 int) |
scores.anti_spoofing.value | score.scores.antiSpoofing.value (0–100 int) |
scores.coordination.value | score.scores.coordination.value (0–100 int) |
scores.routing_information_irr | score.scores.routingInformationIRR |
scores.routing_information_rpki | score.scores.routingInformationRPKI |
scores.*.trend | score.trend.* (separate trend object) |
incidents.m1 | score.incidents.routeLeaks |
incidents.m2 | score.incidents.routeMisoriginations |
incidents.m1c | score.incidents.routeLeaksAccomplice |
incidents.m2c | score.incidents.routeMisoriginationsAccomplice |
incidents.total | score.incidents.total |
manrs_status | Call GET /api/v2/participants?asn={asn}, read participants[0].status |
Get ASN scores (all ASNs)
GET /api/asns/scores?month=YYYYMM
→
GET /api/v2/scores?month=2025-01-01T00:00:00Z
V1 returned raw 0–1 floats for category scores and used offset-based pagination (page, limit, total, pages). V2 returns 0–100 integers in scores[].scores and delivers the full result set without offset pagination.
| V1 field | V2 equivalent |
|---|---|
data | scores |
data[].scores.* | scores[].scores.* (values now 0–100 int) |
data[].scores.filtering.value (raw float) | scores[].scores.filtering.value (0–100 int) |
data[].metrics.m1 | scores[].actions.m1 (raw float) |
data[].metrics.m2 | scores[].actions.m2Grip (raw float) |
data[].metrics.m3 | scores[].actions.m3 (raw float) |
data[].metrics.m7irr | scores[].actions.m7Irr (raw float) |
data[].metrics.m7rpki | scores[].actions.m7Rpki (raw float) |
page, limit, total, pages | No offset pagination — full result returned |
Filter the listing with asns, economies, region (RIR macro-region: africa, asia-pacific, north-america, latin-america, europe), and/or participantIDs.
Get scores for a specific ASN
GET /api/asns/scores/{asn}?month=YYYYMM
→
GET /api/v2/scores/detailed?asn={asn}&month=2025-01-01T00:00:00Z
V1 returned raw 0–1 floats in both scores.* and metrics.*. V2 /scores/detailed uses 0–100 integers in score.scores and raw 0–1 floats in score.actions.
The metrics key in V1 contained normalized per-action scores. In V2 those move to score.actions with renamed keys:
V1 metrics | V2 score.actions |
|---|---|
m1 | m1 |
m1c | m1c |
m2 | m2Grip |
m2c | m2cGrip |
m3–m4c_admin | m3–m4cAdmin |
m5 | m5 |
m7irr | m7Irr |
m7rpki | m7Rpki |
m7rpkin | m7RpkiN |
m7conflict | m7Conflict |
m8 | m8 |
m9 | m9 |
New fields present only in V2: score.routing (full IRR/RPKI prefix breakdown), score.rovSamples, score.contactInfoValid, score.trend, and the six-month history array.
Conformance Routes
V1 returned a combined payload of participant directory data with pre-aggregated conformance scores in a single call. V2 unifies all programmes behind a single endpoint, filtered by type.
V1 used a legacy integer id (e.g. "id": 42). V2 uses a UUID string (e.g. "id": "a3ffc8ac-0ea1-4d35-9e2a-906e34341191"). Update any stored ID references accordingly.
Network Operators
GET /api/conformance/net-ops
→
GET /api/v2/scores/conformance?type=netops
V1 supported Accept: text/csv for CSV output. V2 returns JSON only.
Key field renames between v1 and v2 net-ops rows:
| V1 field | V2 field |
|---|---|
id (int64) | id (UUID string) |
areas_served | regions |
ASNs | asns |
member_since | memberSince |
anti_spoofing | antiSpoofing |
routing_information | routingInformation |
score_irr | scoreIRR |
score_rpki | scoreRPKI |
measurement_date | measurementDate (top-level response field, present only when type=netops) |
IXPs
GET /api/conformance/ixps
→
GET /api/v2/scores/conformance?type=ixp
Key field renames between v1 and v2 IXP rows:
| V1 field | V2 field |
|---|---|
id (int64) | id (UUID string) |
areas_served | regions |
member_since | memberSince |
promote_routing | promoteRouting |
promote_isp_actions | promoteISPActions |
promote_display_manrs | promoteDisplayMANRS |
promote_incentives | promoteIncentives |
V1 returned { prevent, promote_routing, promote_isp_actions } derived from participant status. V2 maps directly:
| V1 value | V2 status |
|---|---|
conformant | conformant |
pending | pending |
non-conformant | non-conformant |
IXP info
GET /api/ixps/info
→
GET /api/v2/participants?type=ixp&status=approved
V1 returned { name, abbreviation, ids: [{ ixf_id, peering_db_id }] }. V2 returns the full Participant model which includes name, abbreviation, ixfID, and peeringDBID directly on each participant record.
CDNs
GET /api/conformance/cdns
→
GET /api/v2/scores/conformance?type=cdn
V1 supported Accept: text/csv for CSV output. V2 returns JSON only.
Key field renames between v1 and v2 CDN rows:
| V1 field | V2 field |
|---|---|
id (int64) | id (UUID string) |
ASNs | asns |
member_since | memberSince |
anti_spoofing | antiSpoofing |
routing_information | routingInformation |
routing_information.IRR | routingInformation.irr |
routing_information.RPKI | routingInformation.rpki |
filtering.ROV | filtering.rov |
filtering.AS-SET | filtering.asSet |
MANRS_adoption | manrsAdoption |
Vendors
GET /api/conformance/vendors
→
GET /api/v2/scores/conformance?type=vendor
Key field renames between v1 and v2 vendor rows:
| V1 field | V2 field |
|---|---|
id (int64) | id (UUID string) |
member_since | memberSince |
solution_filtering | solutionFiltering |
solution_anti_spoofing | solutionAntiSpoofing |
solution_filtering_ixp | solutionFilteringIXP |
solution_protect_l2 | solutionProtectL2 |
technical_resources | technicalResources |
hands_on | handsOn |
V1 values (implemented, planned, not implemented) are unchanged in V2.
Country / Economy Routes
GET /api/countries/scores/{economy}?month=YYYYMM
→
GET /api/v2/scores/summary?economies={economy}&month=2025-01-01T00:00:00Z (aggregate readiness + statistics)
GET /api/v2/scores?economies={economy}&month=2025-01-01T00:00:00Z (per-ASN rows)
V1 required authentication (apiKey). The /scores/summary endpoint is public in V2.
For the rolled-up economy aggregate, use /scores/summary with economies set to one or more ISO-2 codes (it also accepts a region slug for UN regions / sub-regions / RIRs). It returns the readiness key figures — each with its mean value and a per-severity breakdown carrying both count and percentage — plus the underlying incidents, culprits, irr, rpki, and rov statistics. For the individual ASN rows (each with its category/action scores and incident counts), use /scores?economies=.
ROA Routes
ROA history (raw ROAs)
GET /api/roa-history?asn=&tal=&sourceDate=
→
GET /api/v2/roas?asn=&source=&sourceDate=
Same underlying data. Both use cursor-based pagination via pageToken. The tal query parameter is renamed to source in V2. Note that the V1 display name RIPE maps to the canonical source name RIPENCC in V2 — pass source=RIPENCC when querying for RIPE NCC ROAs.
All ROA validation stats (paged)
GET /api/roas?page=&limit=
→
GET /api/v2/roa-stats
Same underlying data — daily RPKI validation outcomes per prefix/ASN pair (valid, unknown, invalidASN, invalidLength). Key differences:
- Pagination: V1 used offset-based
?page=&limit=. V2 uses cursor-based pagination viapageToken. - IPv4/IPv6 split: V1 returned separate
v4andv6arrays, each containing nested{ asn: {number, name}, country: {name, code}, roa: {prefix, state} }objects. V2 returns a flatstats[]array — filter byipVersionif a split is needed. - State casing: V1 used
invalid_asn/invalid_length(snake_case). V2 usesinvalidASN/invalidLength(camelCase). - Endpoint supports the same filters:
asn,sourceDate, and IP prefix.
ROA validation stats by ASN
GET /api/roas/asn/{asn} → GET /api/v2/roa-stats?asn={asn}
V1 returned per-prefix validation records split into v4/v6 arrays. V2 returns the same flat per-prefix records via /roa-stats?asn={asn} with an ipVersion field on each record.
GET /api/v2/stats/roas?asn={asn} is a different endpoint that returns aggregate counts (total valid/unknown/invalid), not individual prefix records. Use /roa-stats?asn={asn} for the per-prefix data equivalent to the v1 route.
ROA validation stats by country
GET /api/roas/country/{country} → GET /api/v2/roa-stats?economy={country}
V1 returned per-prefix records split into v4/v6 arrays for all ASNs in the country. V2 returns the same flat per-prefix records via /roa-stats?economy={country}.
GET /api/v2/stats/roas?economy={country} returns aggregate counts for the scope, not individual prefix records.