DEVELOPER DOCS

REST API

Data Retention

On this page

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.

hoursLabel
2424 hours
4848 hours
1687 days
33614 days
72030 days
144060 days
216090 days
4320180 days
87601 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

HTTP
GET /v1/observ/orgs/{org}/workspaces/{ws}/retention

Auth: API key or JWT · Role: viewer

Response 200 — not schema-modelled

JSON
{ "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']}")

Preview a retention change

HTTP
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

FieldTypeRequiredDescription
hoursinteger✅Proposed retention period. Must be one of the nine allowed values.

The preview body takes only hours. It is a different model from the PUT body — do not send enabled or confirm_token here.

Response 200 — not schema-modelled

JSON
{
  "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")

Set retention

HTTP
PUT /v1/observ/orgs/{org}/workspaces/{ws}/retention

Auth: API key or JWT · Role: admin

Request body — RetentionIn

FieldTypeRequiredDefaultDescription
enabledboolean✅—Whether retention sweeping is active
hoursinteger | null➖nullRetention period. Must be one of the nine allowed values.
confirm_tokenstring | null➖nullToken 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"],
})

Errors

StatusCause
409confirm_token is stale — the underlying data changed. Re-run :preview.
422hours is not one of the nine allowed values, or confirm_token missing on a shortening change
403Role below admin

Lengthening retention needs no token. Shortening always does, because it destroys data.