If you are new to AeroFS API, take a look at the overview and tutorials before diving into this reference manual.

API Reference

The AeroFS API supports reading and writing data to AeroFS Private Cloud instances. It is based on REST and uses JSON for both request and response bodies.

Encoding
All strings are encoded with UTF-8.
Encryption
All API access is done through HTTPS. Unencrypted connections will be rejected.
Read/Write
An attribute of a REST object that is readable will be included in a response containing that object. An attribute that is writable can be modified using PUT and POST methods. If an object attribute is not denoted as read-only or write-only, the attribute is both readable and writable.
Time format
All timestamps follow the ISO 8601 format with UTC time zone. For example, “2013-03-17T01:23Z” stands for March 17th, 2013 at 01:23 AM UTC.
Cross-origin
The API allows Cross-Origin Resource Sharing and is accessible from anywhere. That is, all responses include the header Access-Control-Allow-Origin: *.
Persistent connection
It is highly recommended to use persistent HTTP connections, which leverage HTTP pipelining and amortize the cost of SSL handshaking.
HTTP 1.0
To allow streaming responses of unknown size over a persistent connection, the API uses chunked transfer coding and therefore omits the Content-Length header. As a consequence, HTTP 1.0 clients are not supported.

Versioning

The API version follows semantic versioning in the form MAJOR.MINOR:

  • MAJOR is updated when we make incompatible API changes.

  • MINOR is updated when we add functionality in a backwards-compatible manner.

All API URLs include a version prefix in the form “vMAJOR.MINOR”. The API server will accept a request URL only if it supports the version specified in the URL.

This document describes API version 1.0.

$ curl https://host.name/api/v1.0/children

Authentication

API calls must be made using an OAuth token in the “Authorization” request header field.

The syntax for the header field is Authorization: Bearer <token> where <token> is a valid OAuth token. The Getting Started guide explains how to obtain an OAuth token.

$ curl -H "Authorization: Bearer dec6f0b1db98496fbd3f74d042a9a19d" ...

Errors

AeroFS uses standard HTTP status codes to indicate success or failure in serving API requests:

  • 2xx: The request was successful.

  • 4xx: The request could not be processed; presumably the request is invalid.

  • 5xx: A server-side failure occurred.


In addition, 4xx and 5xx responses have a JSON body with two fields:

  • type An AeroFS specific, machine readable error code.

  • message Human-readable description of the error.


Possible values of the type field include:

  • BAD_ARGS: Invalid request arguments

  • UNAUTHORIZED: Missing or invalid OAuth token

  • FORBIDDEN: Insufficient permissions to perform request

  • NOT_FOUND: Requested resource not found

  • CONFLICT: A conflict caused a write operation to fail

  • INTERNAL_ERROR: Unexpected server error

  • TOO_MANY_REQUESTS: The server is under load and declined to service the request

{
    "type": "BAD_ARGS",
    "message": "The required parameter file_id is missing"
}

Entity tags (ETags)

When appropriate, the server populates entity tags in API response headers and honor conditional requests for subsequent API requests.

Entity tags are opaque strings. No assumptions should be made about their structure or length.

Entity tags are only valid for the resource for which they where obtained. Using an entity tag obtained from one resource in a conditional request for another resource is incorrect and the result is undefined.

For instance an entity tag obtained from the /files/0a1b2c... resource MUST NOT be used for a conditional request to the /files/0a1b2c.../content resource.

Consistency policies

To make appropriate trade-offs between service availability and data consistency, AeroFS API clients can control the policy the load balancer applies when selecting computers to serve API requests. The table below summarizes how the client selects consistency policies. Read this article for more information on this topic.

 

Client behavior Resulting policy
Enable cookies Default: fall back to other computers if the original computer becomes unavailable.
Enable cookies and set Endpoint-Consistency: strict in request headers Consistency over availability: do not switch computer in a session.
Disable cookies Availability over consistency: select arbitrary computers across requests.

OAuth

OAuth 2.0 is a widely used protocol for users to authorize third-party applications to perform secure actions on their behalf. Every API call made to the AeroFS API Server requires an OAuth Access Token. This is preferable to basic authentication for three main reasons:

  1. A user can authorize an application to use their AeroFS data without giving their password to the application.

  2. A user can grant some permissions (e.g. read-only access) and withhold others (e.g. write access).

  3. A user can easily revoke authorization at any time.

This tutorial will guide you through the process of registering an app with an AeroFS Private Cloud Appliance, getting an OAuth Access Token by requesting authorization from a user, and using that token to make API calls.

This section of the API reference describes each call made to the AeroFS OAuth server.

OAuth Scopes

Each OAuth access token is issued for a particuler set of privileges, or “scopes”. The scopes are returned to the caller along with the access token.

The API supports the following scopes:

Scope name Permissions granted
files.read Can list and download files.
files.write Can create, rename, upload, and delete files.
user.read Can view email and name.
user.write Can modify name.
user.password Can reset and modify password.
acl.read Can list shared folders and their members.
acl.write Can create shared folders and manage members.
acl.invitations Can list, accept, and ignore invitations.
organization.admin Can manage users, shared folders, and content.

Requested Scopes vs Granted Scopes

When an application requests an access token, the user may decide to only grant a subset of the requested scopes. Applications should handle such a case gracefully and clearly communicate to the users how partial scope grants will affect functionality.

If the granted scopes are insufficient for your application to work, you may show an error to the user and re-submit your authorization request.

Administrative Scope

The organization.admin scope will only be granted if the authenticated caller is an AeroFS organization admin.

user.read,acl.read

Grants read-only access to basic user information and shared folders.


files.read,files.write

Grants full read and write access to the entire AeroFS folder.

Getting authorization from the user

To get an authorization code, direct the user to the authorization page and wait for the code to be sent to the redirect_uri.

Definition
GET /authorize
Note: this is https://host.name/authorize, not https://host.name/api/v1.0/authorize.
Parameters
response_type Must be “code”.
client_id UUID of the app (generated upon app registration).
redirect_uri A URI to which authorization responses, including errors, will be redirected. This must match the Redirect URI entered during client registration.
scope Comma-separated list of requested scopes
state (optional) A string that will be roundtripped and passed back to the Redirect URI. Recommended: an unguessable string. This should be used to prevent cross-site request forgery attacks.
Returns
The user will be redirected to the redirect_uri with the following query parameters:
code Authorization code.
state (optional) If state was provided in the request, the same string will be included here. If it does not match the expected value, the app should abort the authorization process.
Errors
If client_id or redirect_uri is invalid, a 400 status code will be returned to the user.
If any other error occurs, the user will be directed to the redirect_uri with the following query parameters:
error One of the error codes in section 4.1.2.1 of the OAuth 2.0 spec.
error_description (optional) A human-readable description of the error.
state (optional) If state was provided in the request, the same string will be included here. If it is different, the callback is from a third-party and the app should abort the authorization process.

Send the user to the following URL:

https://host.name/authorize?response_type=code&client_id=afd42bcd-7604-4ce3-ae4b-1873bdbcd83c&redirect_uri=https://app.acme.com/auth_cb&state=9kcht6uiha9f23u7sskonb7cvy70ga3p6bnzrm18&scope=user.read

If the user authorizes the app, they will be redirected to:

https://app.acme.com/auth_cb?code=7ac4fe73a2df4095bd72580a4dcb8501&state=9kcht6uiha9f23u7sskonb7cvy70ga3p6bnzrm18

Getting an access token

Exchange a valid authorization code for an access token.

Definition
POST /auth/token
grant_type Must be “authorization_code”.
code Authorization code.
client_id UUID of the app (generated upon app registration).
client_secret Secret key of the app (generated upon app registration).
redirect_uri Redirect URI provided during client registration and when obtaining authorization code.
Returns
200 OK with the following JSON fields in the body:
access_token An OAuth access token. Keep it secret; keep it safe.
token_type The type of the granted token; today this is always “bearer”.
expires_in Number of seconds until expiry (or 0 for tokens that don’t expire).
scope Comma-separated list of scopes granted by the user.
curl -X POST https://host.name/auth/token --data "grant_type=authorization_code&code=7ac4fe73a2df4095bd72580a4dcb8501&client_id=afd42bcd-7604-4ce3-ae4b-1873bdbcd83c&client_secret=a543b4f7-6f54-427d-aba6-86d036f2883e&redirect_uri=https://app.acme.com/auth_cb"
{
  "access_token": "dec6f0b1db98496fbd3f74d042a9a19d",
  "token_type": "bearer",
  "expires_in": 0,
  "scope": "files.read,files.write"
}

Revoking an access token

Revoke an access token so that the app can no longer use it for API requests.

Definition
DELETE /auth/token/{token}
Returns
200 OK if the token is deleted successfully.
404 Not Found if the token was not found.
curl -X DELETE https://host.name/auth/token/dec6f0b1db98496fbd3f74d042a9a19d

The Children object

A Children object contains a list of files and folders under a parent folder. You may use methods on this object to enumerate the AeroFS directory tree belonging to the authenticated user.

Attributes
parent (read-only) Identifier of the parent folder.
folders (read-only) List of Folder objects under the parent folder.
files (read-only) List of File objects under the parent folder.
{
  "parent": "9f8e7d...",
  "folders": [{
    "id": "0a1b2c...",
    "name": "Folder 1",
    "is_shared": false
  }, {
    "id": "0a1b2c...",
    "name": "Folder 2",
    "is_shared": true
  }],
  "files": [{
    "id": "0a1b2c...",
    "name": "File.doc",
    "last_modified": 123456,
    "size": 123,
    "mime_type": "application/octet-stream"
  }]
}

Listing children of a folder

List files and folders under a given folder.

Definition
GET /children/{id}
Parameters
id (optional) Identifier of the parent folder. If absent, list the children of the root AeroFS folder of the authenticated user.
Returns
A Children object.
$ curl https://host.name/api/v1.0/children/9f8e7d...
{
  "parent": "9f8e7d...",
  "folders": [{
    "id": "0a1b2c...",
    "name": "Folder 1",
    "is_shared": false
  }]
}

The Folder object

A Folder object represents a folder in AeroFS. You may use methods on this object to manipulate folders and retrieve their information.

Attributes
id (read-only) Identifier of this folder.
name Human-readable base name of this folder.
parent (write-only) Identifier of this folder’s parent folder.
is_shared (read-only) Boolean. Whether this folder is a shared folder.
{
  "id": "0a1b2c...",
  "name": "Example Folder",
  "is_shared": false
}

Retrieve folder metadata

Given a folder’s identifier, return its metadata such as the name and parent folder ID.

Definition
GET /folders/{id}
Parameters
id Identifier of the folder.
Returns
A Folder object.
Response header
ETag Entity tag for subsequent conditional requests.
$ curl https://host.name/api/v1.0/folders/0a1b2c...
{
  "id": "0a1b2c...",
  "name": "Example Folder",
  "is_shared": false
}

Create a folder

Create a new, empty folder.

Definition
POST /folders
Request body
A Folder object.
Returns
201 Created with a Folder object in the response body.
409 Conflict if a folder or file with the same name already exists.
Response header
Location URL of the new resource. See RFC2616.
ETag Entity tag for subsequent conditional requests.
$ curl -X POST https://host.name/api/v1.0/folders \
    -H 'Content-Type: application/json' \
    -d '{"parent": "9f8e7d...", "name": "Foo"}'
{
  "id": "0a1b2c...",
  "name": "Foo",
  "is_shared": false
}

Move a folder

Rename a folder and/or move it to a new parent.

The result is undefined if two clients try to move or rename the same folder at the same time without passing an If-Match header.

Movement across shared folder boundary

When a folder is moved across a shared folder boundary, e.g. from the AeroFS root folder into a shared folder or from a shared folder to another shared folder, its identifier will change.

To safely handle such moves the caller should retrieve the new identifier from the response body and update any cached occurence of the old identifier.

Definition
PUT /folders/{id}
Parameters
id Identifier of the folder to be renamed and/or moved.
Request body
A Folder object that specifies the new location.
Request header (optional)
If-Match One or more ETags. The request will fail if the current ETag of the resource does not match any of the given values. See RFC2616.
Returns
200 OK with a Folder object in the response body.
409 Conflict if a folder or file with the same name already exists.
412 Precondition Failed if the conditions specified via the If-Match header could not be satisfied.
Response header
ETag Entity tag for subsequent conditional requests.
$ curl -X PUT https://host.name/api/v1.0/folders/0a1b2c... \
    -H 'Content-Type: application/json' \
    -d '{"parent": "9f8e7d...", "name": "Foo"}'
{
  "id": "0a1b2c...",
  "name": "Foo",
  "is_shared": false
}

Delete a folder

Delete a folder and all its children.

Definition
DELETE /folders/{id}
Parameters
id Identifier of the folder to be deleted.
Request header (optional)
If-Match One or more ETags. The request will fail if the current ETag of the resource does not match any of the given values. See RFC2616.
Returns
204 No Content if the folder was successfully deleted.
412 Precondition Failed if the conditions specified via the If-Match header could not be satisfied.
$ curl -X DELETE https://host.name/api/v1.0/folders/0a1b2c...

The File object

A File object represents a file in AeroFS. You may use methods on this object to manipulate files and retrieve their information.

Files without content

It is possible for a file to exist without having any content. Usually, this is a placeholder for a file upload that is in progress. It can also happen if an upload fails partway through and is not resumed or if Selective Sync is used on a desktop client.

In such cases, the size and timestamp fields will be missing. Old AeroFS desktop clients may populate the size field with value -1.

Trying to download content for such a file will result in a 404 response, however in most cases uploading new content will be possible.

It is always possible to rename, move, or delete a file with no content.

Attributes
id (read-only) Identifier of this file.
name Human-readable base name of this file.
parent (write-only) Identifier of this folder’s parent folder.
last_modified (read-only) Last modified time of this file, in ISO 8601 format.
size (read-only) Long type. Size of this file, in bytes.
mime_type (read-only) MIME type of the file, default to application/octet-stream.
{
  "id": "0a1b2c...",
  "name": "Hello.doc",
  "last_modified": "2013-03-17T01:23Z",
  "size": 1234,
  "mime_type": "application/octet-stream"
}

Retrieve file metadata

Given a file’s identifier, return its metadata such as the name and parent folder ID.

Definition
GET /files/{id}
Parameters
id Identifier of the file.
Returns
A File object.
Response header
ETag Entity tag for subsequent conditional requests.
$ curl https://host.name/api/v1.0/files/0a1b2c...
{
  "id": "0a1b2c...",
  "name": "Hello.doc",
  "last_modified": "2013-03-17T01:23Z",
  "size": 1234,
  "mime_type": "application/octet-stream"
}

Retrieve file content

Given a file’s identifier, return its content.

If the file is modified on the source computer during the transfer, the connection will be closed before transfer completes.

Definition
GET /files/{id}/content
Parameters
id Identifier of the file.
Request header (optional)
Range One or more ranges of bytes for partial requests. See RFC2616.
If-Range An ETag. The Range header will be ignored if the current ETag of the resource does not match the given value. See RFC2616.
If-None-Match One or more ETags. A 304 Not Modified response with an empty body will be returned if the current ETag of the resource matches any of the given values. See RFC2616.
Returns
200 OK with file content in the body.
206 Partial Content with file content in the body. Return a multipart response if multiple subranges are included.
304 Not Modified with an empty body. See the If-None-Match request header above.
416 Requested Range Not Satisfiable with empty body if the request included a Range header and none of the ranges overlap the current extent of the file content.
Response header
Content-Type MIME type of the file or, for subrange response, either application/octet-stream or multipart/byteranges. See RFC2616.
Content-Disposition Suggested filename when save the file to disk. Not available for partial responses. See RFC2616.
Content-Range Location of the returned content in the full file cotent. Available only for partial responses. See RFC2616.
ETag Entity tag for subsequent conditional requests.
$ curl https://host.name/api/v1.0/files/0a1b2c.../content

downloads the entire content of a file.

$ curl https://host.name/api/v1.0/files/0a1b2c.../content \
    -H 'If-None-Match: "50c17c41b533033c73f1eb99d80bbb32"'

downloads the content of the given file only if the entity tag has changed.

$ curl https://host.name/api/v1.0/files/0a1b2c.../content \
    -H 'If-Range: "50c17c41b533033c73f1eb99d80bbb32"' \
    -H 'Range: bytes=0-99'

downloads the first 100 bytes of the given file if the entity tag has not changed, otherwise downloads the whole file.

Create a file

Create a new file, with no content.

Definition
POST /files
Request body
A File object.
Returns
201 Created with a File object in the response body.
409 Conflict if a folder or file with the same name already exists.
Response header
Location URL of the new resource. See RFC2616.
ETag Entity tag for subsequent conditional requests.
$ curl -X POST https://host.name/api/v1.0/files \
    -H 'Content-Type: application/json' \
    -d '{"parent": "9f8e7d...", "name": "Hello.doc"}'
{
  "id": "0a1b2c...",
  "name": "Hello.doc",
  "last_modified": "2013-03-17T01:23Z",
  "size": 0,
  "mime_type": "application/octet-stream"
}

Upload file content

Overwrite an existing file’s content with new content.

Conditional upload

In cases where unconditional overwrite is not acceptable, the client should first make a GET request on the content. (Alternatively, use a HEAD request with the same parameters as GET to fetch response headers only.) The entity tag in the response header can then be passed to this method in the If-Match header.

If two clients try to upload new content to the same file at the same time without passing an If-Match header, the result is undefined.

Chunked upload

To start a chunked upload, make a PUT request including a Content-Range request header, whose value should be consistent with the size of the chunk being uploaded. See RFC2616 for the precise syntax of that header.

The server response will include an Upload-ID header which can be used to upload the next chunk(s) of the file. To obtain the upload identifier without actually starting the upload, make that first request with an empty body and Content-Range: bytes */*.

Multiple chunks may not be uploaded concurrently or out-of-order for the same upload identifier:

  • a PUT request for a range starting before the last received byte will result in the already received data being truncated
  • a PUT request for a range starting after the last received byte will result in a 416 Requested Range Not Satisfiable response

The upload is considered complete when the amount of bytes uploaded at the end of a request matches the value specified in the instance-length of the Content-Range request header.

If the total size of the file being uploaded is not known ahead of time, instance-length can remain unspecified, i.e. *, until the very last chunk. The last chunk may also have an empty body, in which case the byte-range-resp-spec of the Content-Range header should be *.

Resumable upload

When the connection is broken before a chunk is fully uploaded, it is possible to determine the amount of bytes successfully uploaded by sending PUT request with an empty body, a valid Upload-ID and Content-Range: bytes */*. If the upload is still ongoing, the server will respond with 200 OK and a Range header indicating the amount of bytes successfully uploaded so far.

Note that the API currently does not distinguish between invalid, unused and completed upload identifiers: in all of these cases the above request will result in a 400 Bad Request response.

Upload identifiers are not valid forever. The expiration policy can differ among AeroFS desktop clients but in general an upload identifier is expected to remain valid for roughly 24 hours. When the upload identifier expires, any uploaded data will be discarded and subsequent requests including it will be rejected.

Consistency considerations

Each upload identifier is only valid for a single AeroFS desktop client. As outlined in the section on consistency policies, cookies MUST be enabled and the Endpoint-Consistency: strict request header SHOULD be used to ensure that subsequent requests will be routed to the same computer.

Definition
PUT /files/{id}/content
Parameters
id Identifier of the file to upload new content to.
Request body
File content.
Request header (optional)
If-Match One or more ETags. The request will fail if the current ETag of the resource does not match any of the given values. See RFC2616.
Upload-ID Opaque identifier used for incremental upload. Will be ignored unless a Content-Range header is also present.
Content-Range Location of the chunk being uploaded within the file.
Returns
200 OK if successful.
400 Bad Request if given invalid Upload-ID, if the Content-Range header is not consistent with the length of the body or if the request is otherwise inavlid.
412 Precondition Failed if the conditions specified via the If-Match header could not be satisfied.
416 Requested Range Not Satisfiable with empty body if the request included Content-Range and Upload-ID headers and the upload cannot be resumed from the requested position.
429 Too Many Requests if the desktop client servicing the request reached the maximum allowed number of concurrent uploads.
Response header
ETag Entity tag for subsequent conditional requests.
Upload-ID Opaque identifier of ongoing chunked download, if appropriate.
Range Range of bytes upload so far if using chunked upload
$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c.../content \
    -T Hello.doc

Uploads the content of local file Hello.doc to a file with ID 0a1b2c….

$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c.../content \
    -H "Content-Range: bytes */*" \
    -H "Content-Length: 0"

Obtains a fresh upload identifier to be used for a chunked upload to a file with ID 0a1b2c….

$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c.../content \
    -H "Upload-ID: 123456" \
    -H "Content-Range: bytes */*" \
    -H "Content-Length: 0"

Retrieve amount of bytes successfully uploaded to file with ID 0a1b2c… as part of upload 123456.

$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c.../content \
    -H "Upload-ID: 123456" \
    -H "Content-Range: bytes 1000-1199/*" \
    -T chunk.bin

Upload the contents of local file chunk.bin as a chunk of 200 bytes starting at position 1000 to file with ID 0a1b2c… as part of upload 123456.

$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c.../content \
    -H "Upload-ID: 123456" \
    -H "Content-Range: bytes */1200" \
    -H "Content-Length: 0"

Completes chunked upload 123456 to file with ID 0a1b2c….

Move a file

Rename a file and/or move it to a new parent.

The result is undefined if two clients try to move or rename the same file at the same time without passing an If-Match header.

Movement across shared folder boundary

When a file is moved across a shared folder boundary, e.g. from the AeroFS root folder into a shared folder or from a shared folder to another shared folder, its identifier will change.

To safely handle such moves the caller should retrieve the new identifier from the response body and update any cached occurence of the old identifier.

Definition
PUT /files/{id}
Parameters
id Identifier of the folder to be renamed and/or moved.
Request body
A File object that specifies the new location.
Request header (optional)
If-Match One or more ETags. The request will fail if the current ETag of the resource does not match any of the given values. See RFC2616.
Returns
200 OK with a File object in the response body.
409 Conflict if a folder of file with the same name already exists.
412 Precondition Failed if the conditions specified via the If-Match header could not be satisfied.
Response header
ETag Entity tag for subsequent conditional requests.
$ curl -X PUT https://host.name/api/v1.0/files/0a1b2c... \
    -H 'Content-Type: application/json' \
    -d '{"parent": "9f8e7d...", "name": "Hello.doc"}'
{
  "id": "0a1b2c...",
  "name": "Hello.doc",
  "last_modified": "2013-03-17T01:23Z",
  "size": 1234,
  "mime_type": "application/octet-stream"
}

Delete a file

Definition
DELETE /files/{id}
Parameters
id Identifier of the file to be deleted.
Request header (optional)
If-Match One or more ETags. The request will fail if the current ETag of the resource does not match any of the given values. See RFC2616.
Returns
204 No Content if the file was successfully deleted.
412 Precondition Failed if the conditions specified via the If-Match header could not be satisfied.
$ curl -X DELETE https://host.name/api/v1.0/files/0a1b2c...