> For AI agents: the documentation index is at https://docs.gethandup.dev/llms.txt. Append .md to any page URL (without the trailing slash) for Markdown, for example https://docs.gethandup.dev/cli.md.

# retention_put

`PUT /v1/storage/retention`

Set history.keep_days and/or history.files_keep_days: saved to the daemon's config file and applied without a restart. A shorter period starts a cleanup at once. Local, and decide scope on paired devices.

## Request Body required

Media type: `application/json`

`object`

`PUT /v1/storage/retention`: the "keep for" control. Omitted fields keep
their value; 0 keeps forever (files: as long as their request).

- **keep_days**: `integer | null` format: int32, >= 0
- **files_keep_days**: `integer | null` format: int32, >= 0

## Responses

### 200

Media type: `application/json`

`object`

- **retention** (required): `object`

  Retention for resolved requests (decision history). The daemon prunes at
  start and hourly; 0 disables a cap. Pending requests are never pruned.

  - **keep_days**: `integer` format: int32, default: `90`, >= 0

    Delete resolved requests older than this many days (0 = no age cap).

  - **max_requests**: `integer` format: int32, default: `2000`, >= 0

    Keep at most this many resolved requests (0 = no count cap).

  - **max_bytes**: `integer` format: int64, default: `0`, >= 0

    Best-effort live database/WAL/blob byte cap, excluding free database pages (0 = unlimited).

  - **files_keep_days**: `integer` format: int32, default: `0`, >= 0

    Remove files belonging only to resolutions older than N days (0 = request lifetime).

- **job**: `object | null`

  The cleanup that applies a shorter period now; null when nothing
  shrank or another cleanup is running (hourly retention then applies it).

  - **id** (required): `string`
  - **target** (required): `string`

    What a cleanup removes.

    Allowed values: `history` `files`

  - **older_than_days** (required): `integer` format: int32, >= 0

    0 = every resolved request.

  - **keep_newest**: `integer` format: int32, >= 0

    Newest resolved requests kept; 0 = no count limit.

  - **state** (required): `string`

    Allowed values: `running` `done` `cancelled` `failed`

  - **total** (required): `integer` format: int64, >= 0

    Items to process, counted at the start: requests (history) or files (files).

  - **done** (required): `integer` format: int64, >= 0

    Items processed so far.

  - **requests_deleted** (required): `integer` format: int64, >= 0
  - **files_deleted** (required): `integer` format: int64, >= 0
  - **bytes_freed** (required): `integer` format: int64, >= 0

    Bytes freed: removed files plus database pages released by deleted rows.

  - **compacting** (required): `boolean`

    Returning freed database pages to the filesystem (incremental vacuum).

  - **started_at** (required): `integer` format: int64, >= 0

    Unix milliseconds.

  - **finished_at**: `integer | null` format: int64, >= 0
  - **error**: `string | null`

    Set when `state` is `failed`.

### 400

Out of range, or the daemon has no config file

### 403

Remote device without decide scope
