Skip to main content

Sync API

This document outlines the client-server communication of the Standard Notes ecosystem.

Item#

An Item is largely the only model that both clients and server are concerned wtih. The content field stores an encrypted object that can be anything the client needs to operate.

Relationships between items are handled by the client, and not the server, and are stored encrypted in the content field as references.

Items have the following properties:

nametypedescription
uuidstring (or uuid for some databases)The unique identifier for this item.
contenttextAn encrypted string generated by the client.
content_typestringThe type of data contained in the content field. (i.e Note, Tag, SN
enc_item_keytextThe key used to encrypt content, itself also encrypted.
deletedbooleanWhether the model has been deleted.
created_at_timestampintegerTimestamp representing when the item was created, with microsecond precision.
updated_at_timestampintegerTimestamp representing when the item was updated by the server, with microsecond precision.

Content#

Data generated by the client is stored in the content field of the Item. An item's content is "sticky" and can have any property the client chooses, as well as the following:

nametypedescription
appDatadictionaryA domain based dictionary whose content must be preserved between platforms. appData[domain] contains data the client stores in the item.
referencesarrayA metadata array of other Item uuids this item is related to and their respective content_type. See sample below.

references array structure:

[
{uuid: xxxx, content_type: "Tag"},
{uuid: xxxxx, content_type: "Tag"},
]

REST API#

General:

  1. All requests after initial authentication should be authenticated with a session token in the Authorization header:

    Authorization: Bearer <access token>

POST items/sync#

apistringThe API version to use. Must not be null, otherwise oldest API version used. Latest value is "20200115".
compute_integritybooleanShould be false in most cases. Pass true if you plan to read the integrity_hash result (integrity can be optionally checked once on app launch).
itemsarrayAn array of Items.
limitintegerThe maximum number of items to return per request. Official clients use 150.
sync_tokenstringAn opaque token returned by the server from a previous sync request. This lets the server know to pull in only new changes.
cursor_tokenstringAn opaque pagination token returned by the server from a previous multi-page sync request. Send this value back only if the server returned this value from a previous request.

Response#

{
"retrieved_items": Array<Item>,
"saved_items": Array<Item>,
"conflicts": Array<Conflict>,
"sync_token": string,
"cursor_token": string?,
"integrity_hash": string?,
}
retrieved_itemsItems that are new to the client or have been modified since last sync and should be merged with local values or created locally.
saved_itemsItems which have been successfully saved. Clients should merge only the resulting updated_at_timestamp with local values. Do not update local value of content from remote saved_items value.
conflictsItems which have not been saved by the server and returned to client.
sync_tokenAn opaque token which should be sent back to server in subsequent sync request.
cursor_tokenAn opaque token which should be sent back to server in subsequent sync request (if present).

Conflicts#

type Conflict = {
server_item?: Item
unsaved_item?: Item
type: 'sync_conflict' | 'uuid_conflict'
}

A sync_conflict occurs when the item the client is attempting to save has a newer change on the server. The server is able to determine this by reading the updated_at_timestamp value from both the incoming payload and the server payload. If the incoming payload's updated_at_timestamp != to the server's updated_at_timestamp for that item, the save is rejected and returned to client as a sync_conflict. These types of conflicts are not uncommon.

To resolve a sync_conflict, the client must choose a winner between server_item and unsaved_item then re-sync. The winning item should have its updated_at_timestamp value set to the server's value.

A uuid_conflict occurs when the UUID the client has choosen for an item for X user already belongs to an item for Y user. This should mostly only occur when a user registers a new account and imports a data backup from another account.

To resolve a uuid_conflict, change the UUID of the item attempting to be saved to a new UUID, then re-sync.

Deletion#

To delete an item permanently, set deleted to true on the Item and sync. When receiving an item that is deleted, remove it from the local database immediately.

Last updated on