Skip to main content
An asset is a photo or video in your library, identified by a single asset ID. A version is a stored file belonging to that asset. Saving an edited photo as a version keeps the asset’s ID, album memberships, metadata, and face and person associations.

Original and derived versions

There are two categories of asset versions:
  • Original version: the file you first uploaded, preserved unchanged. Its kind is original.
  • Derived version: a new file produced by editing or processing the photo. It contains the finished image and parameters describing how it was produced. Its kind identifies the producer: edit for a client-rendered edit, or external:<service> for an external producer.
The current version is the one Gumnut shows when you browse the asset or request its image URLs. Before you save an edit, the original is current. After you save an edit, the derived version is current, and the original remains available to download or restore. Either an original or a derived version can be current. Gumnut keeps the original and at most one derived version per asset. Your first edit adds a derived version; saving another edit replaces that derived version with a new one. For example, if you crop a photo and later change the crop, Gumnut keeps the untouched upload and the latest cropped image. Each retained version has its own version ID and a position. Position 0 is the original, and the highest retained position is current. Version IDs identify specific stored files; positions can be reused after deletion or revert.
Replacing a derived version or reverting to the original permanently removes the current derived version. There is no undo history of earlier saved edits. Download a version first if you need to keep it separately.

How editing works

The Photos API stores finished image files as derived versions. Your application applies the crop, rotation, filter, or external editing operation and uploads the resulting image. Sending a recipe alone does not cause the Photos API to render it.

Prerequisites

Before starting, you need:
  • An API key scoped to the photo’s library. Reading versions requires read; adding or replacing versions requires write; deleting or reverting versions requires delete_permanently.
  • The photo’s asset ID and a fully rendered JPEG or PNG, with orientation and all edits already applied to its pixels. The file limit is 100 MiB, including any metadata the API adds during finalization.
  • curl to run the examples below. Set GUMNUT_API_KEY to your key and ASSET_ID to an existing asset ID.

Read the retained versions

The response is an array ordered by position: position 0 is the original upload, and the last entry is current. Each entry has an id, kind, params, and file details such as dimensions and size. include=variants adds URLs beyond the default thumbnail, including version_urls.original.url for that version’s exact stored bytes. Normal asset responses and asset_urls describe the current version. Even asset_urls.original refers to the current version’s stored file. To retrieve the untouched upload after an edit, use the position-0 version’s version_urls.original.url instead.

Add or replace a derived version

When the original is current, upload your edited image to add a derived version. This example assumes edited.jpg already contains the original rotated 90 degrees clockwise:
When a derived version is already current, set CURRENT_VERSION_ID to its id from the version list and replace it:
The multipart fields are file, kind, and params. params is a JSON object serialized as a string; the API stores it without interpreting its editing instructions. Use kind=edit with the compatible recipe below for geometric edits, or external:<service> with your producer’s own parameters for other derived versions. original is reserved for the uploaded source. For interoperability with Gumnut and Immich editors, the version-1 recipe has:
  • version: 1.
  • angle: 0, 90, 180, or 270 degrees clockwise.
  • mirror: a boolean for a horizontal flip after rotation.
  • Optional crop: integer x, y, width, and height in the base image’s display-oriented pixels, before rotation. Keep the rectangle within the image and use positive width and height. Omit crop when there is no crop.
Render in the order crop → rotate → horizontal mirror. A vertical flip is represented by a 180-degree rotation combined with a horizontal mirror. The finished image must match the recipe; the API does not check that match. The built-in editors refuse unfamiliar recipe fields rather than discard them on the next save. A version produced by an external service remains viewable and downloadable, but the built-in editors cannot reopen it as an adjustable geometric edit.

Restore the original

Set ORIGINAL_VERSION_ID to the id of the position-0 version, then revert:
Revert makes the addressed retained version current and permanently removes its descendants. Alternatively, DELETE /api/assets/{asset_id}/versions/{version_id} removes the current non-original version and restores its predecessor. You cannot delete the original through that endpoint.

Handle saves and conflicts

  • A new append or replacement returns 201. An exact retry with the same kind, parameters, and finalized bytes returns the current version with 200 and stores nothing new.
  • A stale append or replacement returns 409. Refetch the asset and versions before deciding whether to replace the latest edit; do not blindly overwrite someone else’s changes.
  • 422 means the body, metadata, or image is invalid. 507 means retaining the version would exceed storage capacity. Every retained version, including the original, counts toward storage use.
  • The API copies metadata from the original during finalization, so stored bytes can differ from your upload. Use the returned version’s checksum and URLs when tracking the saved result.
See the API Reference tab for endpoint schemas and error responses.

Faces on edited photos

Face boxes are anchored to the original photo’s pixel coordinates. While a derived version is current, Gumnut and the Immich adapter hide those boxes and reject new manual boxes rather than draw or save them in the wrong place. Your existing face and person associations remain attached to the asset. Restoring the original makes its face geometry available again.