Track the Resilience Program
The Resilience Program sorts your estate into resilience classes (critical, important, standard, or excluded) and tracks whether each class meets its commitments, so you can prove recovery class by class. This guide shows how to pull the current program state and its trend into your own reporting, commit a new program version, and read the supporting security and recovery metrics.
How the numbers fit together
Section titled “How the numbers fit together”For each class, the snapshot reports how many assets are promised, and splits them into four groups:
provable: meets every commitment.drift: falls short because of a coverage or configuration gap.drift_breakdowngives the cause and the covering policies.at_risk: has a finding that breaks the class’s durability floors.at_risk_breakdownhas the details.exceptions: every blocker is waived by an active governance override.
These always add up: provable + drift + at_risk + exceptions = promised.
If your tenant has recovery verdicts turned on and a recent evaluation, the snapshot also includes verdict_model (recovery_verdict_v1), verdict_evaluated_at, and verdict counts (proven_count, unproven_count, at_risk_count, proven_with_exceptions_count). These appear on totals, on each by_class entry, and in three breakdowns. Only read the verdict fields when verdict_model is present. For per-asset proof, see Recovery verdicts and evidence.
Read the current snapshot
Section titled “Read the current snapshot”If no program has been committed, program is null and every count is zero. That’s the normal state on first run, not an error. Reading the snapshot also records today’s trend point.
curl "https://acme.app.elastio.com/gateway/shared-services/v1/resilience-program/snapshot" \ -H "Authorization: Bearer $ELASTIO_TOKEN"import os, requests
BASE = "https://acme.app.elastio.com"HEADERS = {"Authorization": f"Bearer {os.environ['ELASTIO_TOKEN']}"}
resp = requests.get(f"{BASE}/gateway/shared-services/v1/resilience-program/snapshot", headers=HEADERS, timeout=60)resp.raise_for_status()snap = resp.json()
if snap.get("program") is None: print("No Resilience Program committed yet.")else: print("program version", snap["program"]["active_version"]) for cls, m in snap["by_class"].items(): print(f"{cls:10} promised={m['promised']} provable={m['provable']} drift={m['drift']} at_risk={m['at_risk']}") if "verdict_model" in snap: t = snap["totals"] print(f"proven {t['proven_count']} / unproven {t['unproven_count']} (evaluated {snap['verdict_evaluated_at']})")$Base = "https://acme.app.elastio.com"$Headers = @{ Authorization = "Bearer $env:ELASTIO_TOKEN" }$snap = Invoke-RestMethod -Uri "$Base/gateway/shared-services/v1/resilience-program/snapshot" -Headers $Headers$snap.totals$snap.by_class.criticalExample response (trimmed):
{ "as_of": "2026-10-12T11:30:00Z", "program": { "active_version": 4, "committed_at": "2026-09-30T16:00:00Z", "plan_id": "…", "plan_mode": "tags", "default_class": "standard", "inventory_source": "tags", "rules": [ { "tag_key": "tier", "tag_values": ["tier0"], "tier": "critical" } ], … }, "totals": { "promised": 480, "provable": 402, "drift": 51, "at_risk": 19, "exceptions": 8, "excluded": 37, "proven_count": 431, "unproven_count": 49, "at_risk_count": 19, "proven_with_exceptions_count": 8, … }, "by_class": { "critical": { "promised": 60, "provable": 52, "drift": 5, "at_risk": 2, "exceptions": 1, "excluded": 0, … }, "important": { … }, "standard": { … } }, "drift_breakdown": [ { "class": "critical", "cause": "…", "commitment_key": "…", "asset_count": 5, "asset_ids": ["…"], "covering_policy_ids": ["…"] } ], "at_risk_breakdown": [ … ], "verdict_model": "recovery_verdict_v1", "verdict_evaluated_at": "2026-10-12T11:00:00Z", "classify_estate": { … }}Chart the trend
Section titled “Chart the trend”/gateway/shared-services/v1/resilience-program/timeseriesResilience Program per-class trendfrom and to (YYYY-MM-DD, inclusive) are required. The response always has exactly three series: critical, important and standard. It also lists the program version changes in program_versions, so you can mark them on a chart. Points are daily, and granularity=hour is capped to daily rows. Verdict counts are null on points recorded before the verdict model existed.
curl "https://acme.app.elastio.com/gateway/shared-services/v1/resilience-program/timeseries?from=2026-09-01&to=2026-10-12" \ -H "Authorization: Bearer $ELASTIO_TOKEN"resp = requests.get( f"{BASE}/gateway/shared-services/v1/resilience-program/timeseries", headers=HEADERS, params={"from": "2026-09-01", "to": "2026-10-12"}, timeout=60,)resp.raise_for_status()trend = resp.json()for series in trend["series"]: for p in series["points"]: pct = 100 * p["provable"] / p["promised"] if p["promised"] else 0 print(series["class"], p["ts"][:10], f"{pct:.1f}% provable")$trend = Invoke-RestMethod -Uri "$Base/gateway/shared-services/v1/resilience-program/timeseries?from=2026-09-01&to=2026-10-12" -Headers $Headers$trend.series | ForEach-Object { $c = $_.class; $_.points | Select-Object @{ n = "class"; e = { $c } }, ts, promised, provable, drift, at_risk }Example response (trimmed):
{ "range": { "from": "2026-09-01", "to": "2026-10-12", "granularity": "day" }, "program_versions": [ { "version": 3, "active_from": "2026-08-14T10:00:00Z", "active_until": "2026-09-30T16:00:00Z" }, { "version": 4, "active_from": "2026-09-30T16:00:00Z", "active_until": null } ], "series": [ { "class": "critical", "points": [ { "ts": "2026-10-12T00:00:00Z", "promised": 60, "provable": 52, "drift": 5, "at_risk": 2, "proven_count": 56, "unproven_count": 4, "at_risk_count": 2, "proven_with_exceptions_count": 1, "verdict_model": "recovery_verdict_v1" } ] }, { "class": "important", "points": [ … ] }, { "class": "standard", "points": [ … ] } ]}Commit a new program version
Section titled “Commit a new program version”/gateway/shared-services/v1/resilience-program/commitCommit a new Resilience Program versionA commit deactivates the current version and makes a new one (the highest version number plus one) active. The body requires plan_id and policies, an array of v3 policy create bodies, one for each committed class scope (see Manage protection policies). Each policy is created, or updated if it was already created by a program commit. A same-name policy that wasn’t created by a commit causes a 409. Optional fields include rules (tag rules, evaluated in order), default_class, manual_overrides (asset ID → class), plan_mode, spine, node_assignments, tier_definitions and signed_off_by.
Only tenant admins can commit a program version; the gateway checks the role behind your token.
Because the body embeds full policy definitions, the examples read it from a file you maintain, commit.json:
curl -X POST "https://acme.app.elastio.com/gateway/shared-services/v1/resilience-program/commit" \ -H "Authorization: Bearer $ELASTIO_TOKEN" \ -H "Content-Type: application/json" \ --data @commit.jsonimport json
with open("commit.json") as f: body = json.load(f) # {"plan_id": "...", "policies": [...], "rules": [...], "default_class": "standard", ...}
resp = requests.post( f"{BASE}/gateway/shared-services/v1/resilience-program/commit", headers=HEADERS, json=body, timeout=120,)resp.raise_for_status()result = resp.json()print("now at version", result["program"]["active_version"])print("policies written:", [p["name"] for p in result["policies"]])$body = Get-Content -Raw -Path ./commit.json$result = Invoke-RestMethod -Method Post -Uri "$Base/gateway/shared-services/v1/resilience-program/commit" ` -Headers $Headers -ContentType "application/json" -Body $body$result.program.active_versionExample response (trimmed):
{ "program": { "active_version": 5, "committed_at": "2026-10-12T12:00:00Z", "plan_id": "…", "default_class": "standard", "rules": [ … ], … }, "policies": [ { "name": "…", "platform": "AWS", "status": "paused_until", "created_via_plan_id": "…", … } ]}AWS policies created by a commit start as paused_until with a future timestamp. A commit queues a recovery verdict re-evaluation but doesn’t wait for it, so verdict_evaluated_at on the next snapshot can be earlier than committed_at.
Other Resilience Program endpoints let you manage the program’s inputs: the classified estate (/estate, /estate/exposure), the inventory hierarchy (/spine, /spine/recommend, /tag-keys), per-node owner scope and RPO (/node-assignments), and governance overrides that pin a single asset to a class (/overrides).
Read security and recovery metrics
Section titled “Read security and recovery metrics”Security metrics summarise the estate on five measures: ransomware safety, encryption safety, storage health, recovery assurance and asset coverage. rpo_hours sets the RPO used for the recovery assurance numbers. platform takes a comma-separated list (aws, azure, on_prem, ibm). exclude_at_risk=true leaves at-risk assets out of the storage health and recovery assurance numbers.
curl "https://acme.app.elastio.com/gateway/api/v1/security-metrics?rpo_hours=24&platform=aws" \ -H "Authorization: Bearer $ELASTIO_TOKEN"resp = requests.get( f"{BASE}/gateway/api/v1/security-metrics", headers=HEADERS, params={"rpo_hours": 24, "platform": "aws"}, timeout=60,)resp.raise_for_status()ra = resp.json()["data"]["recovery_assurance"]print(f"{ra['assets_under_rpo']} assets within a 24h RPO, {ra['assets_outside_rpo']} outside")$metrics = (Invoke-RestMethod -Uri "$Base/gateway/api/v1/security-metrics?rpo_hours=24&platform=aws" -Headers $Headers).data$metrics.recovery_assuranceExample response:
{ "status": 200, "message": "…", "data": { "ransomware_safety": { "clean_assets": 512, "infected_assets": 3, "at_risk_assets": 9 }, "encryption_safety": { "encrypted_assets": 498, "unencrypted_assets": 4, "unscanned_assets": 22 }, "storage_health": { "unhealthy_storage": 2, "total_storage": 524 }, "recovery_assurance": { "assets_under_rpo": 471, "assets_outside_rpo": 53 }, "asset_coverage": { "covered_assets": 524, "uncovered_assets": 31, "platforms_covered": ["aws"] } }}To see how backup age is spread across your estate, call GET /gateway/api/v1/recovery-analytics/backup-age-percentiles (optional platform). It returns min, max and the top_20 through top_100 percentiles, all in seconds. POST /gateway/api/v1/trends-history returns finding and entropy-anomaly counts over time for a list of asset_ids, between start_at and end_at, at a given time_granularity.
All endpoints
Section titled “All endpoints”Resilience Program
20 operations in the reference →- DELETE
/gateway/shared-services/v1/resilience-programReset the Resilience Program back to its empty state - POST
/gateway/shared-services/v1/resilience-program/commitCommit a new Resilience Program version - GET
/gateway/shared-services/v1/resilience-program/estateThe classified estate, one asset per row - GET
/gateway/shared-services/v1/resilience-program/estate/exposureLive Business-exposure rollup by spine, account, or account group - GET
/gateway/shared-services/v1/resilience-program/node-assignmentsLive per-leaf owner-scope and RPO on the program tree - PUT
/gateway/shared-services/v1/resilience-program/node-assignmentsReplace the live per-leaf owner-scope and RPO bindings - GET
/gateway/shared-services/v1/resilience-program/overridesList governance overrides - POST
/gateway/shared-services/v1/resilience-program/overridesPin one asset to a resilience class - GET
/gateway/shared-services/v1/resilience-program/overrides/{override_id}Read one governance override - PATCH
/gateway/shared-services/v1/resilience-program/overrides/{override_id}Amend a governance override - DELETE
/gateway/shared-services/v1/resilience-program/overrides/{override_id}Retire a governance override - GET
/gateway/shared-services/v1/resilience-program/overrides/{override_id}/historyOne override's timeline - POST
/gateway/shared-services/v1/resilience-program/overrides/batch-deleteRetire many governance overrides - GET
/gateway/shared-services/v1/resilience-program/overrides/summaryGovernance-override counts - GET
/gateway/shared-services/v1/resilience-program/snapshotCurrent Resilience Program snapshot - GET
/gateway/shared-services/v1/resilience-program/spineThe tenant's Mapped Inventory hierarchy - PUT
/gateway/shared-services/v1/resilience-program/spineReplace the tenant's Mapped Inventory hierarchy - GET
/gateway/shared-services/v1/resilience-program/spine/recommendA proposed hierarchy, derived from the estate's own tags - GET
/gateway/shared-services/v1/resilience-program/tag-keysThe tag keys discovered on the estate - GET
/gateway/shared-services/v1/resilience-program/timeseriesResilience Program per-class trend