API reference

Photos

Your photo library: the timeline, photos, albums, links, uploads, Takeout imports, tokens, exports and your activity log.

See Photos. Every route is under /v1/me/photos: your own library, for you signed in, or your photo token (si_pho_…; photos:upload for uploads, photos:read for reading). Organization keys, Caity and the phone assistant never reach it. Links anyone can open are under /v1/hooks/photos without authentication.

Uploads: POST uploads (with the file's sha256 to skip one already in the library) answers the part size and links for the first parts; PUT each part's bytes to its link, ask POST uploads/:uploadId/parts for more, then POST uploads/:uploadId/complete. With singlePart: true the whole file goes to urls["1"] and size can be left out. Details and previews follow in the background (processed).

What a Photos link opens: its title, how many photos, whether locations are kept and downloads allowed, or that it needs its password. No authentication; the visit is in the owner's log.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Response 200

{
  needsPassword: true
} | {
  needsPassword: false
  title: string
  count: number
  keepLocation: boolean
  download: boolean
  expiresAt?: number
  owner?: string
}

POST /v1/hooks/photos/links/:token/unlock

Checks a link's password and answers a 12-hour grant (send it as x-si-link-grant). 10 wrong passwords per link per 15 minutes lock it. No authentication.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Request body

FieldTypeRequiredNotes
passwordstringYes1–200 characters

Response 200

{
  grant: string
  expiresAt: number
}

The link's photos (thumbnails), oldest first, in pages.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.
Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters

Response 200

{
  title: string
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    name: string
    takenAt: number
    width?: number
    height?: number
    duration?: number
    thumbUrl?: string
    location?: {
      lat: number
      lon: number
    }
  }[]
  cursor?: string
}

One photo through the link: its preview (and video), or the original when downloads are on (download=1).

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.
:photoIdPhoto id: the photo's file in Drive (fil_…).
Query parameterTypeRequiredNotes
download"0" | "1"No

Response 200

{
  name: string
  previewUrl?: string
  videoUrl?: string
  motionUrl?: string
  downloadUrl?: string
  location?: {
    lat: number
    lon: number
  }
}

POST /v1/hooks/photos/links/:token/archives

A ZIP of everything in the link (when downloads are on).

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Response 202

{
  archive: {
    archiveId: string
    status: "queued" | "building" | "ready" | "failed"
    name: string
    files: number
    bytes: number
    url?: string
    error?: string
  }
}

A link's ZIP: its status, and a one-hour download link once ready. No authentication.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.
:archiveIdZIP download id (zip_…).

Response 200

{
  archive: {
    archiveId: string
    status: "queued" | "building" | "ready" | "failed"
    name: string
    files: number
    bytes: number
    url?: string
    error?: string
  }
}

GET /v1/me/photos/library

The library: its settings, storage (shared with Drive's personal space) and counts. Made on first use.

Auth: user access token or platform agent key

Response 200

{
  library: {
    driveId: string
    settings: {
      ai: {
        faces: boolean
        objects: boolean
        memories: boolean
      }
      keepLocation: boolean
    }
    usage: {
      bytes: number
      files: number
      limit: number
    }
    counts: {
      photos: number
      favourites: number
      albums: number
      archive: number
      trash: number
    }
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

PATCH /v1/me/photos/settings

Opt-in features (faces, objects and text, memories: nothing runs while off) and whether new links keep locations.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
aiobjectNo
ai.facesbooleanNo
ai.objectsbooleanNo
ai.memoriesbooleanNo
keepLocationbooleanNo

Response 200

{
  library: {
    driveId: string
    settings: {
      ai: {
        faces: boolean
        objects: boolean
        memories: boolean
      }
      keepLocation: boolean
    }
    usage: {
      bytes: number
      files: number
      limit: number
    }
    counts: {
      photos: number
      favourites: number
      albums: number
      archive: number
      trash: number
    }
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/days

Photos per local day on the timeline (newest first), for the scrubber and the grid's layout.

Auth: user access token or platform agent key

Response 200

{
  days: {
    day: string
    count: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/timeline

Timeline photos taken between from and to (ms), newest first.

Auth: user access token or platform agent key

Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters
limitintegerNo1–500; coerced from a string
fromintegerNocoerced from a string
tointegerNocoerced from a string

Response 200

{
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }[]
  cursor?: string
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/lists/:list

Favourites, the archive or the trash, newest first.

Auth: user access token or platform agent key

Path parameterDescription
:listfavourites, archive or trash.
Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters
limitintegerNo1–500; coerced from a string

Response 200

{
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }[]
  cursor?: string
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/trash/empty

Deletes everything in the trash for good (the files from Drive too).

Auth: user access token or platform agent key

Response 200

{
  deleted: number
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/photos/batch

Several photos by id (the map's pins, a selection), in the order asked.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
photoIdsstring[]Yes1–200 items; each 3–64 characters

Response 200

{
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/photos/state

Favourite, unfavourite, archive, unarchive, move to the trash, restore or delete forever (trashed photos only).

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
photoIdsstring[]Yes1–500 items; each 3–64 characters
action"favourite" | "unfavourite" | "archive" | "unarchive" | "trash" | "restore" | "delete"Yes

Response 200

{
  changed: string[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/photos/:photoId

A photo's details: when (and from where that's known) and where it was taken, camera, size, description, albums, and one-hour links to show it (and a Live Photo's video). Logged as opened.

Auth: user access token or platform agent key

Path parameterDescription
:photoIdPhoto id: the photo's file in Drive (fil_…).

Response 200

{
  photo: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
    description?: string
    location?: {
      lat: number
      lon: number
      altitude?: number
      from: "file" | "edit" | "sidecar"
    }
    camera?: {
      make?: string
      model?: string
      lens?: string
      exposure?: string
      fNumber?: number
      iso?: number
      focal?: number
    }
    takenFrom: "file" | "client" | "added" | "edit" | "sidecar"
    local?: string
    offset?: number
    source: "mcp" | "agent" | "drive" | "edited" | "web" | "shortcut" | "takeout" | "picker"
    addedAt: number
    displayUrl?: string
    motionUrl?: string
    albums: {
      albumId: string
      title: string
    }[]
    versions: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

PATCH /v1/me/photos/photos/:photoId

Description, capture time (takenAt, ms; null goes back to the file's) and location (null removes it; "file" goes back to the file's).

Auth: user access token or platform agent key

Path parameterDescription
:photoIdPhoto id: the photo's file in Drive (fil_…).

Request body

FieldTypeRequiredNotes
descriptionstringNoup to 2,000 characters; can be null
favouritebooleanNo
takenAtintegerNocan be null
locationobject | null | "file"No

Response 200

{
  photo: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
    description?: string
    location?: {
      lat: number
      lon: number
      altitude?: number
      from: "file" | "edit" | "sidecar"
    }
    camera?: {
      make?: string
      model?: string
      lens?: string
      exposure?: string
      fNumber?: number
      iso?: number
      focal?: number
    }
    takenFrom: "file" | "client" | "added" | "edit" | "sidecar"
    local?: string
    offset?: number
    source: "mcp" | "agent" | "drive" | "edited" | "web" | "shortcut" | "takeout" | "picker"
    addedAt: number
    displayUrl?: string
    motionUrl?: string
    albums: {
      albumId: string
      title: string
    }[]
    versions: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/photos/:photoId/original

A one-hour link to the original (inline=1 to show it; motion=1 for a Live Photo's video).

Auth: user access token or platform agent key

Path parameterDescription
:photoIdPhoto id: the photo's file in Drive (fil_…).
Query parameterTypeRequiredNotes
inline"0" | "1"No
motion"0" | "1"No

Response 200

{
  url: string
  name: string
  mime: string
  size?: number
  expiresIn: number
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

PUT /v1/me/photos/photos/:photoId/poster

A video's poster frame, made in the browser (JPEG or WebP, base64, up to 1 MB).

Auth: user access token or platform agent key

Path parameterDescription
:photoIdPhoto id: the photo's file in Drive (fil_…).

Request body

FieldTypeRequiredNotes
imagestringYes10–1,400,000 characters

Response 200

{
  photo: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

Search by when (from/to, ms), where (a box: south,west,north,east; or near=lat,lon with km), words in names and descriptions, type and favourites.

Auth: user access token or platform agent key

Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters
limitintegerNo1–500; coerced from a string
fromintegerNocoerced from a string
tointegerNocoerced from a string
bboxstringNoup to 100 characters
nearstringNoup to 60 characters
kmnumberNo0.1–5000; coerced from a string
qstringNoup to 200 characters
type"photo" | "video" | "live" | "raw"No
favourite"0" | "1"No
archived"0" | "1"No

Response 200

{
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }[]
  cursor?: string
  total: number
  truncated: boolean
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/map

Every located photo as a point (id, latitude, longitude, time), for the map.

Auth: user access token or platform agent key

Response 200

{
  points: [string, number, number, number][]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/albums

Your albums, most recently changed first, with covers and how many links show each.

Auth: user access token or platform agent key

Response 200

{
  albums: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/albums

Creates an album, optionally with photos.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
titlestringYes1–200 characters
descriptionstringNoup to 2,000 characters
photoIdsstring[]Noup to 500 items; each 3–64 characters

Response 201

{
  album: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/albums/:albumId

An album and a page of its photos, in its sort order.

Auth: user access token or platform agent key

Path parameterDescription
:albumIdAlbum id (alb_…).
Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters
limitintegerNo1–500; coerced from a string

Response 200

{
  album: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }
  photos: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }[]
  cursor?: string
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

PATCH /v1/me/photos/albums/:albumId

Renames an album, changes its description, cover (a photo in it; null for the first) or order.

Auth: user access token or platform agent key

Path parameterDescription
:albumIdAlbum id (alb_…).

Request body

FieldTypeRequiredNotes
titlestringNo1–200 characters
descriptionstringNoup to 2,000 characters; can be null
coverIdstringNo3–64 characters; can be null
sort"oldest" | "newest" | "added"No

Response 200

{
  album: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

DELETE /v1/me/photos/albums/:albumId

Deletes the album (its photos stay in the library) and turns off its links.

Auth: user access token or platform agent key

Path parameterDescription
:albumIdAlbum id (alb_…).

Response 204 with no body.

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/albums/:albumId/photos

Adds photos to an album (up to 20,000 in one album). Ones already there stay.

Auth: user access token or platform agent key

Path parameterDescription
:albumIdAlbum id (alb_…).

Request body

FieldTypeRequiredNotes
photoIdsstring[]Yes1–500 items; each 3–64 characters

Response 200

{
  album: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/albums/:albumId/photos/remove

Takes photos out of an album; they stay in the library.

Auth: user access token or platform agent key

Path parameterDescription
:albumIdAlbum id (alb_…).

Request body

FieldTypeRequiredNotes
photoIdsstring[]Yes1–500 items; each 3–64 characters

Response 200

{
  album: {
    albumId: string
    title: string
    description?: string
    count: number
    coverId?: string
    coverUrl?: string
    sort: "oldest" | "newest" | "added"
    createdAt: number
    updatedAt: number
    links: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

Links anyone can open: albums and chosen photos.

Auth: user access token or platform agent key

Response 200

{
  links: {
    linkId: string
    url: string
    albumId?: string
    photoCount?: number
    title: string
    keepLocation: boolean
    download: boolean
    expiresAt?: number
    hasPassword: boolean
    visits: number
    lastVisitAt?: number
    createdAt: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/links

A link to an album or to chosen photos: view only, locations removed unless keepLocation, optional expiry and password.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
albumIdstringNo3–64 characters
photoIdsstring[]No1–500 items; each 3–64 characters
titlestringNoup to 200 characters
keepLocationbooleanNo
downloadbooleanNo
expiresAtintegerNo> 0
passwordstringNo4–200 characters

Response 201

{
  link: {
    linkId: string
    url: string
    albumId?: string
    photoCount?: number
    title: string
    keepLocation: boolean
    download: boolean
    expiresAt?: number
    hasPassword: boolean
    visits: number
    lastVisitAt?: number
    createdAt: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

Changes a link: password null removes it; rotate makes a new address (the old one stops working).

Auth: user access token or platform agent key

Path parameterDescription
:linkIdLink id (ilk_… for issue links, irl_… for remote links, plk_… for Photos links: not the link's secret).

Request body

FieldTypeRequiredNotes
titlestringNoup to 200 characters
keepLocationbooleanNo
downloadbooleanNo
expiresAtintegerNo> 0; can be null
passwordstringNo4–200 characters; can be null
rotatebooleanNo

Response 200

{
  link: {
    linkId: string
    url: string
    albumId?: string
    photoCount?: number
    title: string
    keepLocation: boolean
    download: boolean
    expiresAt?: number
    hasPassword: boolean
    visits: number
    lastVisitAt?: number
    createdAt: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

Turns a link off: it stops working at once.

Auth: user access token or platform agent key

Path parameterDescription
:linkIdLink id (ilk_… for issue links, irl_… for remote links, plk_… for Photos links: not the link's secret).

Response 204 with no body.

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/uploads/check

Which of these SHA-256 hashes are already in the library (skip uploading them).

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
hashesstring[]Yes1–1,000 items; each matches ^[0-9a-f]{64}$

Response 200

{
  existing: {
    [key: string]: string
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

POST /v1/me/photos/uploads

Starts an upload into the library: answers Drive's part links (PUT each part, then complete), or duplicate with the photo when sha256 is already there. singlePart (iPhone Shortcuts) sends the whole file to one link; its size may then be left out.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
namestringYes1–255 characters
extstringNoup to 10 characters
sizeintegerNo≥ 0
mimestringNoup to 200 characters
sha256stringNomatches ^[0-9a-f]{64}$
takenAtintegerNo
albumIdstringNo3–64 characters
pairWithstringNo3–64 characters
singlePartbooleanNo
source"web" | "shortcut" | "agent" | "edited"No

Response 201

{
  duplicate: false
  uploadId: string
  itemId: string
  partSize: number
  partCount: number
  urls: {
    [key: number]: string
  }
  contentType: string
  name: string
} | {
  duplicate: true
  photo: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

POST /v1/me/photos/uploads/:uploadId/parts

Links for more parts of an upload (an hour each).

Auth: user access token or platform agent key

Path parameterDescription
:uploadIdUpload id (dup_…), from starting the upload.

Request body

FieldTypeRequiredNotes
partNumbersinteger[]Yes1–100 items; each 1–10000

Response 200

{
  urls: {
    [key: number]: string
  }
  expiresIn: number
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

GET /v1/me/photos/uploads/:uploadId

The parts already stored (resuming).

Auth: user access token or platform agent key

Path parameterDescription
:uploadIdUpload id (dup_…), from starting the upload.

Response 200

{
  uploadId: string
  name: string
  size: number
  partSize: number
  partCount: number
  parts: {
    partNumber: number
    size?: number
  }[]
  expiresAt: number
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

POST /v1/me/photos/uploads/:uploadId/complete

Finishes an upload: the photo (details and previews follow in the background), or the one it duplicates.

Auth: user access token or platform agent key

Path parameterDescription
:uploadIdUpload id (dup_…), from starting the upload.

Response 200

{
  photo: {
    photoId: string
    kind: "raw" | "live" | "video" | "photo"
    state: "main" | "archive" | "trash" | "motion"
    name: string
    mime: string
    size: number
    takenAt: number
    day: string
    width?: number
    height?: number
    duration?: number
    favourite: boolean
    thumbUrl?: string
    located: boolean
    pairId?: string
    processed: boolean
    trashedAt?: number
  }
  duplicate: boolean
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

DELETE /v1/me/photos/uploads/:uploadId

Abandons an upload and the parts it stored.

Auth: user access token or platform agent key

Path parameterDescription
:uploadIdUpload id (dup_…), from starting the upload.

Response 204 with no body.

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.
403This token can't do that (it needs photos:upload).

GET /v1/me/photos/imports

Google Takeout imports, newest first.

Auth: user access token or platform agent key

Response 200

{
  imports: {
    importId: string
    status: "queued" | "canceled" | "done" | "failed" | "uploading" | "running"
    files: {
      name: string
      size: number
      format: "zip" | "tgz"
      from: "upload" | "drive"
      uploaded: boolean
    }[]
    entries: number
    processed: number
    imported: number
    duplicates: number
    skipped: number
    failed: number
    albums: number
    bytes: number
    error?: string
    problems: string[]
    createdAt: number
    startedAt?: number
    finishedAt?: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/imports

A Takeout import: archives to upload (files: name and size of each .zip or .tgz; answers an upload per file) or archives already in Drive (driveItemIds, personal files). Start it once they're uploaded.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
filesobject[]No1–100 items
files[].namestringYes1–255 characters
files[].sizeintegerYes1–107374182400
driveItemIdsstring[]No1–100 items; each 3–64 characters

Response 201

{
  import: {
    importId: string
    status: "queued" | "canceled" | "done" | "failed" | "uploading" | "running"
    files: {
      name: string
      size: number
      format: "zip" | "tgz"
      from: "upload" | "drive"
      uploaded: boolean
    }[]
    entries: number
    processed: number
    imported: number
    duplicates: number
    skipped: number
    failed: number
    albums: number
    bytes: number
    error?: string
    problems: string[]
    createdAt: number
    startedAt?: number
    finishedAt?: number
  }
  uploads: {
    index: number
    partSize: number
    partCount: number
    urls?: {
      [key: number]: string
    }
    parts?: {
      partNumber: number
      size?: number
    }[]
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/imports/:importId

An import with the parts each of its uploads has stored (resuming).

Auth: user access token or platform agent key

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 200

{
  import: {
    importId: string
    status: "queued" | "canceled" | "done" | "failed" | "uploading" | "running"
    files: {
      name: string
      size: number
      format: "zip" | "tgz"
      from: "upload" | "drive"
      uploaded: boolean
    }[]
    entries: number
    processed: number
    imported: number
    duplicates: number
    skipped: number
    failed: number
    albums: number
    bytes: number
    error?: string
    problems: string[]
    createdAt: number
    startedAt?: number
    finishedAt?: number
  }
  uploads: {
    index: number
    partSize: number
    partCount: number
    urls?: {
      [key: number]: string
    }
    parts?: {
      partNumber: number
      size?: number
    }[]
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/imports/:importId/files/:index/parts

Links for the parts of one archive's upload (index: its place in files).

Auth: user access token or platform agent key

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).
:indexThe attachment's position in the message, from 0; or a Takeout archive's place in its import's files.

Request body

FieldTypeRequiredNotes
partNumbersinteger[]Yes1–100 items; each 1–10000

Response 200

{
  urls: {
    [key: number]: string
  }
  expiresIn: number
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/imports/:importId/start

Completes the archives' uploads and starts importing (in the background; re-imports skip what's there).

Auth: user access token or platform agent key

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 200

{
  import: {
    importId: string
    status: "queued" | "canceled" | "done" | "failed" | "uploading" | "running"
    files: {
      name: string
      size: number
      format: "zip" | "tgz"
      from: "upload" | "drive"
      uploaded: boolean
    }[]
    entries: number
    processed: number
    imported: number
    duplicates: number
    skipped: number
    failed: number
    albums: number
    bytes: number
    error?: string
    problems: string[]
    createdAt: number
    startedAt?: number
    finishedAt?: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/imports/:importId/cancel

Stops an import; what it imported stays.

Auth: user access token or platform agent key

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 200

{
  import: {
    importId: string
    status: "queued" | "canceled" | "done" | "failed" | "uploading" | "running"
    files: {
      name: string
      size: number
      format: "zip" | "tgz"
      from: "upload" | "drive"
      uploaded: boolean
    }[]
    entries: number
    processed: number
    imported: number
    duplicates: number
    skipped: number
    failed: number
    albums: number
    bytes: number
    error?: string
    problems: string[]
    createdAt: number
    startedAt?: number
    finishedAt?: number
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

DELETE /v1/me/photos/imports/:importId

Removes a finished, failed or canceled import (and its uploaded archives). Imported photos stay.

Auth: user access token or platform agent key

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 204 with no body.

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/tokens

Personal tokens for uploading (iPhone Shortcut, Mac sync) and reading (MCP).

Auth: user access token or platform agent key

Response 200

{
  tokens: {
    tokenId: string
    name: string
    scopes: ("photos:upload" | "photos:read")[]
    createdAt: number
    lastUsedAt?: number
    expiresAt?: number
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/tokens

Makes a token; its secret is in the answer only.

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
namestringYes1–100 characters
scopes("photos:upload" | "photos:read")[]Yesat least 1 item
expiresAtintegerNo> 0

Response 201

{
  token: {
    tokenId: string
    name: string
    scopes: ("photos:upload" | "photos:read")[]
    createdAt: number
    lastUsedAt?: number
    expiresAt?: number
  }
  secret: string
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

DELETE /v1/me/photos/tokens/:tokenId

Removes a photo token: it stops working at once.

Auth: user access token or platform agent key

Path parameterDescription
:tokenIdPhoto token id (pht_…), not the token itself.

Response 204 with no body.

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/exports

Full exports of the library: ZIPs of every original with an index of dates, places, albums and descriptions.

Auth: user access token or platform agent key

Response 200

{
  exports: {
    exportId: string
    status: "queued" | "ready" | "failed"
    files: number
    bytes: number
    createdAt: number
    expiresAt: number
    archives: {
      archiveId: string
      name: string
      status: string
      files: number
      bytes: number
      url?: string
    }[]
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

POST /v1/me/photos/exports

Starts a full export of the library (originals as ZIPs of up to 10,000 files and 10 GB, with photos.json and albums.json). Ask for it until it's ready.

Auth: user access token or platform agent key

Response 202

{
  export: {
    exportId: string
    status: "queued" | "ready" | "failed"
    files: number
    bytes: number
    createdAt: number
    expiresAt: number
    archives: {
      archiveId: string
      name: string
      status: string
      files: number
      bytes: number
      url?: string
    }[]
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/exports/:exportId

An export with each ZIP's status and its download link (a day) once ready.

Auth: user access token or platform agent key

Path parameterDescription
:exportIdAn export's id (pex_… for Photos, oex_… for an organization).

Response 200

{
  export: {
    exportId: string
    status: "queued" | "ready" | "failed"
    files: number
    bytes: number
    createdAt: number
    expiresAt: number
    archives: {
      archiveId: string
      name: string
      status: string
      files: number
      bytes: number
      url?: string
    }[]
  }
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/log

The owner's personal log: every change and access (theirs, their tokens', link visitors').

Auth: user access token or platform agent key

Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters

Response 200

{
  events: {
    activityId: string
    action: string
    actorId: string
    actorLabel?: string
    at: number
    detail: {
      [key: string]: unknown
    }
  }[]
  cursor?: string
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.

GET /v1/me/photos/access

Who can see what: links, tokens, and any of the library's files shared through Drive.

Auth: user access token or platform agent key

Response 200

{
  links: {
    linkId: string
    url: string
    albumId?: string
    photoCount?: number
    title: string
    keepLocation: boolean
    download: boolean
    expiresAt?: number
    hasPassword: boolean
    visits: number
    lastVisitAt?: number
    createdAt: number
  }[]
  tokens: {
    tokenId: string
    name: string
    scopes: ("photos:upload" | "photos:read")[]
    createdAt: number
    lastUsedAt?: number
    expiresAt?: number
  }[]
  driveShares: {
    itemId: string
    name: string
    principalId: string
    role: string
  }[]
  driveLinks: {
    itemId: string
    name: string
  }[]
}

Errors

StatusMessage
403Caity can look at your photos but not change them.
403This token can't do that (it needs photos:read).
403Photos are only for the person signed in, or their own photo token.