import requests
url = "https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute"
payload = {
"consent": "<string>",
"min_unattached_days": 1825
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({consent: '<string>', min_unattached_days: 1825})
};
fetch('https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"consent": "<string>",
"min_unattached_days": 1825
}
'{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"area": "security",
"kind": "<string>",
"subject": {},
"summary": "<string>",
"plan": {},
"evidence": {},
"status": "proposed",
"source": "<string>",
"created_by": "<string>",
"decided_by": "<string>",
"decided_at": "2023-11-07T05:31:56Z",
"decision_note": "<string>",
"operation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"receipt": {
"steps": [
{
"name": "<string>",
"outcome": "dispatched",
"detail": "<string>",
"evidence": {}
}
],
"claimed_at": "2023-11-07T05:31:56Z",
"executed_by": "<string>",
"dispatched_at": "2023-11-07T05:31:56Z",
"operation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"completed_at": "2023-11-07T05:31:56Z",
"execution_status": "<string>"
},
"dedupe_key": "<string>",
"executable": true,
"expected_monthly_cents": 123,
"baseline_monthly_cents": 123,
"baseline_window": {
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z"
},
"measured_monthly_cents": 123,
"measured_at": "2023-11-07T05:31:56Z",
"measurement_status": "not_applicable",
"verify_until": "2023-11-07T05:31:56Z",
"subject_cluster_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"verification_status": "not_applicable",
"verification_days": [
{
"day": 123,
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"state": "clear",
"cpu_p95_share": 123,
"memory_p95_share": 123,
"nodes": 123,
"reporting": 123,
"hottest_node": "<string>",
"reason": "<string>"
}
],
"rollback_of": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"parent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"run_after": "2023-11-07T05:31:56Z"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}Run an approved decision proposal
Dispatches the platform operation the proposal’s kind maps to (addon_upgrade rewrites the add-on’s chart version in its stack; off_hours_schedule creates the stop and start power schedules; waste_cleanup files the platform cleanup job of the cloud waste finding, which snapshots a stopped server before deleting it, releases an unassigned IP or idle load balancer, deletes an unattached volume, and sets a released persistent volume to Delete (after reading it live, and with clusters.write on its cluster), both only with the written consent this request carries; right_size_ladder files its next wave as a right_size child proposal, approved by the caller, and runs it, staying running until that wave’s verification concludes) as the caller, and records the receipt. The proposal is answered as the run left it: running with its operation_id when there is a platform execution to wait on, succeeded when the operation finished inside the call, or failed with the refusal on its receipt. Only an approved proposal runs, and only once: a concurrent execute finds it running. Gated on the area’s permission: billing.manage for cost, security.manage for security. The token stands in for the browser route’s CSRF double-submit. Bearer-PAT twin of the browser route of the same name under /org; the console’s session cookie is not accepted here and the browser route answers a token with a login redirect. A plan marked consent_required (at its top or under plan.parameters) runs only when the body carries consent “no_snapshot_acknowledged”; without it the answer is 422 with error_code consent_required and the proposal stays approved.
import requests
url = "https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute"
payload = {
"consent": "<string>",
"min_unattached_days": 1825
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({consent: '<string>', min_unattached_days: 1825})
};
fetch('https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://platform.ankra.app/api/v1/org/decisions/{decision_id}/execute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"consent": "<string>",
"min_unattached_days": 1825
}
'{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"area": "security",
"kind": "<string>",
"subject": {},
"summary": "<string>",
"plan": {},
"evidence": {},
"status": "proposed",
"source": "<string>",
"created_by": "<string>",
"decided_by": "<string>",
"decided_at": "2023-11-07T05:31:56Z",
"decision_note": "<string>",
"operation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"receipt": {
"steps": [
{
"name": "<string>",
"outcome": "dispatched",
"detail": "<string>",
"evidence": {}
}
],
"claimed_at": "2023-11-07T05:31:56Z",
"executed_by": "<string>",
"dispatched_at": "2023-11-07T05:31:56Z",
"operation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"completed_at": "2023-11-07T05:31:56Z",
"execution_status": "<string>"
},
"dedupe_key": "<string>",
"executable": true,
"expected_monthly_cents": 123,
"baseline_monthly_cents": 123,
"baseline_window": {
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z"
},
"measured_monthly_cents": 123,
"measured_at": "2023-11-07T05:31:56Z",
"measurement_status": "not_applicable",
"verify_until": "2023-11-07T05:31:56Z",
"subject_cluster_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"verification_status": "not_applicable",
"verification_days": [
{
"day": 123,
"from": "2023-11-07T05:31:56Z",
"to": "2023-11-07T05:31:56Z",
"state": "clear",
"cpu_p95_share": 123,
"memory_p95_share": 123,
"nodes": 123,
"reporting": 123,
"hottest_node": "<string>",
"reason": "<string>"
}
],
"rollback_of": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"parent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"run_after": "2023-11-07T05:31:56Z"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
PAT organisation override.
Path Parameters
Body
Response
The proposal as the run left it: running, succeeded or failed, with its receipt
One proposal of the decision ledger: what it is about, what the surface computed, where it stands, who decided, and what running it did.
security or cost; decides which permission approving and running it takes.
security, cost What the proposal does, e.g. addon_upgrade, image_rebuild, right_size, off_hours_schedule, waste_cleanup. Only kinds with a platform operation are executable.
Identity of what the proposal is about (finding_id, cluster_id, addon_name, waste_finding_id ...), one document per kind.
The steps the surface computed. plan.parameters is the machine half the executable kinds are called with: addon_upgrade takes {cluster_id, addon_name, chart_version}; off_hours_schedule takes {cluster_id, timezone, schedules: [{action, stop_mode, cron_expression}]}; waste_cleanup takes {waste_finding_id}.
proposed, approved, held, set_aside, running, succeeded, failed, superseded Which surface computed it (default "surface").
Ankra user id of whoever posted it.
Ankra user id of the last approve or set-aside.
The platform execution a run dispatched, to watch under /api/v1/org/executions.
The record of running a proposal: who ran it and when, the platform operation it became, the steps taken and how it ended.
Show child attributes
Show child attributes
Whether the platform has an operation for the kind, so a surface offers "run" only where running can work.
What the surface expected a cost proposal to save per month, in USD cents, recorded when it succeeded: plan.parameters.expected_monthly_cents, else evidence.expected_monthly_cents, each with an optional sibling expected_currency (ISO code, default usd) converted to USD. Zero, whatever it declared, for an off_hours_schedule whose every stop is a pause on a provider that bills a powered-off server at its full price (Hetzner, DigitalOcean, UpCloud): it saves no compute cost. Null when the proposal declared none, has not run, or is not a cost proposal; never zero for an unknown.
The subject cluster's run rate before the change: the mean monthly_cost_estimate_cents of its cost snapshots over baseline_window, in USD cents. Null until a measurement opens, or when no snapshot covered the window.
The 24 hours before the change was dispatched, [from, to); to is when the change ran.
Show child attributes
Show child attributes
What the change measurably saved per month, in USD cents: baseline_monthly_cents minus the cluster's 24h mean run rate seven days after the change. Negative when the run rate rose. Null unless measurement_status is measured.
When the measurement loop wrote its verdict (measured, unmeasured or reverted).
Where the measured outcome stands: not_applicable (not a cost proposal, not run, or no cluster to measure), pending (inside the seven-day verification window), measured, unmeasured_coverage_moved (the cluster was not priced the same way on both sides), unmeasured_no_snapshots (nothing to read on one side, or the cluster is no longer priced), reverted (the change was undone inside the window). The activity feed's measured / unmeasured / reverted event carries the reason.
not_applicable, pending, measured, unmeasured_coverage_moved, unmeasured_no_snapshots, reverted When the verification window closes: seven days after the change ran. The measurement loop settles the row once it has passed.
The cluster whose cost snapshots measure the change: plan.parameters.cluster_id, else subject.cluster_id.
Where a right-size's seven-day verification stands (ankra-cozgu.1.2): verifying until every day is judged, passed when all seven were clear, failed on the first day any node of the group ran p95 CPU over 60% or p95 memory over 70% of capacity (a right_size_rollback proposal is filed), unverified_no_metrics when no day tripped but at least one could not be read. not_applicable for every other proposal.
not_applicable, verifying, passed, failed, unverified_no_metrics The judged verification days in order, empty until the first 24h after the dispatch has been read.
Show child attributes
Show child attributes
On a right_size_rollback: the right-size it undoes, which reads measurement_status reverted once this rollback succeeds.
On a wave of a right-size ladder (a right_size proposal with source ladder): the right_size_ladder proposal it belongs to. Null for every other proposal.
The earliest time the cost autopilot may run a proposal it approved itself - the end of its pre-notice window, in which a person may hold it; null for a proposal a person approved, which a person runs.