Solel//dev docs

Files

The core keeps everyone's files, so Files, Photos, Mail and your app all see the same ones. Your back end reaches them through the core's files API, acting for the person using the app.

Grants

  • files.read lets your app read and list: GET and HEAD requests.
  • files.write lets it do everything else: write, move, copy, delete, star and share.

Call with your token and the person in X-Solel-Person, as Acting for a person describes:

curl -sS "$SOLEL_CORE_URL/api/files/me/?list" \
  -H "Authorization: Bearer $SOLEL_APP_TOKEN" \
  -H "X-Solel-Person: $PERSON"

Spaces and paths

  • Spaces. me is the person's own space. group:<id> is a household group's space. share:<id> is something shared with them, with the thing itself at the path "".
  • What they see. Your app sees only what the person does: their own space, their groups' spaces and what's shared with them. Roles don't widen it, and a child sees only what's shared with them. See Your space and shared spaces.
  • Paths are names joined by /, with no leading or trailing slash, and "" is the whole space. A name can't be . or .., hold a slash or a control character, start or end with a space, or be over 255 bytes. Folders a file goes into are made as it's written.

Keeping an index

To keep up without walking the tree, as Photos does, call GET /api/files/changes for a cursor, list what's there, then ask GET /api/files/changes?since=<cursor> now and then. Each page has up to 500 changes and says if there are more. A folder that arrives in one go, by a move, a copy or a restore, comes as one created change, so list it to see what's inside.

An entry

{
  "name": "IMG_0412.jpg", "path": "Photos/2026/10/IMG_0412.jpg", "kind": "file",
  "size": 3481220, "modified": "2026-10-20T09:12:03Z", "type": "image/jpeg",
  "etag": "<sha256 of the file>", "starred": false,
  "sharedWith": [{ "groupId": "…", "name": "Grown-ups", "access": "see" }]
}

Folders have a size of 0, a type of "", no etag, and items, how many things they hold. sharedWith is shown only to the owner.

Endpoints

Method and path What it does
GET /api/files The person's spaces, how much is in them, and the disk's room
GET /api/files/{space}/{path}?list What's in a folder. The whole of a space is /api/files/me/?list
GET /api/files/{space}/{path}?info One entry, and what the person can do with it
GET /api/files/{space}/{path} The file. ?inline shows pictures, video, sound, PDFs and text in place. Ranges work
PUT /api/files/{space}/{path} Writes the file from the body. If-None-Match: * won't replace one; If-Match: "<etag>" replaces only that one. 201 new, 200 replaced, 507 when it doesn't fit
POST …?mkdir Makes a folder
POST …?move, POST …?copy {"space": "me", "path": "New/place"}. Nothing at the new path is replaced
POST …?star, POST …?unstar Stars it, for that person alone
GET …?versions, POST …?restore Earlier versions, and {"version": "<id>"} to bring one back
GET …?shares, POST …?share Who it's shared with, and {"shares": [{"personId" or "groupId": "…", "access": "see" or "change"}], "notify": true} to set that
DELETE /api/files/{space}/{path} Moves it to the Trash
GET /api/files/people Who the person can share with
GET /api/files/shared, GET /api/files/shared-by-me What's shared with them, and what they share
GET /api/files/recent, GET /api/files/starred What they added or changed lately, and what they starred
GET /api/files/search?q= Up to 100 names with q in them
GET /api/files/changes?since=&space= The log of changes
GET /api/files/trash, DELETE /api/files/trash The Trash, and emptying it
POST /api/files/trash/{id}/restore, DELETE /api/files/trash/{id} Restoring something, or deleting it for good

Every POST takes JSON, even an empty {}. A changed file answers 412 when its If-Match no longer matches. Downloads come with Content-Security-Policy: sandbox, so a file never runs as part of Solel's own pages.