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.