> ## Documentation Index
> Fetch the complete documentation index at: https://docs.everabyte.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Retention and versions

> How immutability, file versions, trash, and restore interact.

Everabyte protects data with three related but distinct mechanisms. Confusing them leads to integrations that fail in production.

| Mechanism | What it does | Who controls it |
| - | - | - |
| Retention | Makes content immutable until a date | Dashboard or file update |
| Legal hold | Preserves content for litigation | Dashboard / compliance admin |
| Trash | Delays permanent deletion | API (`trash=soft`) and dashboard |
| Versions | Preserves prior content of a file | API uploads and version endpoints |

## Retention values

File-level retention accepts:

```text theme={null}
30d, 45d, 90d, 120d, 180d, 1Y, 2Y, 3Y, 5Y
```

Bucket-level retention accepts the same set **except** `30d` and `45d`. A bucket-wide write-once (WORM) policy shorter than 90 days is not offered.

Retention is expressed as a period value, and the backend stores an expiry. Once active, the content is locked until that expiry.

## Retention rules that affect your integration

> **A file with active retention cannot be changed or deleted**
>
> Renaming, changing visibility, changing retention again, or deleting returns an error. Do not offer these actions in your UI when `isRetention` is true.

> **Bucket retention overrides per-file behavior**
>
> When a bucket has active retention, per-file retention changes are rejected, and files in that bucket cannot be soft- or hard-deleted even if they have no individual retention.

> **Retention cannot be shortened or cleared once active**
>
> The lock is one-way until expiry. Plan retention at upload time rather than treating it as a toggle.

> **Legal hold blocks deletion independently**
>
> A legal hold can block deletion even when retention has expired. Legal hold is managed outside the public API.

## Versions

When a file is uploaded again with the same name and extension in the same folder scope, the backend can create a new version instead of a separate file. The upload response then has `isUpdate: true`.

Use `GET /files/{fileId}/versions` to list versions. Each entry includes the version identifier, size, creation time, action, author metadata when resolvable, and an `isCurrent` flag. The current live object is synthesized into the list even when it has no separate version row.

### The nested version response

Version endpoints wrap a service result inside the normal controller envelope. The list response looks like this:

```json theme={null}
{
  "status": 200,
  "message": "Versions retrieved",
  "data": {
    "status": 200,
    "message": "Versions retrieved",
    "data": [
      {
        "id": "b3f1f8a4-2c0e-4f6a-9a11-8b7c6d5e4f30",
        "fileId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "versionId": "3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY+MTRCxf3vjVBH40Nr8X8gdRQBpUMLUo",
        "sizeByte": 482133,
        "createdAt": "2026-10-21T14:03:11.000Z",
        "isDeleted": false,
        "name": "report",
        "extFile": "pdf",
        "action": "upload",
        "isCurrent": true
      }
    ],
    "maxVersions": 10
  }
}
```

Read `data.data` for the array. The inner `status` and `message` duplicate the outer values. This is current behavior, not a documentation error.

The same nesting applies to version restore, version delete, and file restore-from-trash.

### Version operations

| Operation | Endpoint | Behavior |
| - | - | - |
| List | `GET /files/{fileId}/versions` | Returns versions plus `maxVersions` |
| Restore | `POST /files/{fileId}/versions/{versionId}/restore` | Makes an older version current |
| Delete | `DELETE /files/{fileId}/versions/{versionId}` | Permanently removes one archived version |
| Download | `GET /files/{fileId}/versions/{versionId}/download` | Streams that version's bytes |

Deleting the **current** version through the version endpoint is rejected. Delete the file itself instead. A restore of the already-current version is also rejected as a no-op.

Restoring and deleting versions require write or delete capability. Downloading a version requires read capability.

## Trash and restore

`DELETE /files/delete/{fileId}?trash=soft` marks the file deleted and starts the display window. `trash=hard` permanently removes it.

Restore a soft-deleted file with:

```bash theme={null}
curl -X POST "https://api.everabyte.io/api/files/FILE_ID/restore" \
  -H "X-Public-Key: $EVB_PUBLIC_KEY" \
  -H "X-Secret-Key: $EVB_SECRET_KEY"
```

Restoring a file that is not in trash returns `400`. Restoring after the display window returns `410`. The response payload is nested the same way as version operations.

Folders have their own trash endpoints: `DELETE /folders/delete/{folderId}` and `POST /folders/restore-from-trash/{folderId}`.

> [!WARNING]
>
> Hard deletion is irreversible. Retention and legal hold can block it, but once it succeeds there is no restore path.

## Recommended integration pattern

1. Read `isRetention` and `retentionPeriod` before showing destructive actions.
2. Treat `trash=soft` as the default delete.
3. Require an explicit, user-confirmed action for `trash=hard`.
4. Poll or refresh lists after mutations; do not assume local state matches server state.
5. Handle `410` as "too late to restore", not as a transient error.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.