Reference #
Every type, method, argument, condition, comparator, facet, error and limit of the API, as the server checks them. Lengths count characters (Unicode code points) unless they say bytes. A JSON Schema of every type says the same, generated from the same constants.
Capabilities, abbreviated below:
| URN | |
|---|---|
| core | urn:ietf:params:jmap:core |
| filenode | urn:ietf:params:jmap:filenode |
| files | https://ns.ordner.fyi/svc/jmap/files |
| photos | https://ns.ordner.fyi/svc/jmap/photos |
Each method needs its capability in using and a right of the credential
over the account (the credential's scopes, intersected with a delegation's
rights in a delegated account; Signing in §9).
1. Methods at a glance #
| Method | Capability | Right | Section |
|---|---|---|---|
FileNode/get, /changes, /query, /queryChanges |
filenode | drive:read |
§2 |
FileNode/set, FileNode/copy |
filenode | drive:write |
§2 |
FileNode/facets |
files | drive:read |
§7 |
FileAnnotation/set |
files | drive:annotate |
§4 |
AnnotationSchema/get, /changes |
files | drive:read |
§5 |
AnnotationSchema/set |
files | drive:annotate |
§5 |
AnnotationView/get, /changes |
files | drive:read |
§6 |
AnnotationView/set |
files | drive:annotate |
§6 |
FileVector/get, /changes, /query |
files | drive:read |
§9 |
FileVector/set |
files | drive:annotate |
§9 |
AnnotationSource/get, /changes |
files | drive:read; the owner reads every source, anyone else only their own |
§11 |
AppData/destroy |
files | drive:annotate |
§12 |
PhotoFace/get, /changes, /query |
photos | drive:read (embeddings: drive:faces) |
§8 |
PhotoFace/set |
photos | the drive's owner, or drive:faces |
§8 |
PhotoPeople/get |
photos | drive:read |
§8 |
PhotoPeople/set |
photos | drive:write |
§8 |
PhotoTags/get |
photos | drive:read |
§8 |
AlbumSuggestion/get, /changes, /query, /queryChanges |
photos | drive:read |
§10 |
AlbumSuggestion/set |
photos | drive:annotate (deciding: drive:write) |
§10 |
Blob/upload, Blob/get, Blob/lookup |
urn:ietf:params:jmap:blob |
a write right (upload), drive:read |
RFC 9404 |
Quota/get, … |
urn:ietf:params:jmap:quota |
RFC 9425 |
Faces, people and suggestions are methods of a drive's own account; an
account a share opened to the person (a view) answers them
accountNotSupportedByMethod. FileVector/get also works in a view.
2. FileNode #
A file, folder or symbolic link of a drive (draft-ietf-jmap-filenode-14).
2.1 Properties #
| Property | Type | |
|---|---|---|
id |
Id | stable across rename and move |
parentId |
Id | null | null at the top of the drive |
nodeType |
"file" | "directory" | "symlink" |
|
blobId |
Id | null | the content, a file's only; bound to the person who read it |
target |
String[] | null | a symbolic link's target |
size |
UnsignedInt | null | bytes, a file's only |
name |
String | 1–255 octets of UTF-8, no / or control characters, not ., .., .versions |
type |
String | null | media type, a file's only |
created, modified, changed |
UTCDate | changed is server-set on every write of the node, including annotations |
accessed |
UTCDate | null | |
executable |
Boolean | |
isSubscribed |
Boolean | always true |
myRights |
{ mayRead, mayAddChildren, mayRename, mayDelete, mayModifyContent, mayShare } |
|
shareWith, role |
filenode-14 | |
annotations |
{ <sourceId>: FileAnnotation } | null |
every source's annotation of the current content (§3); read-only |
photo |
Photo | null | an analysed picture's metadata (§2.3) |
album |
{ coverId, locationKeep, faceNamesKeep } | null |
a folder directly under Pictures/Albums; the share rules that keep location, and those that keep face names (§8.6) |
notPicture |
Boolean | the photo worker read it and found no picture |
unreadable |
String | null | why the photo worker gave up reading it |
shareAccess, officeAccess, openBy |
sharing and editing; not part of this API |
FileNode/get answers every property unless properties names some; id
is always answered. ids: null is refused when the account holds more than
maxObjectsInGet nodes: query, then get by id.
2.2 Query conditions #
FileNode/query's filter is a FilterCondition or a FilterOperator
{ operator: "AND" | "OR" | "NOT", conditions: [] } (NOT: none of the
conditions). Within one condition object, all members must hold. An unknown
member is unsupportedFilter; a value of the wrong type is
invalidArguments.
Standard (filenode-14):
| Condition | Value | Matches |
|---|---|---|
isTopLevel |
Boolean | nodes at the top of the drive (or not) |
parentId |
Id | the folder's children |
ancestorId |
Id | everything below the folder |
descendantId |
Id | the node's ancestors |
nodeType |
file | directory | symlink |
|
role, hasAnyRole |
String, Boolean | |
blobId |
Id | files of that content |
isExecutable |
Boolean | |
createdBefore, createdAfter, modifiedBefore, modifiedAfter, accessedBefore, accessedAfter |
UTCDate | Before is <, After is ≥ |
minSize, maxSize |
UnsignedInt | size ≥ minSize, size < maxSize |
name, type |
String | exactly |
nameMatch, typeMatch |
String | a glob (*, ?) over the name or type |
text |
String | nameMatch or typeMatch of the value, or body |
body |
String | what applications wrote: every word a prefix of a word of a description, a label, a searchable field or a text, without case |
changedAfter |
UTCDate | changed ≥ the value (Keeping up §3) |
Annotations (files):
| Condition | Value | Matches |
|---|---|---|
hasLabel |
String | files with a label of that name from any source, without case (NFC) |
annotatedBy |
SourceId | files the source has a current annotation of |
isAnnotated |
Boolean | false: files whose current content the calling source has not annotated (its queue); true: those it has. A picture's .xmp sidecar is in neither |
field |
{ source, name, equals | in | min | max | exists | contains } |
§5.3 |
similarTo |
{ model, vector, minSimilarity } |
§9.3 |
Pictures and faces (photos):
| Condition | Value | Matches |
|---|---|---|
isPhoto |
Boolean | analysed pictures, and files not read yet that look like pictures by type or name |
isPhotoRead |
Boolean | analysed pictures only |
isNotPicture |
Boolean | files that look like pictures and are not |
isMarkedNotPicture |
Boolean | every file the worker found no picture in |
isPhotoStale, isPhotoUnlinked |
Boolean | the photo worker's queues |
isAlbum |
Boolean | album folders |
photoTakenAfter, photoTakenBefore |
LocalDate (2026-10-14T09:12:03) |
taken ≥, taken < |
personName |
String | pictures with a face of that name, without case |
hasFaces |
Boolean | pictures with at least one face region |
keyword |
String | read pictures whose photo.keywords hold it, without case |
hasShareWith |
Boolean | shared nodes |
2.3 Comparators #
sort is a list of { property, isAscending }; ties are broken by name,
then id.
property |
|
|---|---|
name, type, size, created, modified, nodeType, tree |
filenode-14 |
photoTaken |
by photo.taken (an unread picture by modified), nodes without one last |
field |
with source and name: a sortable field of that source (§5); nodes without a value last either way; else unsupportedSort |
similarity |
only with a similarTo condition: the most similar first, whatever isAscending says |
2.4 The photo value #
null on anything that is not an analysed picture (and while a changed
picture is being read again). Otherwise:
| Field | Type | |
|---|---|---|
taken |
LocalDate | the camera's wall clock |
takenOffset |
±HH:MM | null |
|
width, height |
Int | pixels as displayed |
orientation |
1–8 | EXIF orientation |
fileOrientation |
1–8 | null | the orientation in the file's own bytes |
camera |
{ make, model, lens } | null |
|
exposure |
{ fNumber, exposureTime, iso, focalLength } | null |
|
location |
{ latitude, longitude, altitude } | null |
null to a reader of an album shared without location |
title, description |
String | null | the person's (XMP) |
keywords |
String[] | the person's (XMP dc:subject) |
rating |
−1–5 | |
faces |
PhotoFaceRegion[] | §8.1 |
thumbnailBlobId |
Id | null | about 400 px, WebP |
displayBlobId |
Id | null | about 2,048 px, WebP, for formats a browser cannot show |
renderedBlobId |
Id | null | the edited picture, JPEG |
edits |
{ crop, angle } | null |
|
renderedFrom |
{ orientation, edits } |
what the renditions show |
sidecarId |
Id | null | the picture's .xmp sidecar file |
originId |
Id | null | an album copy's library picture |
analysed |
String | the content it was read from (server-set) |
With drive:write, FileNode/set writes photo/title, photo/description,
photo/keywords, photo/rating, photo/taken, photo/takenOffset,
photo/location, photo/orientation, photo/edits and photo/faces
(the person's faces, §8.2), into the sidecar first. Every other field is
server-set: writing it is invalidProperties (stating its current value is
no change).
3. FileAnnotation #
One source's annotation of a file's current content, the value of
FileNode.annotations[<sourceId>].
| Field | Type | |
|---|---|---|
source |
Source | { id, actor: { id, name }, app: { id, kind: "app" | "pw", name } | null } |
blobId |
Id | the content it was made from, which is the file's now (an annotation of other content is not answered) |
updated |
UTCDate | its last write |
description |
String | null | ≤ 2,000 characters |
labels |
[{ name, confidence }] |
≤ 100; name 1–100 characters, unique without case; confidence 0–1 or null |
textBlobId |
Id | null | the file's text as the source wrote it, text/plain; charset=utf-8 |
fields |
{ <name>: value } |
values of the source's fields (§5) its schema still names, of the type it says now |
annotations is null when no source has a current annotation. Everyone
who may read the file reads every source's annotations (a share reader
too). A copy of the file carries them (same content); move and rename keep
them. Downloading textBlobId needs only a read of the file.
4. FileAnnotation/set #
{ accountId, ifInState?, update: { <nodeId>: Update }, destroy: [<nodeId> | "<nodeId>/<sourceId>"] }. There is no create: the node is the key. At
most 256 updates and destroys together (else requestTooLarge). The state
is FileNode's: every write changes it and is pushed as a FileNode change.
4.1 The caller's own annotation #
Update = { blobId, description?, labels?, text?, fields?, faces? };
nothing else.
blobId(required): the file'sblobIdas this person read it. The write lands only while the file still holds that content; else SetErrorcontentChanged(properties: ["blobId"]). A blob id that is not a content blob id this person read isinvalidProperties.- Absent fields stay as they were;
{ blobId }alone records "read, nothing to say", which takes the file off the caller's queue. description: String ≤ 2,000 ornull.labels: the whole list, replacing the caller's;[]clears it.text: the blob id of an upload of typetext/plain(charset UTF-8), ≤ 1,048,576 bytes (tooLarge), valid UTF-8;nullremoves it. Its words are searchable at once.fields:{ <name>: value | null }for fields of the caller's schema (§5):nullremoves a value, absent ones stay. A name the schema does not define, or a value not of its type, isinvalidPropertieswithproperties: ["fields/<name>"].faces: only on an analysed picture (§8.3); elsewhereinvalidProperties.- A write over an annotation of older content starts afresh: nothing of the old one carries over.
updated[<nodeId>] is null, or, when the update held faces, { faces: [<faceId> | null], facesRefused: [{ at, type, description }] } (§8.3).
4.2 Removing from another source's annotation #
An update naming another source only removes from that source's
annotation: { source, description: null?, labels?, text: null?, fields: { <name>: null }? }. labels is the list to keep, a subset of that
source's labels (a label not there is forbidden). It takes no blobId and
no faces (another source's faces are changed through photo/faces,
§8.2); a description, text or field value other than null is forbidden.
This is how the person (or a front-end acting for them) declines what an
application said after keeping it as their own.
4.3 Destroy #
"<nodeId>" removes the caller's own annotation of the node (its text
included); "<nodeId>/<sourceId>" removes that source's. A node not read by
the caller is notFound.
4.4 SetErrors #
type |
When |
|---|---|
notFound |
no such file, or one the caller cannot read |
contentChanged |
blobId is not the file's content now |
invalidProperties |
a member that is not one of the above; a folder; a value out of its bounds (properties names it) |
tooLarge |
text over 1 MiB |
forbidden |
an embedding without drive:faces; anything but a removal in another source's annotation |
serverFail |
the write did not land (other writes kept changing the file); try again |
5. AnnotationSchema: fields an application defines #
5.1 The schema #
One per source per account; its id is the source id.
{ "id": "<sourceId>", "source": Source, "updated": UTCDate,
"fields": { "<name>": FieldDefinition } }
| FieldDefinition | Type | Default | |
|---|---|---|---|
type |
string | strings | number | boolean | date | localDate |
— | |
title |
{ <language tag>: String } |
— | x-default required; each 1–64 characters |
shown |
Boolean | true |
shown in the web apps' details |
facet |
Boolean | false |
offered as a filter with counts (§7) |
searchable |
Boolean | false |
string values enter the full-text index (body, text) |
sortable |
Boolean | false |
offered as a sort (field comparator) |
unit |
String | null | null |
1–16 characters, shown after a number |
- Names match
[a-z][a-zA-Z0-9]{0,63}; at most 64 fields. - Language tags are
x-defaultor BCP 47 (de,pt-BR).
| Type | Value |
|---|---|
string |
String ≤ 1,000 |
strings |
≤ 100 Strings of ≤ 200 |
number |
a finite number |
boolean |
Boolean |
date |
UTCDate (2026-11-15T10:00:00Z) |
localDate |
a calendar date YYYY-MM-DD |
5.2 Methods #
AnnotationSchema/set { accountId, schema: { fields } | null }replaces the caller's whole schema (nullremoves it). Answers{ accountId, oldState, newState, schema }, the schema with defaults filled in. An invalid schema is the method errorinvalidArgumentsnaming what is wrong. Changing a field's type drops its values; removing a field drops its values; both leave the index at once and are never answered again.AnnotationSchema/get { accountId, ids }:idsare source ids,nullfor every source's.AnnotationSchema/changesas RFC 8620; push typeAnnotationSchema.
5.3 The field condition #
{ field: { source, name, <operator> } }, at least one operator:
| Operator | Value | Matches |
|---|---|---|
equals |
a value of the field's type | the value, strings without case (NFC) |
in |
list of values | any of them |
min, max |
number, UTCDate or YYYY-MM-DD |
inclusive bounds; for number, date, localDate only |
exists |
Boolean | the node has a value (or not) |
contains |
list of Strings | a strings value holding any of them |
A field the source's schema does not define matches nothing (and exists: false everything). Several field conditions combine with AND, OR and
NOT.
6. AnnotationView: views an application contributes #
A saved query the web apps list beside their own places ("Invoices", "Screenshots"). A view is a query, never a folder: it lists what the index answers now, so an application keeps a view current by writing fields.
| Property | Type | |
|---|---|---|
id |
Id | server-set, from the source and key |
key |
String 1–200 | the source's own key; immutable |
source |
Source | |
title |
{ <language tag>: String 1–64 } |
x-default required |
description |
{ <language tag>: String 1–200 } | null |
|
in |
"files" | "photos" |
which web app lists it |
filter |
FileNode filter | null | as FileNode/query takes it, checked by the same parser; names no account |
sort |
FileNode comparators | null | |
layout |
"list" | "grid" |
default grid |
columns |
String[] ≤ 4 | the source's shown fields, for the list layout |
AnnotationView/set(drive:annotate), at most 64 objects per call:createneedskey,titleandin; akeythe source used before updates that view and answers it as created ({ id, source }). At most 50 views per source (overQuota). A source updates and destroys its own views only (forbidden). Withdrive:write, a credential may destroy another source's view: the person removed it, and its key is refused from then on (removed). A filter or sortFileNode/querywould refuse isinvalidPropertiesnamingfilterorsort.AnnotationView/get { accountId, ids }(ids: nullfor all) and/changes; push typeAnnotationView.
7. FileNode/facets #
{ accountId, filter, facets: [{ source?, name, limit? }] } → { accountId, facets: [{ source?, name, values: [{ value, count }] }] }: for each facet,
its values among the nodes the filter matches, the most frequent first,
then by value.
- 1–10 facets;
limit1–100, default 20. - Without
source, a built-in facet:labels(every source's labels),person(face names) ortype(media type). - With
source, that source's field, which must befacet: true(invalidArgumentsotherwise). Strings group without case and show as written; numbers, booleans and dates as their values.
8. Faces and people #
8.1 PhotoFaceRegion (photo.faces) #
| Field | Type | |
|---|---|---|
id |
String | 1–32 of A–Z a–z 0–9 _ -, stable within the picture |
area |
{ x, y, w, h } |
centre and size as fractions of the picture as displayed (after orientation); x, y 0–1, w, h above 0 and at most 1 |
name |
String | null | the person's name |
nameBy |
"person" | SourceId | null |
who named it |
source |
SourceId | null | who found it; null when drawn by the person or read from the file's own metadata |
confidence |
0–1 | null | the finding source's |
hasEmbedding |
Boolean | a current embedding is kept; false to whoever lacks drive:faces |
Regions are kept in the picture's XMP sidecar as MWG regions, so other
programs (Lightroom, digiKam) show them; faces those programs wrote are
read too (source: null). A person is a name: two faces with the same name
are the same person. At most 500 regions per picture.
8.2 The person's faces: FileNode/set photo/faces #
With drive:write, the whole list as it should be, in the displayed frame:
an entry without id is drawn ({ area, name? }), one with an id is
moved (area) or named (name, null unnames), and a region left out is
removed. Server-set fields of an entry are ignored. Every region so written
is the person's: nameBy: "person" (or null unnamed), and no application
changes or removes it again.
8.3 An application's faces: FileAnnotation/set faces #
faces: [{ id?, area?, name?, confidence?, embedding? }], at most 500, on an
analysed picture, with the update's blobId guarding the content:
- The list replaces the regions this source found that no person
touched. An entry without
idis a new region (arearequired); one with theidof the source's own region is that region again (its id kept;areaandconfidencemay change); one with theidof another region only names it, and only while it is unnamed and no person touched it. - A new region overlapping one the source does not replace (intersection over union ≥ 0.5) is refused as the same face.
- A source naming a face sets
nameByto itself. embedding: { model, vector }:model1–100 characters naming the model and its version;vectorbase64 of little-endian float32, 64–1,024 dimensions, not all zero, normalised to unit length by the server. Needsdrive:faces(else the whole update isforbidden).
The answer for the node is { faces: [<faceId> | null], facesRefused: [{ at, type, description }] }: per entry, the region it is now or null, and
for each refusal at (the entry's id, or its index) and type:
type |
|
|---|---|
touchedByPerson |
the person named, moved or drew it |
alreadyNamed |
only an unnamed region may be named |
sameFace |
a region already marks this face |
notFound |
no such region on this picture |
invalid |
an area or confidence out of bounds, or a new region without an area |
An embedding is kept for the region's content; a content change drops it. Embeddings are never in the sidecar, a file, a ZIP, WebDAV or a share.
8.4 PhotoFace #
A region as an object of its own, id <nodeId>/<faceId>:
{ id, nodeId, faceId, area, name, nameBy, source, confidence, hasEmbedding, model, embedding? } — model the current embedding's model or null;
embedding (base64) only when asked for in properties and only under
drive:faces.
PhotoFace/query { accountId, filter, sort, position, limit }→ ids,total;limitdefault 256, answered aslimitwhen the request gives none. Conditions:name(exact, without case),isNamed,source,inAncestorId,updatedAfter(a picture written, or an embedding written, at or after it),similarTo: { id, minSimilarity }(needsdrive:faces; the given face must hold an embedding; default 0.6; only faces of the same model; sorted most similar first).sortis[{ property: "similarity" }]undersimilarToonly.canCalculateChangesisfalse.PhotoFace/get, ≤ 500 ids.PhotoFace/changes: over a journal of the last face changes; below its floorcannotCalculateChanges. A picture that leaves the drive is told byFileNode/changes. Push typePhotoFace.PhotoFace/set { accountId, destroyEmbeddings: true | { source }, limit }: removes embeddings (every source's, or one source's),limit1–1,000 (default 1,000) per call; answers{ accountId, destroyed, remaining }; call again untilremainingis 0. The drive's owner, ordrive:faces.
8.5 People #
PhotoPeople/get { accountId }→{ accountId, state, list: [{ name, count, coverId }] }: the distinct names of named faces, the most pictures first;coverIdis one of their faces.PhotoPeople/set { accountId, rename: { <old>: <new> | null } }(drive:write): every face named<old>(without case) is renamed as the person's write (nullunnames); a rename onto an existing name merges the two. At most 500 pictures per call:{ accountId, renamed: { <old>: n }, notRenamed, remaining }; call again untilremainingis 0.PhotoTags/get { accountId, inAncestorId?, notInAncestorIds? }→{ accountId, state, list: [{ name, count, coverId }] }: the distinct keywords of the read pictures (photo.keywords, without case) below the folderinAncestorIdand outside each folder ofnotInAncestorIds(at most 16), the most pictures first;coverIdis the most recently taken picture carrying it (a node id);stateisFileNode's. A tag's pictures:FileNode/querywithkeyword.
8.6 Names in a shared album #
Each rule of an album's share keeps or removes face names, as it does
location: album.faceNamesKeep lists the rules that keep them (a principal
id for a person, group or guest, a password rule's id, a link's own id),
default none, written by whoever may share the album (forbidden otherwise).
A reader reached through any keeping rule sees names; the owner and their
delegates always do. To a share's reader whose rules all remove them:
photo.facesanswers every region withname: nullandnameBy: null; the boxes stay (hasFacesstill finds them).personName, thepersonfacet and the face-name part ofbodyandtextfind nothing by a name in that album.- A
photo/faceswrite that names a face isforbidden; moving, drawing (unnamed) and removing boxes are taken, and a name already there is kept. PhotoFace/*,PhotoPeople/*andPhotoTags/getare a drive's own: a share's account isaccountNotSupportedByMethodfor every reader.- The picture's bytes and sidecar are served without names (and without
location when that is removed too): the ETag carries
-nonames(after-nogpswhen both go).
9. FileVector: vectors of content #
9.1 The object #
One source's vectors of one file, id <nodeId>/<sourceId>:
{ id, nodeId, source, blobId, updated, vectors: [{ model, kind, vector }] }
model: 1–100 characters naming the model and its version (clip-vit-b-32@1). Vectors of different models are never compared.kind:"image"or"text".vector: base64 of little-endian float32, 64–2,048 dimensions, not all zero, normalised to unit length by the server (answered normalised).
Vectors are not biometric: every reader of the file reads them. A content change lapses them.
9.2 Methods #
FileVector/set { accountId, update: { <nodeId>: { blobId, vectors } }, destroy: [<nodeId> | "<nodeId>/<sourceId>"] }(drive:annotate), ≤ 256 per call: an update replaces the caller's vectors of the node (≤ 4);blobIdguards as in §4.1 (contentChanged). A destroy takes the caller's vectors, or the named source's. Nocreate.FileVector/get { accountId, ids }, ≤ 500 ids.FileVector/query { accountId, filter: { model, source, inAncestorId, updatedAfter }, position, limit }→ ids sorted by id,total;limitdefault 256, answered aslimitwhen the request gives none;canCalculateChangesfalse. In a drive's own account.FileVector/changes: ids whose vectors changed (updated) or are all gone (destroyed). Push typeFileVector.
9.3 Similarity search: similarTo #
FileNode/query condition similarTo: { model, vector, minSimilarity }:
the files with a current vector of that model and dimension whose cosine
with vector is at least minSimilarity (−1–1, default 0.2), a file's best
vector counting. It combines with every other condition; sort by
similarity to get the nearest first. The query vector is the
application's: the server embeds nothing.
10. AlbumSuggestion #
| Property | Type | |
|---|---|---|
id |
Id | server-set, from the source and key |
key |
String 1–200 | the source's own key; immutable |
source |
Source | |
name |
String ≤ 255 | a valid folder name |
reason |
String ≤ 500 | null | |
photoIds |
Id[] 1–5,000 | pictures of the library (under Pictures, not in Albums); ones no longer there are left out as read |
coverId |
Id | null | one of photoIds |
state |
pending | accepted | dismissed |
|
albumId |
Id | null | the album made of it, once accepted |
created, updated |
UTCDate |
AlbumSuggestion/set(≤ 256 per call). By the source (drive:annotate):create(key,name,photoIds, optionalreason,coverId); a key it used before updates that suggestion and answers it as created;updateanddestroyof its own pending ones. A dismissed key refuses create and update withdismissed, an accepted one withaccepted: it is never offered again. At most 200 pending per source (overQuota). By the person (drive:write): an update ofstatealone (withalbumId, a folder atPictures/Albums/<name>, when accepting), on any source's suggestion. A pending suggestion left with no picture is removed by the next write.AlbumSuggestion/get(≤ 500 ids,nullfor all),/changes,/query { filter: { state, source, updatedAfter }, sort: [{ property: "created" | "updated", isAscending }] }(default newest created first),/queryChanges(answers only "no change"; elsecannotCalculateChanges). Push typeAlbumSuggestion.
11. AnnotationSource #
The sources that wrote into a drive: { id, actor, app, firstWrite, lastWrite, counts: { annotations, faces, embeddings, vectors, pendingSuggestions, views, schema } }. The counts are what the source holds
now. AnnotationSource/get { accountId, ids } (null for all) and
/changes: every source that wrote into the drive, to its owner and to a
delegate alike. Every source in a drive is its owner's: an application, an
app password and a delegate all act as the owner, marked only by the
application. Push type AnnotationSource.
12. AppData/destroy #
{ accountId, source, limit? } → { accountId, source, destroyed, remaining }:
one page of what the source added — its annotations (≤ limit, 1–256,
default 256), then its pending suggestions, its views, its faces no person
touched, its embeddings and its vectors. Call again until remaining is 0.
A source removes its own; the drive owner's web session, or the source's
own actor's, removes any source's.
13. Method errors #
type |
When |
|---|---|
unknownMethod |
the method's capability is not in using, or the credential's app password does not open it |
invalidArguments |
an argument out of its rules; the description says which |
unsupportedFilter, unsupportedSort |
an unknown condition or comparator, or one used without what it needs |
forbidden |
the credential lacks the right (description names it) |
accountNotFound |
no such account for this credential |
accountNotSupportedByMethod |
a share view for a drive-only method; a method outside the Pictures confinement |
requestTooLarge |
over a per-call limit |
stateMismatch |
ifInState is not the current state |
cannotCalculateChanges |
/changes or /queryChanges cannot answer from that state |
anchorNotFound |
a query's anchor is not in its results |
serverUnavailable |
the install keeps no such data |
14. Types and formats #
- Id: an opaque string; compare it, never parse or build it. The ids
of faces and vectors are two ids joined by
/(<nodeId>/<faceId>,<nodeId>/<sourceId>), which an application may split at the first/. - UTCDate:
2026-10-26T09:12:03Z, optional fractional seconds. - LocalDate (
photo.taken,photoTakenAfter):2026-10-14T09:12:03. - A field of type
localDateis a calendar date2026-11-15. - Vectors: standard base64 (with padding) of little-endian IEEE 754
float32,
dimensions × 4bytes.