Clippy Travels API

REST API for accessing travel photos and trips

Authentication

All API endpoints require authentication via API key:

API keys have scopes: read (GET endpoints), write (create/update), admin (full access)

Media

GET /api/media/search Read Search and filter photos
ParameterTypeDescription
trip_idint|stringFilter by trip ID (comma-separated for multiple)
tagsstringFilter by tag slugs or IDs (comma-separated)
exclude_tagsstringExclude photos with these tags
date_fromdateFilter by date (YYYY-MM-DD)
date_todateFilter by date (YYYY-MM-DD)
yearintFilter by year
monthintFilter by month (1-12)
typestringFilter by type: photo, video
has_locationboolFilter by GPS data presence
bboxstringBounding box: sw_lat,sw_lng,ne_lat,ne_lng
camerastringFilter by camera make/model
limitintResults per page (max 100, default 50)
offsetintPagination offset
sortstringSort field: taken_at, created_at, display_order
orderstringSort order: ASC, DESC
GET /api/media/search?tags=food,travel&limit=20

{
  "success": true,
  "data": [
    {
      "id": 123,
      "url": "https://...",
      "thumbnail": "https://...",
      "width": 4000,
      "height": 3000,
      "taken_at": "2024-01-15 14:30:00",
      "location": { "lat": 35.6762, "lng": 139.6503 },
      "trip": { "id": 1, "name": "Tokyo 2024", "slug": "tokyo-2024" },
      "tags": [
        { "id": 1, "name": "Food", "slug": "food", "color": "#f59e0b" }
      ]
    }
  ],
  "pagination": { "total": 150, "limit": 20, "offset": 0, "has_more": true }
}
GET /api/media/get Read Get single photo by ID
ParameterTypeDescription
idintRequired Photo ID
GET /api/media/get?id=123

{
  "success": true,
  "data": {
    "id": 123,
    "url": "https://cdn.example.com/photos/abc123.jpg",
    "thumbnail": "https://cdn.example.com/thumbs/abc123.jpg",
    "width": 4000,
    "height": 3000,
    "taken_at": "2024-01-15 14:30:00",
    "location": { "lat": 35.6762, "lng": 139.6503 },
    "trip": { "id": 1, "name": "Tokyo 2024", "slug": "tokyo-2024" },
    "camera_info": { "make": "Sony", "model": "A7IV", "lens": "24-70mm f/2.8" },
    "exposure_info": { "aperture": "f/2.8", "shutter_speed": "1/250", "iso": 400 },
    "navigation": { "prev_id": 122, "next_id": 124 }
  }
}
GET /api/media/filters Read Get available filter options

Returns available years, cameras, and other filter options based on existing photos.

GET /api/media/filters

{
  "success": true,
  "filters": {
    "years": [
      { "year": 2024, "count": 450 },
      { "year": 2023, "count": 320 }
    ],
    "cameras": [
      { "make": "Sony", "model": "A7IV", "count": 280 },
      { "make": "Apple", "model": "iPhone 15 Pro", "count": 150 }
    ],
    "trips": [
      { "id": 1, "name": "Tokyo 2024", "slug": "tokyo-2024", "photo_count": 125 }
    ],
    "date_range": { "min": "2023-01-15", "max": "2024-12-20" },
    "media_types": { "photo": 720, "video": 50 },
    "location": { "with_location": 680, "without_location": 90 }
  }
}

Trips

GET /api/trips/list Read List all published trips

Returns all published trips with photo counts.

GET /api/trips/list

{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Tokyo 2024",
      "slug": "tokyo-2024",
      "location": "Tokyo, Japan",
      "description": "Spring trip exploring Tokyo",
      "trip_date": "2024-03-15",
      "photo_count": 125,
      "cover_photo": { "id": 45, "thumbnail": "https://..." }
    },
    {
      "id": 2,
      "name": "Iceland Adventure",
      "slug": "iceland-adventure",
      "location": "Iceland",
      "trip_date": "2024-01-10",
      "photo_count": 89
    }
  ]
}
GET /api/trips/get Read Get single trip by ID or slug
ParameterTypeDescription
idintTrip ID
slugstringTrip slug (alternative to ID)
GET /api/trips/get?slug=tokyo-2024

{
  "success": true,
  "data": {
    "id": 1,
    "name": "Tokyo 2024",
    "slug": "tokyo-2024",
    "location": "Tokyo, Japan",
    "description": "Spring trip exploring Tokyo and surrounding areas",
    "trip_date": "2024-03-15",
    "photo_count": 125,
    "video_count": 8,
    "date_range": { "start": "2024-03-15", "end": "2024-03-22" },
    "cover_photo": { "id": 45, "url": "https://...", "thumbnail": "https://..." },
    "tags": [
      { "id": 1, "name": "Travel", "slug": "travel", "color": "#3b82f6" }
    ]
  }
}

Lists (Curated Collections)

GET /api/lists/list Read List all curated lists
ParameterTypeDescription
include_unpublishedboolInclude unpublished lists
include_hiddenboolInclude hidden lists
GET /api/lists/list

{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Best of 2024",
      "slug": "best-of-2024",
      "description": "Top photos from 2024",
      "photo_count": 25,
      "is_published": true,
      "has_password": false,
      "thumbnail": { "url": "https://...", "thumbnail": "https://..." }
    }
  ],
  "total": 1
}
GET /api/lists/get Read Get single list with photos
ParameterTypeDescription
idintList ID
slugstringList slug (alternative to ID)
passwordstringPassword if list is protected
GET /api/lists/get?slug=best-of-2024

{
  "success": true,
  "data": {
    "id": 1,
    "name": "Best of 2024",
    "slug": "best-of-2024",
    "photos": [
      { "id": 123, "url": "https://...", "thumbnail": "https://..." }
    ]
  }
}
POST /api/lists/create Write Create a new list
ParameterTypeDescription
namestringRequired List name
descriptionstringOptional description
passwordstringOptional password protection
is_publishedboolPublished status
is_hiddenboolHidden (direct link only)
publish_atdatetimeScheduled publish date
POST /api/lists/add-photo Write Add photo(s) to list
ParameterTypeDescription
list_idintRequired List ID
photo_idintSingle photo ID
photo_idsarrayMultiple photo IDs
POST /api/lists/remove-photo Write Remove photo(s) from list
ParameterTypeDescription
list_idintRequired List ID
photo_idintSingle photo ID
photo_idsarrayMultiple photo IDs
DELETE /api/lists/delete Admin Delete a list
ParameterTypeDescription
idintRequired List ID

Locations

GET /api/locations/countries Read List countries with photo counts
GET /api/locations/countries

{
  "success": true,
  "data": [
    { "country": "Japan", "photo_count": 450 },
    { "country": "Iceland", "photo_count": 120 }
  ],
  "total": 15
}
GET /api/locations/cities Read List cities with photo counts
ParameterTypeDescription
countrystringFilter by country name
GET /api/locations/cities?country=Japan

{
  "success": true,
  "data": [
    { "city": "Tokyo", "country": "Japan", "photo_count": 280 },
    { "city": "Kyoto", "country": "Japan", "photo_count": 95 }
  ]
}
GET /api/locations/region Read Query photos by bounding box
ParameterTypeDescription
lat1floatRequired SW latitude
lng1floatRequired SW longitude
lat2floatRequired NE latitude
lng2floatRequired NE longitude
limitintResults per page (max 100)
offsetintPagination offset
GET /api/locations/region?lat1=35.6&lng1=139.6&lat2=35.8&lng2=139.9

{
  "success": true,
  "data": [...photos...],
  "pagination": { "total": 280, "limit": 50, "offset": 0 },
  "bounding_box": { "sw": {...}, "ne": {...} }
}
GET /api/locations/thumbnail Read Get representative photo for location
ParameterTypeDescription
countrystringCountry name
citystringCity name
GET /api/locations/thumbnail?country=Japan

{
  "success": true,
  "data": {
    "photo": { "id": 123, "url": "https://...", "thumbnail": "https://..." },
    "location": { "country": "Japan" }
  }
}

Tags

GET /api/tags/list Read List all tags
ParameterTypeDescription
include_statsboolInclude photo/trip counts
GET /api/tags/list?include_stats=true

{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Food",
      "slug": "food",
      "color": "#f59e0b",
      "description": "Food and restaurant photos",
      "photo_count": 89,
      "trip_count": 5
    },
    {
      "id": 2,
      "name": "Landscape",
      "slug": "landscape",
      "color": "#22c55e",
      "photo_count": 156,
      "trip_count": 8
    }
  ]
}
POST /api/tags/create Write Create a new tag
ParameterTypeDescription
namestringRequired Tag name
colorstringHex color (default: #6366f1)
descriptionstringOptional description
POST /api/tags/create
Content-Type: application/json

{ "name": "Architecture", "color": "#8b5cf6", "description": "Buildings and structures" }

{
  "success": true,
  "data": {
    "id": 5,
    "name": "Architecture",
    "slug": "architecture",
    "color": "#8b5cf6",
    "description": "Buildings and structures"
  }
}
POST /api/tags/photo Write Add/remove tag from photo(s)
ParameterTypeDescription
photo_idintSingle photo ID
photo_idsarrayMultiple photo IDs (for bulk)
tag_idintSingle tag ID
tag_idsarrayMultiple tag IDs (for bulk)
actionstring"add" or "remove" (default: add)
POST /api/tags/photo
Content-Type: application/json

{ "photo_ids": [123, 124, 125], "tag_id": 1, "action": "add" }

{
  "success": true,
  "message": "Tag added to 3 photos",
  "affected": 3
}
POST /api/tags/trip Write Add/remove tag from trip
ParameterTypeDescription
trip_idintRequired Trip ID
tag_idintTag ID (for add/remove)
tag_idsarrayTag IDs (for "set" action)
actionstring"add", "remove", or "set"
POST /api/tags/trip
Content-Type: application/json

{ "trip_id": 1, "tag_ids": [1, 2, 3], "action": "set" }

{
  "success": true,
  "message": "Trip tags updated",
  "tags": [
    { "id": 1, "name": "Travel", "slug": "travel" },
    { "id": 2, "name": "Food", "slug": "food" },
    { "id": 3, "name": "City", "slug": "city" }
  ]
}

Jobs

GET /api/jobs/status Admin Get job status
ParameterTypeDescription
idintRequired Job ID
GET /api/jobs/status?id=42

{
  "success": true,
  "data": {
    "id": 42,
    "type": "import",
    "status": "running",
    "progress": 45,
    "total_items": 100,
    "processed_items": 45,
    "failed_items": 2,
    "created_at": "2024-01-15 10:30:00",
    "started_at": "2024-01-15 10:30:05"
  }
}
POST /api/jobs/cancel Admin Cancel a pending/running job
ParameterTypeDescription
job_idintRequired Job ID
POST /api/jobs/cancel
Content-Type: application/json

{ "job_id": 42 }

{ "success": true, "message": "Job cancelled" }
POST /api/jobs/resume Admin Resume a paused/cancelled job
ParameterTypeDescription
job_idintRequired Job ID
POST /api/jobs/resume
Content-Type: application/json

{ "job_id": 42 }

{ "success": true, "message": "Job resumed" }
POST /api/jobs/revert Admin Revert a completed job (delete imported photos)
ParameterTypeDescription
job_idintRequired Job ID
POST /api/jobs/revert
Content-Type: application/json

{ "job_id": 42 }

{ "success": true, "message": "Job reverted, 45 photos deleted" }

Albums (Sync)

GET /api/albums/diff Admin Get sync diff between local and Immich
ParameterTypeDescription
trip_idintRequired Trip ID
album_idstringRequired Immich album ID
GET /api/albums/diff?trip_id=1&album_id=abc-123

{
  "success": true,
  "data": {
    "to_add": 15,
    "to_remove": 3,
    "unchanged": 107,
    "new_assets": [
      { "id": "xyz-456", "filename": "IMG_001.jpg", "taken_at": "2024-01-15" }
    ],
    "removed_assets": [
      { "id": "xyz-789", "filename": "IMG_050.jpg" }
    ]
  }
}
POST /api/albums/sync Admin Execute album sync
ParameterTypeDescription
trip_idintRequired Trip ID
album_idstringRequired Immich album ID
actionstring"full", "add", or "remove"
POST /api/albums/sync
Content-Type: application/json

{ "trip_id": 1, "album_id": "abc-123", "action": "full" }

{
  "success": true,
  "data": {
    "job_id": 43,
    "status": "pending",
    "action": "full",
    "items_to_process": 15
  }
}