Immich server compatibility¶
Immich 3.0 reworked several of the API endpoints pymmich relies on. pymmich speaks both dialects: it asks the server for its version and picks the matching API variant automatically, so the same pymmich release works against old and new servers alike.
Supported versions¶
| Immich server | API variant | Status |
|---|---|---|
| 2.7 – 2.x | v2 |
Supported |
| 3.0, 3.1 | v3 |
Supported |
| older than 2.7 | v2 |
Untested; may work |
Nothing needs to be configured for this. The same API key permissions apply to both generations — see API key permissions.
How the variant is detected¶
On the first command that touches a version-dependent endpoint,
pymmich issues a single GET /server/version request and derives the
variant from the reported major version: 2.x → v2, 3.x → v3.
- Lazy — no request is made until a version-dependent call is actually needed.
- Cached — the result is remembered for the lifetime of the client, i.e. one per command run, so a run costs at most one extra request.
- Unprivileged —
GET /server/versionis a public endpoint on both server generations and needs no API-key permission, so detection also works with a minimally scoped key.
Release candidates
Pre-release versions such as 3.0.0-rc.1 are treated like their
final release: only the major version decides which variant is
used.
What actually differs¶
| Area | Immich 2.x | Immich 3.x |
|---|---|---|
| Owned albums | GET /albums |
GET /albums?isOwned=true |
| Shared albums | GET /albums?shared=true |
GET /albums?isShared=true |
| All visible albums | GET /albums and GET /albums?shared=true, merged client-side |
GET /albums?isOwned=true and GET /albums, merged client-side |
| Album contents | GET /timeline/buckets + GET /timeline/bucket, then GET /assets/{id} per asset |
POST /search/metadata with an albumIds filter |
| Upload | POST /assets including the deviceId / deviceAssetId fields |
POST /assets without those fields (dropped in 3.0) |
| Album members | album owner is reported separately from albumUsers |
album owner appears in albumUsers with the role owner |
| Asset listings | metadata search returns timeline assets by default | default widened to everything but locked assets, so pymmich asks for timeline assets explicitly |
| Album contents scope | timeline + archived assets | additionally hidden assets, which pymmich filters out for parity |
Some of these are worth a sentence more:
- Which endpoint lists an album. On Immich 2.x,
POST /search/metadataforcibly scopes results to the caller's own assets, which would hide photos other members contributed to a shared album. pymmich therefore reads album contents through the timeline endpoints there. Immich 3.0 stopped applying that owner scope when analbumIdsfilter is given (it checks album read access instead), so on 3.x the stable search endpoint is used — fewer requests, and no reliance on internal endpoints. - Album members. Because Immich 3.x lists the owner as an
albumUsersentry,unshareexplicitly ignores that entry: the owner of an album is never treated as a user the album was shared with, and can never be unshared by accident. - Asset listings. Immich 2.x restricted metadata searches to
timeline assets; Immich 3.0 changed the default to "everything
except locked assets", which would have made
listand filename lookups start reporting archived and hidden assets on a 3.x server only. pymmich sends the timeline filter explicitly so listings look the same either way. - What an album listing contains. It is deliberately not narrowed the same way: an album is listed and downloaded with its archived members included, as on Immich 2.x. Hidden assets are dropped, though — Immich stores the video part of a motion photo as a hidden asset, and the 2.x timeline endpoints never returned those for an album, so keeping them would mean one surprise extra file per motion photo on a 3.x server.
Pinning the variant¶
If GET /server/version is unreachable — a restrictive reverse proxy
that only forwards a subset of the API is the usual culprit —
detection fails and pymmich cannot pick a variant. Set
PYMMICH_API_VARIANT to skip detection and pin the variant instead:
# Talk to a 2.x server (e.g. 2.7):
export PYMMICH_API_VARIANT=v2
# Talk to a 3.x server (e.g. 3.0 or 3.1):
export PYMMICH_API_VARIANT=v3
Only v2 and v3 are accepted; anything else makes pymmich exit with
a configuration error. When the variable is set, no version request is
made at all.
Escape hatch, not a default
Leave PYMMICH_API_VARIANT unset unless detection actually fails.
A pinned variant does not track server upgrades: after moving from
Immich 2.x to 3.x you would have to update the variable by hand, or
pymmich keeps sending the old requests.
If detection fails¶
pymmich reports the failing request, so a broken detection shows up as
an error on GET /server/version. Things to check, in order:
- Is
PYMMICH_URLright? Bothhttps://hostandhttps://host/apiare accepted; the/apisuffix is appended when missing. - Is the server reachable at all?
GET /server/pingis public too, so if that fails the problem is the URL, the network or TLS verification — not the API variant. - Does a proxy block the endpoint? If ping works but the version
request returns 403/404, the proxy in front of Immich is filtering
paths. Either allow
/api/server/versionthrough, or setPYMMICH_API_VARIANTas shown above. - Does the server report an odd version? A response that isn't a
major/minor/patchtriple is rejected rather than guessed at; pinning the variant works around that as well.