REST API
Data Retention
Customer-settable retention, from 24 hours to 1 year. The sweeper deletes expired spans on an hourly bucketed schedule and is fail-closed: if it cannot confirm what it is about to delete, it deletes nothing.
Shortening retention is destructive and therefore uses a two-step preview-and-confirm flow.
Allowed periods
hours is an allow-list, not a free integer. Only these nine values are
accepted; anything else is rejected. That is deliberate — a free-form field is
how a fat-fingered 1 erases a year of telemetry, and there is no undo.
hours | Label |
|---|---|
24 | 24 hours |
48 | 48 hours |
168 | 7 days |
336 | 14 days |
720 | 30 days |
1440 | 60 days |
2160 | 90 days |
4320 | 180 days |
8760 | 1 year |
Below 48 hours, the daily roll-ups (drift, correlation, savings) run less often than data expires, so those panels thin out. The choice is not blocked — it is labelled. Surface that warning in your UI when a user selects
24.
Get retention
GET /v1/observ/orgs/{org}/workspaces/{ws}/retention
Auth: API key or JWT · Role: viewer
Response 200 — not schema-modelled
{ "enabled": true, "hours": 720, "effective_hours": 720, "updated_at": "2026-08-08T10:00:00Z" }
Examples
r = evigauge.get("/v1/observ/orgs/{org}/workspaces/{ws}/retention")
print(f"retention: {r['hours']}h ({r['hours'] // 24}d), enabled={r['enabled']}")
const r = await evigauge.get("/v1/observ/orgs/{org}/workspaces/{ws}/retention");
console.log(`retention: ${r.hours}h (${Math.floor(r.hours / 24)}d), enabled=${r.enabled}`);
Preview a retention change
POST /v1/observ/orgs/{org}/workspaces/{ws}/retention:preview
Reports how much data a proposed period would delete, and returns a
confirm_token you must pass to the PUT. Read-only — nothing is deleted.
Auth: API key or JWT · Role: admin
Request body — RetentionPreviewIn
| Field | Type | Required | Description |
|---|---|---|---|
hours | integer | ✅ | Proposed retention period. Must be one of the nine allowed values. |
The preview body takes only
hours. It is a different model from thePUTbody — do not sendenabledorconfirm_tokenhere.
Response 200 — not schema-modelled
{
"hours": 168,
"spans_to_delete": 4820113,
"traces_affected": 118402,
"oldest_deleted": "2026-07-02T00:00:00Z",
"confirm_token": "rtc_01J8XYZ..."
}
Examples
prev = evigauge.post("/v1/observ/orgs/{org}/workspaces/{ws}/retention:preview",
json={"hours": 168})
print(f"Would delete {prev['spans_to_delete']:,} spans "
f"across {prev['traces_affected']:,} traces")
const prev = await evigauge.post(
"/v1/observ/orgs/{org}/workspaces/{ws}/retention:preview", { hours: 168 });
console.log(`Would delete ${prev.spans_to_delete} spans across ${prev.traces_affected} traces`);
Set retention
PUT /v1/observ/orgs/{org}/workspaces/{ws}/retention
Auth: API key or JWT · Role: admin
Request body — RetentionIn
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | boolean | ✅ | — | Whether retention sweeping is active |
hours | integer | null | ➖ | null | Retention period. Must be one of the nine allowed values. |
confirm_token | string | null | ➖ | null | Token from :preview. Required when the change shortens retention. |
Examples
# Shortening retention is destructive → preview first, then confirm.
prev = evigauge.post("/v1/observ/orgs/{org}/workspaces/{ws}/retention:preview",
json={"hours": 168})
if prev["spans_to_delete"] > 0:
print(f"About to delete {prev['spans_to_delete']:,} spans.")
evigauge.put("/v1/observ/orgs/{org}/workspaces/{ws}/retention", json={
"enabled": True,
"hours": 168,
"confirm_token": prev["confirm_token"],
})
// Shortening retention is destructive → preview first, then confirm.
const prev = await evigauge.post(
"/v1/observ/orgs/{org}/workspaces/{ws}/retention:preview", { hours: 168 });
if (prev.spans_to_delete > 0) {
console.log(`About to delete ${prev.spans_to_delete} spans.`);
}
await evigauge.put("/v1/observ/orgs/{org}/workspaces/{ws}/retention", {
enabled: true,
hours: 168,
confirm_token: prev.confirm_token,
});
Errors
| Status | Cause |
|---|---|
409 | confirm_token is stale — the underlying data changed. Re-run :preview. |
422 | hours is not one of the nine allowed values, or confirm_token missing on a shortening change |
403 | Role below admin |
Lengthening retention needs no token. Shortening always does, because it destroys data.