API reference

Every route of the PhotoMemory API. Base URL https://photomemory.thundera.eu.

Conventions

  • Auth — "User" routes need a Thundera SSO session: the thundera_token cookie, or Authorization: Bearer <access token>. "Admin" routes need a token with a system-super-admin, system-admin or system-support role, or the X-Admin-Key header. "Public" needs nothing.
  • Format — JSON. IDs are UUIDs. Lists take page (from 1) and per_page (default 50, max 200).
  • Errors — {"detail": "..."} with 400 invalid input (unsupported format, file over 50 MB), 401 not authenticated or invalid token, 403 not allowed, 404 not found, 409 duplicate photo, 410 share expired, 429 rate limited.

Account

MethodPathAuthDescription
GET/api/auth/meUserCurrent user: id, email, username, full_name, avatar_url, storage_used, storage_limit (GB), quality_preference, plan, has_plan.
PATCH/api/auth/settingsUserBody {quality_preference?, full_name?}; quality is full or optimized. Returns the user.
POST/api/auth/select-plan?plan_id=UserChoose a local storage plan (id from /api/plans/local). 404 if unknown.

Photos

MethodPathAuthDescription
POST/api/photos/uploadUsermultipart/form-data field file (max 50 MB). 201 with the photo. 409 if the same file (checksum) already exists.
GET/api/photosUserQuery page, per_page, sort (taken_at, created_at, file_size), order (asc, desc).
GET/api/photos/timelineUserQuery year, month. Returns [{date, photos[]}].
GET/api/photos/mapUserQuery lat, lon, radius_km. Photos with GPS, max 500.
GET/api/photos/searchUserQuery q, camera_make, camera_model, date_from, date_to, person_id, tags, is_favorite, page, per_page.
GET/api/photos/trashUserDeleted photos (30-day retention).
DELETE/api/photos/trash/emptyUserPermanently delete everything in the Trash.
GET/api/photos/stats/camerasUserCamera usage statistics.
GET/api/photos/{id}UserOne photo with EXIF, location, tags, ai_tags, thumbnail_url, medium_url.
GET/api/photos/{id}/downloadUserDecrypted original file.
PATCH/api/photos/{id}UserBody {description?, tags?, is_favorite?, is_archived?}.
POST/api/photos/{id}/rotateUserRotate; degrees must be 90, 180 or 270.
DELETE/api/photos/{id}?permanent=falseUserMove to Trash, or delete for good with permanent=true.
POST/api/photos/{id}/restoreUserRestore from Trash.

Albums

MethodPathAuthDescription
POST/api/albumsUserBody {title, description?}. 201.
GET/api/albumsUserList albums with photo_count and cover_url.
GET/api/albums/{id}UserAlbum with its photos (paged).
PATCH/api/albums/{id}UserBody {title, description?}.
POST/api/albums/{id}/photosUserBody: JSON array of photo UUIDs.
DELETE/api/albums/{id}/photosUserBody: JSON array of photo UUIDs to remove.
DELETE/api/albums/{id}UserDelete the album (photos are kept).

People

MethodPathAuthDescription
GET/api/peopleUserPeople found in your photos.
GET/api/people/{id}UserOne person with their photos.
PATCH/api/people/{id}UserRename: body {name}.
POST/api/people/{id}/merge/{other_id}UserMerge other_id into id.

Sharing

MethodPathAuthDescription
POST/api/sharesUserBody {album_id? | photo_id?, shared_with_email?, permission, is_public, expires_hours?, password?, max_views?}. Returns link_token.
GET/api/shares/link/{token}?password=PublicOpen a shared item. 404 unknown, 410 expired or max views reached, 401 password required or wrong.
GET/api/shares/shared-with-meUserItems shared with your email.
DELETE/api/shares/{id}UserRevoke a share.

Families

MethodPathAuthDescription
POST/api/familiesUserBody {name}. 201.
GET/api/familiesUserYour families with members.
POST/api/families/{id}/inviteUserBody {email, role} (owner, admin, member).
GET/api/families/{id}/photosUserFamily photo stream.
DELETE/api/families/{id}/members/{user_id}UserRemove a member.

Sync

MethodPathAuthDescription
GET/api/sync/statusUserAccount and library status for a sync client.
GET/api/sync/manifestUserEvery photo id, checksum, filename, size and updated_at; plus server_time.
GET/api/sync/changes?since=UserPhotos changed since an ISO timestamp (includes is_deleted); per_page up to 1000.
GET/api/sync/photo/{id}/originalUserDecrypted original.
GET/api/sync/photo/{id}/thumbnailUserThumbnail.
GET/api/sync/photo/{id}/metadataUserFull metadata.

Plans

MethodPathAuthDescription
GET/api/plansPublicPlan catalogue proxied from auth.thundera.eu: {plans:[{id, tier, billing_period, name, tagline, unit_amount_cents, currency, features, limits, is_popular}]}. Cached 60 s.
GET/api/plans/localPublicLocal storage plans selectable at first access.

Admin

MethodPathAuthDescription
GET/api/admin/statsAdminSystem totals (users, photos, albums, people, faces, storage).
GET/api/admin/users?search=AdminPaged user list.
GET/api/admin/users/{id}AdminUser detail.
PATCH/api/admin/users/{id}AdminBody may contain is_active, quality_preference, full_name, is_verified, plan_id (storage limit follows the plan).
DELETE/api/admin/users/{id}AdminDelete a user with all data in the database and S3.
POST/api/admin/reprocess-metadataAdminFill missing metadata (background).
POST/api/admin/reprocess-metadata-overwriteAdminRe-extract and overwrite all metadata.
GET/api/admin/thumbnail-presetsAdminPresets low, medium, high.
POST/api/admin/reprocess-thumbnails?preset=&user_id=&user_ids=AdminRegenerate thumbnails for one, several or all users.
GET/api/plans/admin/allAdminAll local plans.
POST/api/plans/adminAdminCreate a local plan.
PATCH/api/plans/admin/{id}AdminUpdate a local plan.
DELETE/api/plans/admin/{id}AdminDiscontinue (soft delete).

Health and metrics

MethodPathAuthDescription
GET/api/healthPublicLiveness.
GET/metricsPublicPrometheus metrics (scraped in-cluster).

Example

curl -H "Authorization: Bearer $TOKEN" \
  "https://photomemory.thundera.eu/api/photos/search?q=lisbon&is_favorite=true"