Reading
Everything on this page needs the foldr.read scope (and profile for getMe), and works on exactly what the person can see in Foldr.
Who am I: getMe
Section titled “Who am I: getMe”curl -s -H "Authorization: Bearer $TOKEN" $FOLDR/api/v1/mename is the display name (or the sign-in name where there’s none), email is null where the directory has none, and username is the sign-in name. Needs the profile scope.
Shares: listShares, getShare
Section titled “Shares: listShares, getShare”A share is a storage location the person can read: a folder on a file server, a bucket, a SharePoint library, a Google Drive, and so on.
curl -s -H "Authorization: Bearer $TOKEN" "$FOLDR/api/v1/shares?limit=50"{ "items": [ { "id": "01a11dce-14f0-7f23-b857-c621356097a0", "name": "Finance", "type": "smb", "indexed": true, "read_only": false, "reachable": true } ], "next_cursor": null, "truncated": false}| Field | |
|---|---|
id | The share’s id, always a UUID. Use it in every other call. |
name | The name people see in Foldr. |
type | The kind of storage: smb, local, hosted, s3, b2, azure_blob, sftp, ftp, webdav, edge, google_drive, google_shared_drive, group_drive, onedrive, sharepoint, teams, dropbox, box or other. The list is open: treat a value you don’t know as other. |
indexed | Whether the share can be searched with search. |
read_only | true when the person can’t change anything in the share. |
reachable | false when the share’s file server couldn’t be reached just now. It still exists and is the person’s; try again in a few minutes. Unreachable shares are listed after the rest. |
getShare(GET /shares/{share_id}) returns one share. A share that doesn’t exist and a share that isn’t the person’s get exactly the same404.- A share that opens only with the person’s own password isn’t listed, because a token carries no password. See Getting access.
- A share the person can read isn’t necessarily one your app may change: check
read_only, and remember that an app’s policy decides where it can make changes.
Listing a folder: listChildren
Section titled “Listing a folder: listChildren”curl -s -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/shares/$SHARE/children" \ --data-urlencode "path=/Reports" --data-urlencode "limit=100"{ "items": [ { "share_id": "01a11dce-14f0-7f23-b857-c621356097a0", "path": "/Reports/2026", "name": "2026", "kind": "folder", "size": null, "modified": "2026-10-08T23:16:47Z", "mime_type": null, "export": null, "etag": "W/\"d-1791501407\"", "read_only": false, "checked_out": null }, { "share_id": "01a11dce-14f0-7f23-b857-c621356097a0", "path": "/Reports/Q3.xlsx", "name": "Q3.xlsx", "kind": "file", "size": 48213, "modified": "2026-10-07T09:02:11Z", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "export": null, "etag": "\"3a5f9c1d7e\"", "read_only": false, "checked_out": null } ], "next_cursor": null, "truncated": false}Folders come first, then everything by name. path omitted, empty or / is the top of the share. A file instead of a folder is 409 not-a-folder.
An item has these fields, all always present:
| Field | |
|---|---|
share_id, path, name | Where it is. path is the canonical path (see Conventions); name is its last segment. |
kind | file or folder. |
size | Bytes. null for a folder, and for an item with no fixed size (a native Google document). |
modified | When it was last modified, where the storage says; otherwise null. |
mime_type | The storage’s media type, or one guessed from the name. null for a folder. |
export | For a native Google document that can be downloaded: { "mime_type": ..., "extension": ... }, what getContent will deliver (a Google Doc comes down as a docx). null for everything else. |
etag | The item’s entity tag. See Conventions. |
read_only | true when the person can’t change things in this share. |
checked_out | Who has the item checked out, as { "by": { "id", "name" }, "since" }, or null. |
Paging, the one-minute snapshot and the 25,000-entry limit are described under Pagination. Two things to remember in particular: a listing is a snapshot, so use getItem for the truth about one item; and a truncated: true listing is not the whole folder.
One item: getItem
Section titled “One item: getItem”curl -s -i -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/shares/$SHARE/item" --data-urlencode "path=/Reports/Q3.xlsx"The answer is the item above, with its ETag also in the ETag header. This is the call to make before you change something: it gives the live ETag. Send that ETag back as If-None-Match on a later call to get 304 while it hasn’t changed.
Downloading: getContent, getDownloadUrl
Section titled “Downloading: getContent, getDownloadUrl”curl -s -H "Authorization: Bearer $TOKEN" -o Q3.xlsx -G \ "$FOLDR/api/v1/shares/$SHARE/content" --data-urlencode "path=/Reports/Q3.xlsx"The body is the file’s bytes, with the file’s own Content-Type, Content-Disposition: attachment; filename*=... (UTF-8) and its ETag.
- Ranges. Send
Range: bytes=0-1023and, where the storage can seek, you get206withContent-Range. Where it can’t, you get200with the whole file. Use ranges to resume an interrupted download. A range that runs past the end is cut short, as HTTP says. - Conditional.
If-None-Matchwith the file’s ETag answers304while it’s unchanged. - A folder is
409 not-a-file. - A label that blocks download is
403 download-blocked. This is checked before any redirect.
Redirects to direct download
Section titled “Redirects to direct download”On a share set up for direct downloads (a setting on the share, which Foldr Cloud turns on for storage that supports it), getContent answers 302 with a Location pointing straight at the storage, so the bytes don’t pass through Foldr. That URL is a short-lived credential of its own.
- Follow the redirect without your Foldr token. Your HTTP client must not send
Authorizationto the storage host; most clients drop it for a redirect to a different host, but check yours (curl’s-Ldoes;--location-trusteddoesn’t). - Don’t log the URL or hand it to anyone else.
?direct=falsekeeps the bytes coming through Foldr instead.- A redirect counts as the download.
If your platform can’t follow a redirect to another host (some connector tools can’t), ask for the URL yourself with getDownloadUrl and fetch it as a separate step:
curl -s -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/shares/$SHARE/download-url" --data-urlencode "path=/Reports/Q3.xlsx"{ "url": "https://storage.example.net/...", "expires_at": "2026-10-08T23:32:11Z" }expires_at is a floor: the URL works until at least then, and some storage keeps it working longer. A share without direct downloads answers 409 no-direct-download; use getContent there. The same download rules apply (download-blocked, and so on).
Native Google documents
Section titled “Native Google documents”A Google Doc, Sheet, Slides or Drawing has no bytes of its own. getContent exports it: the answer’s Content-Type is export.mime_type and Content-Disposition names it with export.extension (Minutes.docx). Because the length isn’t known until it has been sent, there’s no Content-Length and no range support (Accept-Ranges: none; a Range is answered 200, whole), and it always comes through Foldr, never as a redirect. A Google type with no export, a Form, is 409 not-downloadable. Its name and path stay as stored, without the extension.
Search: search
Section titled “Search: search”curl -s -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/search" \ --data-urlencode "q=quarterly forecast" --data-urlencode "limit=20"{ "items": [ { "item": { "share_id": "...", "path": "/Reports/Q3.xlsx", "name": "Q3.xlsx", "kind": "file", "size": 48213, "modified": "2026-10-07T09:02:11Z", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "export": null, "etag": null, "read_only": false, "checked_out": null }, "score": 7.42, "snippet": "... the quarterly forecast for Q3 assumes ..." } ], "next_cursor": "...", "total_estimate": 134, "not_searched": [ { "share_id": "...", "name": "Archive", "reason": "unreachable" } ]}qis required: the words to search for, at most 500 characters.share_idlimits the search to one share.limitis 20 by default and at most 50.- It’s a keyword search over the shares the person can see, and respects their permissions. Only indexed shares are searched (
indexedon the share). It does not call an AI model. - A hit’s
itemcomes from the search index, so itsetagandchecked_outarenull; callgetItemfor the live values.scoreis only comparable within one response.snippetis a short passage around the match, where there is one and it may be shown. - Pages. Pass
next_cursorback with the sameqandshare_id. Where the person’s shares sit in more than one search index, pages walk the indexes one after another, so a page can have fewer hits thanlimitand still not be the last.total_estimateis only an estimate. not_searchednames shares the search couldn’t cover and why:unreachable(its file server is down),not-indexed(it isn’t indexed) orindex-unavailable(its search index didn’t answer). The list of reasons is open. If a search comes back thin, check this before concluding that nothing matches.searchcosts 3 on your rate budget.
Custom fields: listFields, getFieldValues
Section titled “Custom fields: listFields, getFieldValues”Foldr lets organisations record extra information (custom fields) on files. listFields (GET /fields) returns, as a plain array, the fields the person can see:
[ { "id": "5b3f...", "name": "Status", "type": "select", "options": ["Draft", "Approved"], "multiple": false, "read_only": false }]type is one of string, text, number, bool, date, location, select, signature, delegate; the list is open. options is the list of allowed values where the field has one, otherwise null. read_only is true when the person can’t set the field on any of their shares.
getFieldValues returns the values on one file or folder:
curl -s -i -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/shares/$SHARE/field-values" --data-urlencode "path=/Reports/Q3.xlsx"[ { "field_id": "5b3f...", "value": "Approved", "updated_at": "2026-10-07T09:10:02Z", "updated_by": { "id": "8f2c1d4e-...", "name": "Alex Morgan" } }]A field that holds several values appears once for each value. value is a string, a number or a boolean according to the field’s type; a location is an object. updated_by is null where it isn’t known. Only the fields the person is allowed to see on that share are included. The ETag header covers the whole set: send it as If-None-Match to get 304, and as If-Match when you set a value.
Versions: listVersions
Section titled “Versions: listVersions”curl -s -G -H "Authorization: Bearer $TOKEN" \ "$FOLDR/api/v1/shares/$SHARE/versions" --data-urlencode "path=/Reports/Q3.xlsx"{ "items": [ { "id": "3HL4kqtJvjVBH_QUKNd.Fb3NUi", "modified": "2026-10-07T09:02:11Z", "size": 48213, "current": true }, { "id": "mBLNn8a.dZS0QpWuxkmW3J_FT.", "modified": "2026-10-05T16:40:30Z", "size": 47902, "current": false } ], "next_cursor": null, "truncated": false}The versions of a file that its storage keeps, newest first, all on one page. They are earlier saves (Foldr’s own hosted storage, S3 and Azure where versioning is on, SharePoint) or an SMB server’s shadow copies (“Previous Versions”). Storage that keeps none answers an empty list, and so does a person who lacks the share’s List versions permission, so an empty list doesn’t prove there are no versions. The id is what restoreVersion takes; it’s opaque. Someone who may only read the approved version of a published file is shown that version alone. listVersions costs 2.
Listing versions is a read (foldr.read); putting one back is a change that needs files.overwrite.