Skip to content

Table of contents

Virtual File System

Cozy applications can use files for storing binary content, like photos or bills in PDF. This service offers a REST API to manipulate easily without having to know the underlying storage layer. The metadata are kept in CouchDB, but the binaries can go to the local system, or a Swift instance.

Directories

A directory is a container for files and sub-directories.

Its path is the path of its parent, a slash (/), and its name. It’s case sensitive.

Root directory

The root of the virtual file system is a special directory with id io.cozy.files.root-dir.

You can use it in any request where you would use a directory, except you cannot delete it.

POST /files/:dir-id

Create a new directory. The dir-id parameter is optional. When it’s not given, the directory is created at the root of the virtual file system.

Query-String

Parameter Description
Type directory
Name the directory name
Tags an array of tags
CreatedAt the creation date
MetadataID the identifier of a metadata object

HTTP headers

Parameter Description
Date The modification date of the directory

Request

POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=directory&Name=phone&Tags=bills,konnectors HTTP/1.1
Accept: application/vnd.api+json
Date: Mon, 19 Sep 2016 12:35:08 GMT

Status codes

  • 201 Created, when the directory has been successfully created
  • 404 Not Found, when the parent directory does not exist
  • 409 Conflict, when a directory with the same name already exists
  • 422 Unprocessable Entity, when the Type, Name, or MetadataID parameter is missing or invalid

Response

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
Location: https://cozy.example.com/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee
{
  "data": {
    "type": "io.cozy.files",
    "id": "6494e0ac-dfcb-11e5-88c1-472e84a9cbee",
    "meta": {
      "rev": "1-ff3beeb456eb"
    },
    "attributes": {
      "type": "directory",
      "name": "phone",
      "path": "/Documents/phone",
      "created_at": "2016-09-19T12:35:08Z",
      "updated_at": "2016-09-19T12:35:08Z",
      "tags": ["bills", "konnectors"],
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:48Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-20T18:32:48Z"
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        }
      },
      "not_synchronized_on": {
        "links": {
          "self": "/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on"
        },
        "data": [
          {
            "type": "io.cozy.oauth.clients",
            "id": "653dfdb0-0595-0139-92df-543d7eb8149c"
          }
        ]
      }
    },
    "links": {
      "self": "/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee"
    }
  }
}

Note: see not synchronized directories for more informations about the not_synchronized_on field.

GET /files/:file-id

Get a directory or a file informations. In the case of a directory, it contains the list of files and sub-directories inside it. For a note, its images are included.

Contents is paginated following jsonapi conventions. The default limit is 30 entries.

Request

GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP/1.1
Accept: application/vnd.api+json

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "links": {
    "next": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?page[cursor]=9152d568-7e7c-11e6-a377-37cbfb190b4b"
  },
  "data": {
    "type": "io.cozy.files",
    "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81",
    "meta": {
      "rev": "1-e36ab092"
    },
    "attributes": {
      "type": "directory",
      "name": "Documents",
      "path": "/Documents",
      "created_at": "2016-09-19T12:35:00Z",
      "updated_at": "2016-09-19T12:35:00Z",
      "tags": [],
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:47Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-20T18:32:47Z"
      }
    },
    "relationships": {
      "contents": {
        "data": [
          {
            "type": "io.cozy.files",
            "id": "6494e0ac-dfcb-11e5-88c1-472e84a9cbee"
          },
          {
            "type": "io.cozy.files",
            "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b"
          }
        ]
      }
    },
    "links": {
      "self": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
    }
  },
  "included": [
    {
      "type": "io.cozy.files",
      "id": "6494e0ac-dfcb-11e5-88c1-472e84a9cbee",
      "meta": {
        "rev": "1-ff3beeb456eb"
      },
      "attributes": {
        "type": "directory",
        "name": "phone",
        "path": "/Documents/phone",
        "created_at": "2016-09-19T12:35:08Z",
        "updated_at": "2016-09-19T12:35:08Z",
        "tags": ["bills", "konnectors"],
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:32:47Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:32:47Z"
        }
      },
      "relationships": {
        "parent": {
          "links": {
            "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
          },
          "data": {
            "type": "io.cozy.files",
            "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
          }
        }
      },
      "links": {
        "self": "/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee"
      }
    },
    {
      "type": "io.cozy.files",
      "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
      "meta": {
        "rev": "1-0e6d5b72"
      },
      "attributes": {
        "type": "file",
        "name": "hello.txt",
        "trashed": false,
        "md5sum": "ODZmYjI2OWQxOTBkMmM4NQo=",
        "created_at": "2016-09-19T12:38:04Z",
        "updated_at": "2016-09-19T12:38:04Z",
        "tags": [],
        "size": 12,
        "executable": false,
        "class": "document",
        "mime": "text/plain",
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:32:49Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:32:49Z",
          "uploadedAt": "2016-09-20T18:32:49Z",
          "uploadedOn": "https://cozy.example.com/",
          "uploadedBy": {
            "slug": "drive"
          }
        }
      },
      "relationships": {
        "parent": {
          "links": {
            "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
          },
          "data": {
            "type": "io.cozy.files",
            "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
          }
        }
      },
      "links": {
        "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b"
      }
    }
  ]
}

GET /files/:file-id/size

This endpoint returns the size taken by the files in a directory, including those in subdirectories.

Request

GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/size HTTP/1.1
Accept: application/vnd.api+json

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.sizes",
    "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81",
    "attributes": {
      "size": "1234567890"
    },
    "meta": {}
  }
}

GET /files/_changes

This endpoint is similar to the changes feed of CouchDB for io.cozy.files. There are a few specificities:

  • it is wrapped in the VFS lock to avoid seeing inconsistent results
  • it automatically skips design docs
  • if the requests is coming from an OAuth client, it excludes the files and directories that are in a not synchronized folder
  • it only supports the options since, limit, and include_docs of CouchDB
  • it has an option fields to only include those fields in the results
  • it has an option include_file_path to add the path for files
  • it has two options skip_deleted and skip_trashed to not send to the client the deleted/trashed files and directories.

Request

GET /files/_changes?include_docs=true&fields=type,name,dir_id&skip_deleted=true&limit=3 HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "last_seq": "13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A",
  "pending": 24,
  "results": [
    {
      "id": "io.cozy.files.root-dir",
      "seq": "11-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTuXKAQe5Jpmrl5ojG68iwA2IcV0g",
      "doc": {
        "type": "directory"
      },
      "changes": [
        {
          "rev": "1-077f26acac6f0a5e1022f109e8d1dfc4"
        }
      ]
    },
    {
      "id": "io.cozy.files.trash-dir",
      "seq": "12-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kSeXKAQe5Jpmrl5ojG68iwA2KUV0w",
      "doc": {
        "dir_id": "io.cozy.files.root-dir",
        "name": ".cozy_trash",
        "type": "directory"
      },
      "changes": [
        {
          "rev": "1-de9c11dbc386b5f91adbe2aee4a3e754"
        }
      ]
    },
    {
      "id": "d30b0dd6e0e8fefdac2a94cb2c00249f",
      "seq": "13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A",
      "doc": {
        "dir_id": "io.cozy.files.root-dir",
        "name": "Administratif",
        "type": "directory"
      },
      "changes": [
        {
          "rev": "1-24f2828e8dbe64135913072a4c92d846"
        }
      ]
    }
  ]
}

POST /files/_find

Find allows to find documents using a mango selector. You can read more about mango selectors here.

Note that it returns a bookmark in the links, useful to paginate (following the JSON-API pagination). On the last page, there won’t be a links.next.

It is possible to pass a execution_stats parameter to get some information about the query execution. See here for more details.

Request

POST /files/_find HTTP/1.1
{
    "selector": {
        "class": "image",
        "trashed": false
    },
    "limit": 2,
    "bookmark": "g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGpibWhiA9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA7IYZzA",
    "use_index": "_design/a5f4711fc9448864a13c81dc71e660b524d7410c",
    "execution_stats": true
}

Response

HTTP/1.1 200 OK
Date: Mon, 27 Sept 2016 12:28:53 GMT
Content-Length: ...
Content-Type: application/json
{
  "data": [
    {
      "type": "io.cozy.files",
      "id": "e8c1561846c730428180a5f6c6107914",
      "attributes": {
        "type": "file",
        "name": "nicepic1.jpg",
        "dir_id": "f49b4087cbf946dfc759214394009a6c",
        "created_at": "2020-02-13T16:35:47.568155477+01:00",
        "updated_at": "2020-02-13T16:35:47.568155477+01:00",
        "size": "345385",
        "md5sum": "12cGYwT+RiNjFxf4f7AmzQ==",
        "mime": "image/jpeg",
        "class": "image",
        "executable": false,
        "trashed": false,
        "tags": [],
        "path": "/Pictures/nicepic1.jpg",
        "metadata": {
          "datetime": "2020-02-13T16:35:47.568155477+01:00",
          "extractor_version": 2,
          "height": 1080,
          "width": 1920
        }
      },
      "meta": {
        "rev": "2-235e715b1d82a93285be1b0bd691b779"
      },
      "links": {
        "self": "/files/e8c1561846c730428180a5f6c6107914",
        "tiny": "/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/tiny",
        "small": "/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/small",
        "medium": "/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/medium",
        "large": "/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/large"
      },
      "relationships": {
        "parent": {
          "links": {
            "related": "/files/f49b4087cbf946dfc759214394009a6c"
          },
          "data": {
            "id": "f49b4087cbf946dfc759214394009a6c",
            "type": "io.cozy.files"
          }
        }
      }
    },
    {
      "type": "io.cozy.files",
      "id": "e8c1561846c730428180a5f6c6109007",
      "attributes": {
        "type": "file",
        "name": "nicepic2.jpg",
        "dir_id": "f49b4087cbf946dfc759214394009a6c",
        "created_at": "2020-02-13T16:35:47.845049743+01:00",
        "updated_at": "2020-02-13T16:35:47.845049743+01:00",
        "size": "323009",
        "md5sum": "Fla3ucNXuW2Xw/TK8pfsPA==",
        "mime": "image/jpeg",
        "class": "image",
        "executable": false,
        "trashed": false,
        "tags": [],
        "path": "/Pictures/nicepic2.jpg",
        "metadata": {
          "datetime": "2020-02-13T16:35:47.845049743+01:00",
          "extractor_version": 2,
          "height": 1080,
          "width": 1920
        }
      },
      "meta": {
        "rev": "2-4883d6b8ccad32f8fb056af9b7f8b37f"
      },
      "links": {
        "self": "/files/e8c1561846c730428180a5f6c6109007",
        "tiny": "/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/tiny",
        "small": "/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/small",
        "medium": "/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/medium",
        "large": "/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/large"
      },
      "relationships": {
        "parent": {
          "links": {
            "related": "/files/f49b4087cbf946dfc759214394009a6c"
          },
          "data": {
            "id": "f49b4087cbf946dfc759214394009a6c",
            "type": "io.cozy.files"
          }
        }
      }
    }
  ],
  "links": {
    "next": "/files/_find?page[cursor]=g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGlgaGJiD9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA694ZyA"
  },
  "meta": {
    "count": 2,
    "execution_stats": {
      "total_docs_examined": 11,
      "results_returned": 2,
      "execution_time_ms": 8.833
    }
  }
}

DELETE /files/:dir-id

Put a directory and its subtree in the trash. It requires the permissions on io.cozy.files for PATCH.

HTTP headers

It’s possible to send the If-Match header, with the previous revision of the file/directory (optional).

Files

A file is a binary content with some metadata.

POST /files/:dir-id

Upload a file in the directory identified by :dir-id.

The created_at field will be the first valid value in this list:

  • the datetime extracted from the EXIF for a photo
  • the CreatedAt parameter from the query-string
  • the Date HTTP header
  • the current time from the server.

The updated_at field will be the first value in this list:

  • the datetime extracted from the EXIF for a photo if it is greater than the other values
  • the UpdatedAt parameter from the query-string
  • the Date HTTP header
  • the current time from the server.

/!\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at.

Query-String

Parameter Description
Type file
Name the file name
Size the file size (when Content-Length can’t be used)
Tags an array of tags
Executable true if the file is executable (UNIX permission)
Encrypted true if the file is client-side encrypted
Metadata a JSON with metadata on this file (not recommended)
MetadataID the identifier of a metadata object
CreatedAt the creation date of the file
UpdatedAt the modification date of the file
SourceAccount the id of the source account used by a konnector
SourceAccountIdentifier the unique identifier of the account targeted by the connector

HTTP headers

Parameter Description
Content-Length The file size
Content-MD5 A Base64-encoded binary MD5 sum of the file
Content-Type The mime-type of the file
Date The modification date of the file

Request

POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=file&Name=hello.txt&CreatedAt=2016-09-18T01:23:45Z HTTP/1.1
Accept: application/vnd.api+json
Content-Length: 12
Content-MD5: hvsmnRkNLIX24EaM7KQqIA==
Content-Type: text/plain
Date: Mon, 19 Sep 2016 12:38:04 GMT
Host: cozy.example.com

Hello world!

Status codes

  • 201 Created, when the file has been successfully created
  • 404 Not Found, when the parent directory does not exist
  • 409 Conflict, when a file with the same name already exists
  • 412 Precondition Failed, when the md5sum is Content-MD5 is not equal to the md5sum computed by the server
  • 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server’s filesystem maximum file size
  • 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn’t exist, Type, Name, or MetadataID parameter is missing or invalid, etc.)

Response

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
Location: https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b
{
  "data": {
    "type": "io.cozy.files",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    "meta": {
      "rev": "4-1482b88a"
    },
    "attributes": {
      "type": "file",
      "name": "sunset.jpg",
      "trashed": false,
      "md5sum": "ODZmYjI2OWQxOTBkMmM4NQo=",
      "created_at": "2016-09-18T20:38:04Z",
      "updated_at": "2016-09-21T12:38:04Z",
      "tags": [],
      "metadata": {
        "datetime": "2016-09-18T20:38:04Z",
        "height": 1080,
        "width": 1920
      },
      "size": 12,
      "executable": false,
      "class": "image",
      "mime": "image/jpg",
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:49Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-21T14:46:37Z",
        "uploadedAt": "2016-09-20T18:37:52Z",
        "uploadedOn": "https://cozy.example.com/",
        "uploadedBy": {
          "slug": "drive"
        }
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        }
      },
      "referenced_by": {
        "links": {
          "self": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references"
        },
        "data": [
          {
            "type": "io.cozy.albums",
            "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4"
          }
        ]
      },
      "old_versions": {
        "data": [
          {
            "type": "io.cozy.files.versions",
            "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec"
          },
          {
            "type": "io.cozy.files.versions",
            "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72"
          }
        ]
      }
    },
    "links": {
      "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b",
      "tiny": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/tiny",
      "small": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/small",
      "medium": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/medium",
      "large": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/large"
    }
  },
  "included": [
    {
      "type": "io.cozy.files.versions",
      "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec",
      "meta": {
        "rev": "1-26a331"
      },
      "attributes": {
        "file_id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
        "updated_at": "2016-09-21T10:11:12Z",
        "md5sum": "a2lth5syMW+4r7jwNhdk3A==",
        "size": 123456,
        "tags": [],
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:37:52Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:37:52Z",
          "uploadedAt": "2016-09-20T18:37:52Z",
          "uploadedOn": "https://cozy.example.com/",
          "uploadedBy": {
            "slug": "drive"
          }
        }
      }
    },
    {
      "type": "io.cozy.files.versions",
      "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72",
      "meta": {
        "rev": "1-57b3e2"
      },
      "attributes": {
        "file_id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
        "updated_at": "2016-09-18T20:38:04Z",
        "md5sum": "FBA89XXOZKFhdv37iILb2Q==",
        "size": 159753,
        "tags": [],
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:32:49Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:32:49Z",
          "uploadedAt": "2016-09-20T18:32:49Z",
          "uploadedOn": "https://cozy.example.com/",
          "uploadedBy": {
            "slug": "drive"
          }
        }
      }
    }
  ]
}

Note: see references of documents in VFS for more informations about the references field.

POST /files/upload/metadata

Send a metadata object that can be associated to a file (or directory) uploaded after that, via the MetadataID query parameter. The MetadataID parameter is only valid for 10 minutes, and will expire after that.

Note: a special permission on io.cozy.certified.carbon_copy is required to send a request with carbonCopy as key in the attributes map. Same for electronicSafe.

See the metadata doctype to know more about metadata attributes that can be set, notably for images and document qualification.

Request

POST /files/upload/metadata HTTP/1.1
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.metadata",
    "attributes": {
      "qualification": {
        "label": "telecom_invoice",
        "purpose": "invoice",
        "sourceCategory": "telecom"
      },
      "datetime": "2017-04-22T01:00:00-05:00"
    }
  }
}

Response

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.metadata",
    "id": "42E6BD48",
    "attributes": {
      "qualification": {
        "label": "telecom_invoice",
        "purpose": "invoice",
        "sourceCategory": "telecom"
      },
      "datetime": "2017-04-22T01:00:00-05:00"
    }
  }
}

GET /files/download/:file-id

Download the file content.

By default the content-disposition will be inline, but it will be attachment if the query string contains the parameter Dl=1

Request

GET /files/download/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Length: 12
Content-Disposition: inline; filename="hello.txt"
Content-Type: text/plain

Hello world!

GET /files/download

Download the file content from its path.

By default the content-disposition will be inline, but it will be attachment if the query string contains the parameter Dl=1

Request

GET /files/download?Path=/Documents/hello.txt&Dl=1 HTTP/1.1

GET /files/:file-id/thumbnails/:secret/:format

Get a thumbnail of a file (for an image & pdf only). :format can be tiny (96x96) small (640x480), medium (1280x720), or large (1920x1080).

This API does not require authentication because the secret acts as a token. This secret is valid for 10 minutes, after which the link will return an error. To retrieve a new functional link, you must query the files API again to obtain a new secret.

PUT /files/:file-id

Overwrite a file

The updated_at field will be the first value in this list:

  • the datetime extracted from the EXIF for a photo if it is greater than the other values
  • the UpdatedAt parameter from the query-string
  • the Date HTTP header
  • the current time from the server.

/!\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at.

Query-String

Parameter Description
Size the file size (when Content-Length can’t be used)
Tags an array of tags
Executable true if the file is executable (UNIX permission)
Encrypted true if the file is client-side encrypted
MetadataID the identifier of a metadata object
UpdatedAt the modification date of the file
SourceAccount the id of the source account used by a konnector
SourceAccountIdentifier the unique identifier of the account targeted by the connector

HTTP headers

The HTTP headers are the same than for uploading a file. There is one additional header, If-Match, with the previous revision of the file (optional).

Request

PUT /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP/1.1
Accept: application/vnd.api+json
Content-Length: 12
Content-MD5: hvsmnRkNLIX24EaM7KQqIA==
Content-Type: text/plain
If-Match: 1-0e6d5b72

HELLO WORLD!

Status codes

  • 200 OK, when the file has been successfully overwritten
  • 404 Not Found, when the file wasn’t existing
  • 412 Precondition Failed, when the If-Match header is set and doesn’t match the last revision of the file
  • 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server’s filesystem maximum file size
  • 422 Unprocessable Entity, when the sent data is invalid (for example, the MetadataID parameter has expired)

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    "meta": {
      "rev": "2-d903b54c"
    },
    "attributes": {
      "type": "file",
      "name": "hello.pdf",
      "trashed": false,
      "md5sum": "YjU5YmMzN2Q2NDQxZDk2Nwo=",
      "created_at": "2016-09-19T12:38:04Z",
      "updated_at": "2016-09-19T12:38:04Z",
      "tags": [],
      "size": 12,
      "executable": false,
      "class": "pdf",
      "mime": "application/pdf",
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:49Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-21T04:27:50Z",
        "uploadedAt": "2016-09-21T04:27:50Z",
        "uploadedOn": "https://cozy.example.com/",
        "uploadedBy": {
          "slug": "drive"
        }
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        }
      }
    },
    "links": {
      "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b",
      "icon": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/icon/543d7eb8",
      "preview": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/preview/77e117e0",
      "tiny": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/tiny",
      "small": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/small",
      "medium": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/medium",
      "large": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/large"
    }
  }
}

POST /files/:file-id/copy

Create a copy of a file in the same directory with a copy suffix in its name

Query-String

Parameter Description
Name the file copy name (optional)
DirID the destination directory id (optional)

Request

POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/copy HTTP/1.1
Accept: application/vnd.api+json

Status codes

  • 201 Created, when the file has been successfully copied
  • 404 Not Found, when the file does not exist
  • 409 Conflict, when a file with the same name as the copy would have already exists
  • 413 Payload Too Large, when there is not enough available space on the cozy to copy the file

Response

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files",
    "id": "7382f28a-21d4-12d9-4438-3fd53e98a219",
    "meta": {
      "rev": "1-83a82e9"
    },
    "attributes": {
      "type": "file",
      "name": "hello (copy).pdf",
      "trashed": false,
      "md5sum": "YjU5YmMzN2Q2NDQxZDk2Nwo=",
      "created_at": "2022-10-18T18:33:24Z",
      "updated_at": "2022-10-18T18:33:24Z",
      "tags": [],
      "size": 12,
      "executable": false,
      "class": "pdf",
      "mime": "application/pdf",
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2022-10-18T18:33:24Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2022-10-18T18:33:24Z"
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        }
      }
    },
    "links": {
      "self": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219",
      "icon": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/icon/543d7eb8",
      "preview": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/preview/77e117e0",
      "tiny": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/tiny",
      "small": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/small",
      "medium": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/medium",
      "large": "/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/large"
    }
  }
}

DELETE /files/:file-id

Put a file in the trash.

Common

GET /files/metadata

Same as /files/:file-id but to retrieve informations from a path.

Request

GET /files/metadata?Path=/Documents/hello.txt HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
Location: https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b
{
  "data": {
    "type": "io.cozy.files",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    "meta": {
      "rev": "1-0e6d5b72"
    },
    "attributes": {
      "type": "file",
      "name": "hello.txt",
      "trashed": false,
      "md5sum": "ODZmYjI2OWQxOTBkMmM4NQo=",
      "created_at": "2016-09-19T12:38:04Z",
      "updated_at": "2016-09-19T12:38:04Z",
      "tags": [],
      "size": 12,
      "executable": false,
      "class": "document",
      "mime": "text/plain",
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:49Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-20T18:32:49Z",
        "uploadedAt": "2016-09-20T18:32:49Z",
        "uploadedOn": "https://cozy.example.com/",
        "uploadedBy": {
          "slug": "drive"
        }
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81"
        }
      }
    },
    "links": {
      "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b"
    }
  }
}

PATCH /files/:file-id and PATCH /files/metadata

Both endpoints can be used to update the metadata of a file or directory, or to rename/move it. The difference is the first one uses an id to identify the file/directory to update, and the second one uses the path.

Some specific attributes of the patch can be used:

  • dir_id attribute can be updated to move a file or directory
  • move_to_trash boolean to specify that the file needs to be moved to the trash
  • permanent_delete boolean to specify that the files needs to be deleted (after being trashed)

HTTP headers

It’s possible to send the If-Match header, with the previous revision of the file/directory (optional).

Request

PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP/1.1
Accept: application/vnd.api+json
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    "attributes": {
      "type": "file",
      "name": "hi.txt",
      "dir_id": "f2f36fec-8018-11e6-abd8-8b3814d9a465",
      "tags": ["poem"]
    }
  }
}

Status codes

  • 200 OK, when the file or directory metadata has been successfully updated
  • 400 Bad Request, when a the directory is asked to move to one of its sub-directories
  • 404 Not Found, when the file/directory wasn’t existing
  • 412 Precondition Failed, when the If-Match header is set and doesn’t match the last revision of the file/directory
  • 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn’t exist)

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
Location: https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b
{
  "data": {
    "type": "io.cozy.files",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
    "meta": {
      "rev": "1-0e6d5b72"
    },
    "attributes": {
      "type": "file",
      "name": "hi.txt",
      "trashed": false,
      "md5sum": "ODZmYjI2OWQxOTBkMmM4NQo=",
      "created_at": "2016-09-19T12:38:04Z",
      "updated_at": "2016-09-19T12:38:04Z",
      "tags": ["poem"],
      "size": 12,
      "executable": false,
      "class": "document",
      "mime": "text/plain",
      "cozyMetadata": {
        "doctypeVersion": "1",
        "metadataVersion": 1,
        "createdAt": "2016-09-20T18:32:49Z",
        "createdByApp": "drive",
        "createdOn": "https://cozy.example.com/",
        "updatedAt": "2016-09-22T13:32:51Z",
        "uploadedAt": "2016-09-21T04:27:50Z",
        "uploadedOn": "https://cozy.example.com/",
        "uploadedBy": {
          "slug": "drive"
        }
      }
    },
    "relationships": {
      "parent": {
        "links": {
          "related": "/files/f2f36fec-8018-11e6-abd8-8b3814d9a465"
        },
        "data": {
          "type": "io.cozy.files",
          "id": "f2f36fec-8018-11e6-abd8-8b3814d9a465"
        }
      }
    },
    "links": {
      "self": "/files/9152d568-7e7c-11e6-a377-37cbfb190b4b"
    }
  }
}

PATCH /files/

Endpoint to update the metadata of files and directories in batch. It can be used, for instance, to move many files in a single request.

Request

PATCH /files/ HTTP/1.1
Content-Type: application/vnd.api+json
{
  "data": [
    {
      "type": "io.cozy.files",
      "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
      "meta": {"rev": "1-0e6d5b72"},
      "attributes": {"dir_id": "f2f36fec-8018-11e6-abd8-8b3814d9a465"}
    },
    {
      "type": "io.cozy.files",
      "id": "9152d568-7e7c-11e6-a377-37cbfb190b4c",
      "meta": {"rev": "2-123123"},
      "attributes": {"move_to_trash": true}
    }
  ]
}

Status codes

The same status codes can be encountered as the PATCH /files/:file-id route.

POST /files/archive

Create an archive. The body of the request lists the files and directories that will be included in the archive. For directories, it includes all the files and sub-directories in the archive.

It’s possible to give a file by its id (in the ids array) or by its path (in the files array).

The generated archive is temporary and is not persisted.

Request

POST /files/archive HTTP/1.1
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.archives",
    "attributes": {
      "name": "project-X",
      "ids": ["a51aeeea-4f79-11e7-9dc4-83f67e9494ab"],
      "files": [
        "/Documents/bills",
        "/Documents/images/sunset.jpg",
        "/Documents/images/eiffel-tower.jpg"
      ]
    }
  }
}

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "links": {
    "related": "/files/archive/4521DC87/project-X.zip"
  },
  "data": {
    "type": "io.cozy.files.archives",
    "id": "4521DC87",
    "attributes": {
      "href": "/files/archive/4521DC87/project-X.zip"
    }
  }
}

GET /files/archive/:key/:name

Download a previously created archive. The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename.

This route does not require Basic Authentification

GET /files/archive/4521DC87/project-X.zip HTTP/1.1
Accept: application/zip
Content-Length: 12345
Content-Disposition: attachment; filename="project-X.zip"
Content-Type: application/zip

POST /files/downloads?Path=file_path

Create a file download. The Path query parameter specifies the file to download. The response json API links contains a related link for downloading the file, see below.

POST /files/downloads?Id=file_id

Also create a file download. But it takes the id of the file and not its path.

POST /files/downloads?VersionId=file_id/version_id

This is a third way to create a file download. But, this time, it is for downloading an old version of a file.

These 3 routes also accept a Filename=... parameter in the query-string to change the filename that will be used for the downloaded file.

GET /files/downloads/:secret/:name

Allows to download a file with a secret created from the route above.

The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename.

By default the content-disposition will be inline, but it will be attachment if the query string contains the parameter Dl=1

This route does not require Basic Authentification

Versions

The identifier of the io.cozy.files.versions is composed of the file-id and another string called the version-id, separated by a /. So, when a route makes reference to /something/:file-id/:version-id, you can use the identifier of the version document (without having to prepend the file identifier).

GET /files/download/:file-id/:version-id

Download an old version of the file content

By default the content-disposition will be inline, but it will be attachment if the query string contains the parameter Dl=1

Request

GET /files/download/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP/1.1

POST /files/:file-id/versions

Create a new version of a file, with the same content but new metadata. It requires a permission for PUT on the file, as it is equivalent to upload the same content of the file.

Query-String

Parameter Description
Tags an array of tags

Request

POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/metadata HTTP/1.1
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.metadata",
    "attributes": {
      "qualification": {
        "label": "telecom_invoice",
        "purpose": "invoice",
        "sourceCategory": "telecom"
      },
      "datetime": "2017-04-22T01:00:00-05:00",
    }
  }
}

POST /files/revert/:file-id/:version-id

This endpoint can be used to revert to an old version of the content for a file.

Request

POST /files/revert/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP/1.1

PATCH /files/:file-id/:version-id

This endpoint can be used to edit the tags of a previous version of the file.

Request

PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP/1.1
Accept: application/vnd.api+json
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "io.cozy.files.versions",
    "id": "9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72",
    "attributes": {
      "tags": ["poem"]
    }
  }
}

DELETE /files/:file-id/:version-id

This endpoint can be used to delete an old version of the content for a file.

Request

DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP/1.1

Response

HTTP/1.1 204 No Content

DELETE /files/versions

Deletes all the old versions of all files to make space for new files.

Request

DELETE /files/versions HTTP/1.1

Response

HTTP/1.1 204 No Content

Trash

When a file is deleted, it is first moved to the trash. In the trash, it can be restored. Or, after some time, it will be removed from the trash and permanently destroyed.

The file trashed attribute will be set to true.

GET /files/trash

List the files inside the trash. It’s paginated.

Query-String

Parameter Description
page[cursor] the last id of the results
page[limit] the number of entries (30 by default)

Request

GET /files/trash HTTP/1.1
Accept: application/vnd.api+json

Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
{
  "data": [
    {
      "type": "io.cozy.files",
      "id": "df24aac0-7f3d-11e6-81c0-d38812bfa0a8",
      "meta": {
        "rev": "1-3b75377c"
      },
      "attributes": {
        "type": "file",
        "dir_id": "io.cozy.files.trash-dir",
        "name": "foo.txt",
        "trashed": true,
        "restore_path": "/previous_parent",
        "md5sum": "YjAxMzQxZTc4MDNjODAwYwo=",
        "created_at": "2016-09-19T12:38:04Z",
        "updated_at": "2016-09-19T12:38:04Z",
        "tags": [],
        "size": 123,
        "executable": false,
        "class": "document",
        "mime": "text/plain",
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:32:49Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:32:49Z",
          "uploadedAt": "2016-09-20T18:32:49Z",
          "uploadedOn": "https://cozy.example.com/",
          "uploadedBy": {
            "slug": "drive"
          }
        }
      },
      "links": {
        "self": "/files/trash/df24aac0-7f3d-11e6-81c0-d38812bfa0a8"
      }
    },
    {
      "type": "io.cozy.files",
      "id": "4a4fc582-7f3e-11e6-b9ca-278406b6ddd4",
      "meta": {
        "rev": "1-4a09030e"
      },
      "attributes": {
        "type": "file",
        "dir_id": "io.cozy.files.trash-dir",
        "name": "bar.txt",
        "trashed": true,
        "restore_path": "/other_parent",
        "md5sum": "YWVhYjg3ZWI0OWQzZjRlMAo=",
        "created_at": "2016-09-19T12:38:04Z",
        "updated_at": "2016-09-19T12:38:04Z",
        "tags": [],
        "size": 456,
        "executable": false,
        "class": "document",
        "mime": "text/plain",
        "cozyMetadata": {
          "doctypeVersion": "1",
          "metadataVersion": 1,
          "createdAt": "2016-09-20T18:32:49Z",
          "createdByApp": "drive",
          "createdOn": "https://cozy.example.com/",
          "updatedAt": "2016-09-20T18:32:49Z",
          "uploadedAt": "2016-09-20T18:32:49Z",
          "uploadedOn": "https://cozy.example.com/",
          "uploadedBy": {
            "slug": "drive"
          }
        }
      },
      "links": {
        "self": "/files/trash/4a4fc582-7f3e-11e6-b9ca-278406b6ddd4"
      }
    }
  ]
}

POST /files/trash/:file-id

Restore the file with the file-id identifiant into its restore_path. If a file already exists at the restore path with the same name, a suffix will be added to avoid any conflict.

The file’s trashed attributes will be set to false.

DELETE /files/trash/:file-id

Destroy the file and make it unrecoverable (it will still be available in backups).

DELETE /files/trash

Clear out the trash.

Trashed attribute

All files that are inside the trash will have a trashed: true attribute. This attribute can be used in mango queries to only get “interesting” files.

Real-time via websockets

In addition to the normal events for files, the stack also injects some events when a thumbnail is generated. A permission on io.cozy.files is required to subscribe to those events on io.cozy.files.thumbnails.

Example

client > {"method": "AUTH",
          "payload": "xxAppOrAuthTokenxx="}
client > {"method": "SUBSCRIBE",
          "payload": {"type": "io.cozy.files.thumbnails"}}
server > {"event": "CREATED",
          "payload": {"id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
                      "type": "io.cozy.files.thumbnails",
                      "doc": {"format": "large"}}}
server > {"event": "CREATED",
          "payload": {"id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
                      "type": "io.cozy.files.thumbnails",
                      "doc": {"format": "medium"}}}
server > {"event": "CREATED",
          "payload": {"id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
                      "type": "io.cozy.files.thumbnails",
                      "doc": {"format": "small"}}}
server > {"event": "CREATED",
          "payload": {"id": "9152d568-7e7c-11e6-a377-37cbfb190b4b",
                      "type": "io.cozy.files.thumbnails",
                      "doc": {"format": "tiny"}}}