API examples
Every request below carries the three headers from Authentication. To keep the examples short, they are in a shell array:
DRIVE=https://tj7hnhcvwir4n6rl5itdqut3mq0wdpke.lambda-url.us-east-1.on.aws
AUTH=(-H "Authorization: Bearer $MACHINE_TOKEN"
-H "x-granite-grant: $GRANT_ID"
-H "x-drive-user-context: $USER_CONTEXT")
The responses were captured from Drive’s own code under a grant with
drive.read and drive.write over the folder
6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f.
Create a file
POST /v1/files
curl "$DRIVE/v1/files" "${AUTH[@]}" -H "Content-Type: application/json" \
-d '{
"name": "shopping.md",
"content": "Apples\n",
"mime_type": "text/markdown",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f"
}'
| Field | Required | Rules |
|---|---|---|
name | Yes | Up to 255 characters. Unique within its folder. |
directory_id | Yes, under a folder grant | A folder the grant covers. |
content | No | A string, up to 300,000 bytes. |
mime_type | No | The file’s type. |
tags | No | Up to 50 strings of up to 80 characters. |
201 Created:
{
"content": "Apples\n",
"content_hash": "sha256:d14cbe5383b698ced713c1325292e005a85a051cb10d969893d60fde2ec32c53",
"created_at": "2026-11-05T20:40:14.87202439Z",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f",
"id": "9327802d-b5d8-42e7-a6d5-61d31ffaf600",
"mime_type": "text/markdown",
"name": "shopping.md",
"owner_uid": "usr_7Hq2mV9cXk4tR1pB",
"size_bytes": 7,
"tags": [],
"updated_at": "2026-11-05T20:40:14.87202439Z",
"version": 1
}
owner_uid is the person’s Drive id. It is the same for every app the person
uses.
List files
GET /v1/files lists the files your grant covers that are not in the trash.
Filter with ?directory_id=<folder id> or ?tag=<tag>. Entries carry no
content; read a file by id for that.
curl "$DRIVE/v1/files?directory_id=6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f" "${AUTH[@]}"
[
{
"content_hash": "sha256:d14cbe5383b698ced713c1325292e005a85a051cb10d969893d60fde2ec32c53",
"created_at": "2026-11-05T20:40:14.87202439Z",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f",
"id": "9327802d-b5d8-42e7-a6d5-61d31ffaf600",
"mime_type": "text/markdown",
"name": "shopping.md",
"owner_uid": "usr_7Hq2mV9cXk4tR1pB",
"size_bytes": 7,
"tags": [],
"updated_at": "2026-11-05T20:40:14.87202439Z",
"version": 1
}
]
Read a file
GET /v1/files/{id} returns the file with its content, in the same shape
as Create a file.
A file the person uploaded in the Drive app may be larger than the 300,000
byte limit for text content; its response has no content. Reading such
files from an app is not covered by these pages.
Update a file
PATCH /v1/files/{id} changes any of name, content, mime_type, tags
and directory_id (to move it to another folder your grant covers). Send the
version you last read as expected_version:
curl -X PATCH "$DRIVE/v1/files/9327802d-b5d8-42e7-a6d5-61d31ffaf600" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{"expected_version": 1, "content": "Apples\nPears\n"}'
200 OK:
{
"content": "Apples\nPears\n",
"content_hash": "sha256:85aec20b7cdcd332697e548f15fde71522f8aff36413f786e4a8261cc7676c35",
"created_at": "2026-11-05T20:40:14.87202439Z",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f",
"id": "9327802d-b5d8-42e7-a6d5-61d31ffaf600",
"mime_type": "text/markdown",
"name": "shopping.md",
"owner_uid": "usr_7Hq2mV9cXk4tR1pB",
"size_bytes": 13,
"tags": [],
"updated_at": "2026-11-05T20:40:15.219403584Z",
"version": 2
}
If the file has changed since (someone else wrote version 2 first), the update
is refused and nothing is written. Read the file again and retry.
409 Conflict:
{"error": "file version mismatch"}
Earlier versions
Each update keeps the previous version. GET /v1/files/{id}/revisions lists
them, without content:
[
{
"content_hash": "sha256:d14cbe5383b698ced713c1325292e005a85a051cb10d969893d60fde2ec32c53",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f",
"file_created_at": "2026-11-05T20:40:14.87202439Z",
"file_id": "9327802d-b5d8-42e7-a6d5-61d31ffaf600",
"file_updated_at": "2026-11-05T20:40:14.87202439Z",
"mime_type": "text/markdown",
"name": "shopping.md",
"owner_uid": "usr_7Hq2mV9cXk4tR1pB",
"preserved_at": "2026-11-05T20:40:15.219403584Z",
"size_bytes": 7,
"tags": [],
"version": 1
}
]
To bring one back, POST /v1/files/{id}/revisions/{version}/restore with the
current version:
curl "$DRIVE/v1/files/9327802d-b5d8-42e7-a6d5-61d31ffaf600/revisions/1/restore" "${AUTH[@]}" \
-H "Content-Type: application/json" -d '{"expected_current_version": 2}'
The restore is a new version (here 3) with the old content; it returns the
file.
Trash and restore
POST /v1/files/{id}/archive (no body) moves a file to the person’s trash.
It returns the file with archived_at and archived_by set:
{
"archived_at": "2026-11-05T20:40:15.50659191Z",
"archived_by": {
"kind": "agent_run",
"uid": "usr_7Hq2mV9cXk4tR1pB"
},
"content": "Apples\n",
"content_hash": "sha256:d14cbe5383b698ced713c1325292e005a85a051cb10d969893d60fde2ec32c53",
"created_at": "2026-11-05T20:40:14.87202439Z",
"directory_id": "6f1c2a9e-4b7d-5e3a-9c8f-0d2e4a6b8c1f",
"id": "9327802d-b5d8-42e7-a6d5-61d31ffaf600",
"mime_type": "text/markdown",
"name": "shopping.md",
"owner_uid": "usr_7Hq2mV9cXk4tR1pB",
"size_bytes": 7,
"tags": [],
"updated_at": "2026-11-05T20:40:15.50659191Z",
"version": 4
}
kind is agent_run when an app moved the file. GET /v1/files/archived
lists the trashed files your grant covers, and
POST /v1/files/{id}/restore (no body) takes one out of the trash.
Deleting
Apps can’t permanently delete files: DELETE /v1/files/{id} returns 403
to an app. Move the file to the trash; the person can delete it from there in
the Drive app.