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

# Versions

> Upload, download, and manage entity versions

Every entity is versioned. Each push creates a new version with a timestamp identifier and a source hash for deduplication. One version is marked as active — this is what gets installed or deployed by default.

## Upload version

Version upload is a two-step process: request an upload URL, then confirm the upload after the file is stored.

### Step 1: Get upload URL

```bash theme={null}
POST /api/entities/{entityId}/versions/upload-url
```

| Parameter         | Type | Required         | Description                                                                                                |
| ----------------- | ---- | ---------------- | ---------------------------------------------------------------------------------------------------------- |
| `version`         | body | Yes              | Version string (e.g., `2024.06.10-153042`)                                                                 |
| `source_hash`     | body | Yes              | SHA hash of the source code                                                                                |
| `base_version_id` | body | After first push | The version this push builds on. Must be the entity's current tip; see [Push protection](#push-protection) |
| `force`           | body | No               | Create version even if source hash already exists (does not bypass push protection)                        |

If the source hash matches an existing version (and `force` is false), the API returns the existing version info instead of generating an upload URL. This prevents duplicate uploads.

Returns signed upload URLs for the main package and lockfile.

**Authentication:** Entity access + publisher role required.

### Step 2: Confirm upload

```bash theme={null}
POST /api/entities/{entityId}/versions/confirm
```

| Parameter              | Type | Required         | Description                                                                     |
| ---------------------- | ---- | ---------------- | ------------------------------------------------------------------------------- |
| `storage_path`         | body | Yes              | Path where the package was uploaded                                             |
| `version`              | body | Yes              | Version string                                                                  |
| `source_hash`          | body | Yes              | Source code hash                                                                |
| `file_size_bytes`      | body | Yes              | Package file size                                                               |
| `base_version_id`      | body | After first push | Same as step 1: must be the entity's current tip                                |
| `service_dependencies` | body | No               | Array of required service slugs                                                 |
| `package_json`         | body | No               | Package.json contents                                                           |
| `package_lock_path`    | body | No               | Lockfile storage path                                                           |
| `set_as_active`        | body | No               | Set this version as active immediately                                          |
| `force`                | body | No               | Create even if the source hash already exists (does not bypass push protection) |

Creates the version record in the database. If `set_as_active` is true, this version becomes the active version.

**Authentication:** Entity access + publisher role required.

## Push protection

A push may only extend the **current tip**: the most recently created version. Both upload endpoints validate `base_version_id` against it, and reject the push with `409` when the value is stale, or when it's omitted while the entity already has versions:

```json theme={null}
{
  "error": "A newer version was published after your base version",
  "code": "STALE_BASE",
  "latest_version": {
    "id": "…",
    "version": "2026.07.08-101502",
    "published_by": "…",
    "created_at": "2026-07-08T10:15:02Z"
  }
}
```

`latest_version` is the current tip to reconcile against before retrying.

* The first push to an entity needs no `base_version_id`.
* `force` does not bypass this check; it only bypasses source-hash deduplication.
* On confirm, deduplication runs first, so re-confirming a version you already published returns `200` with the existing version rather than `409`.

## Download version

```bash theme={null}
GET /api/entities/{entityId}/versions/{versionId}/download
```

Returns a signed download URL for the version package. Access is granted to:

* Entity publishers
* Users the entity is shared with
* Organization members if the entity is published to the org store
* Any authenticated user if the entity is in a public store

**Authentication:** Entity access required (multiple access paths).

## Get active version

```bash theme={null}
GET /api/entities/{entityId}/active-version
```

Returns the currently active version details.

**Authentication:** Entity access required.

## Set active version

```bash theme={null}
PUT /api/entities/{entityId}/active-version
```

| Parameter   | Type | Required | Description                 |
| ----------- | ---- | -------- | --------------------------- |
| `versionId` | body | Yes      | Version ID to set as active |

The active version is what gets installed by default from stores or shares, and what gets deployed unless a specific version is specified.

**Authentication:** Entity access + publisher role required.

## Delete version

```bash theme={null}
DELETE /api/entities/{entityId}/versions/{versionId}
```

Deletes the version record and removes the package from storage. Cannot delete the active version — set a different active version first.

**Authentication:** Entity access + publisher role required.

## Version identifiers

Versions use a timestamp-based format: `YYYY.MM.DD-HHMMSS` (e.g., `2024.06.10-153042`). This provides chronological ordering without semantic versioning complexity.

The `source_hash` field enables deduplication — if you push the same source code twice, the platform recognizes the duplicate and returns the existing version rather than creating a new one.
