docs/notes.md
Rama master · réplica de lectura del repositorio original.
[Table of contents](README.md#table-of-contents)
# Notes for collaborative edition
The cozy-notes application can be used to take notes, and collaborate on them.
The note is persisted as a file in the VFS, but it also has specific routes to
enable the collaborative edition in real-time. The content of the file is a
markdown export of the notes, except if the note has images, and it is a tar
with the markdown as `index.md` and the images in that case. The markdown
format is mostly compatible with CommonMark, but there are a few changes:
- we are using the [consistent attribute syntax](https://talk.commonmark.org/t/consistent-attribute-syntax/272) for some markups like colors and underline
- the tables are not saved like in [GFM](https://github.github.com/gfm/#tables-extension-) because we can have merged cells and several paragraphs inside a cell
- misc.
The downloaded files can be reuploaded to the Cozy, and if the `.cozy-note`
extension is kept, the stack will try to recreate the Prosemirror tree, making
possible to use the uploaded file as a note in Cozy-Notes with realtime
collaboration.
## Routes
### POST /notes
It creates a note: it creates a files with the right metadata for collaborative edition.
**Note:** a permission on `POST io.cozy.files` is required to use this route.
#### Parameter
| Parameter | Description |
| --------- | ------------------------------------------------------------------------- |
| title | The title of the note, that will also be used for the filename |
| dir_id | The identifier of the directory where the file will be created (optional) |
| schema | The schema for prosemirror (with OrderedMap transformed as arrays) |
| content | The initial content of the note (optional) |
**Note:** if the `dir_id` is not given, the file will be created in a `Notes`
directory (and this directory will have a referenced_by on the notes apps to
allow to find this directory even if it is renamed or moved later).
#### Request
```http
POST /notes HTTP/1.1
Host: alice.example.net
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.documents",
"attributes": {
"title": "My new note",
"dir_id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
}
}
}
```
#### Response
```http
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "1-f71ee54e2"
},
"attributes": {
"type": "file",
"name": "My new note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:38:04Z",
"tags": [],
"metadata": {
"title": "My new note",
"content": { "type": "doc", "content": [{ "type": "paragraph" }] },
"version": 0,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 1,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:38:04Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
### GET /notes
It returns the list of notes, sorted by last update. It adds the path for the
files in the response, as it can be convient for the notes application.
**Note:** a permission on `GET io.cozy.files` is required to use this route.
#### Request
```http
GET /notes HTTP/1.1
Host: alice.example.net
Accept: application/vnd.api+json
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"links": {
"next": "/notes?page[cursor]=a078d6f0-04a9-0138-3e03-543d7eb8149c"
},
"data": [{
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "1-f71ee54e2"
},
"attributes": {
"type": "file",
"name": "My new note.cozy-note",
"path": "/Notes/my new note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:38:04Z",
"tags": [],
"metadata": {
"title": "My new note",
"content": { "type": "doc", "content": [{ "type": "paragraph" }] },
"version": 0,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 1,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:38:04Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}]
}
```
### GET /notes/:id
It fetches the file with the given id. It also includes the changes in the
content that have been accepted by the stack but not yet persisted to the file.
#### Request
```http
GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP/1.1
Host: alice.example.net
Accept: application/vnd.api+json
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "4-1482b88a"
},
"attributes": {
"type": "file",
"name": "My new note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:38:52Z",
"tags": [],
"metadata": {
"title": "My new note",
"content": { "type": "doc", "content": [{ "type": "horizontal_rule" }] },
"version": 3,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 4,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:38:04Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
### GET /notes/:id/text
It returns the content of the note as text with no formatting.
#### Request
```http
GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/text HTTP/1.1
Host: alice.example.net
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
```
```
This is the content of the note.
```
### GET /notes/texts
It returns the content of several notes as text with no formatting. The
identifiers of the notes must be given in the query-string parameter `ids`, as
a comma-separated list.
#### Request
```http
GET /notes/texts?ids=bf0dbdb0-e1ed-0137-8548-543d7eb8149c,6bc77a60-c8fe-013c-20a9-18c04daba326 HTTP/1.1
Host: alice.example.net
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/json
```
```json
{
"bf0dbdb0-e1ed-0137-8548-543d7eb8149c": "This is the content of the note.",
"6bc77a60-c8fe-013c-20a9-18c04daba326": "This is the text of another note."
}
```
### GET /notes/:id/steps?Version=xxx
It returns the steps since the given version. If the revision is too old, and
the steps are no longer available, it returns a 412 response with the whole
document for the note.
#### Request
```http
GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/steps?Version=3 HTTP/1.1
Host: alice.example.net
Accept: application/vnd.api+json
```
#### Response (success)
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": [{
"type": "io.cozy.notes.steps",
"attributes": {
"sessionID": "543781490137",
"stepType": "replace",
"from": 1,
"to": 1,
"slice": {
"content": [{ "type": "text", "text": "H" }]
},
"version": 4
}
}, {
"type": "io.cozy.notes.steps",
"attributes": {
"sessionID": "543781490137",
"stepType": "replace",
"from": 2,
"to": 2,
"slice": {
"content": [{ "type": "text", "text": "ello" }]
},
"version": 5
}
}]
}
```
#### Response (failure)
```http
HTTP/1.1 412 Precondition Failed
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "4-1482b88a"
},
"attributes": {
"type": "file",
"name": "My new note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:38:52Z",
"tags": [],
"metadata": {
"title": "My new note",
"content": { "type": "doc", "content": [{ "type": "horizontal_rule" }] },
"version": 6,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 4,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:38:04Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
### PUT /notes/:id/title
It updates the title.
#### Request
```http
PUT /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/title HTTP/1.1
Host: alice.example.net
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.documents",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"attributes": {
"sessionID": "543781490137",
"title": "A new title for my note"
}
}
}
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "4-1482b88a"
},
"attributes": {
"type": "file",
"name": "A new title for my note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:39:37Z",
"tags": [],
"metadata": {
"title": "A new title for my note",
"content": { "type": "doc", "content": [{ "type": "horizontal_rule" }] },
"version": 3,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 4,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:39:37Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
### PATCH /notes/:id
It sends some steps to apply on the document. The last known version of the
note must be sent in the `If-Match` header to avoid conflicts.
#### Request
```http
PATCH /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP/1.1
Host: alice.example.net
If-Match: 3
Content-Type: application/vnd.api+json
```
```json
{
"data": [{
"type": "io.cozy.notes.steps",
"attributes": {
"sessionID": "543781490137",
"stepType": "replace",
"from": 1,
"to": 1,
"slice": {
"content": [{ "type": "text", "text": "H" }]
}
}
}, {
"type": "io.cozy.notes.steps",
"attributes": {
"sessionID": "543781490137",
"stepType": "replace",
"from": 2,
"to": 2,
"slice": {
"content": [{ "type": "text", "text": "ello" }]
}
}
}]
}
```
#### Response (success)
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "4-1482b88a"
},
"attributes": {
"type": "file",
"name": "A new title for my note.cozy-note",
"trashed": false,
"md5sum": "MDlmN2UwMmYxMjkwYmUyMTFkYTcwN2EyNjZmMTUzYjMgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-11-05T12:39:37Z",
"tags": [],
"metadata": {
"title": "A new title for my note",
"content": {
"type": "doc",
"content": [{ "type": "paragraph", "text": "Hello" }]
},
"version": 5,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"topNode": "doc"
}
},
"size": 6,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2019-11-05T12:39:37Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
#### Response (failure)
If at least one step can't be applied, they will all be discarded, and the
response will be this error:
```http
HTTP/1.1 409 Conflict
Content-Type: application/vnd.api+json
```
```json
{
"status": 409,
"Title": "Conflict",
"Detail": "Cannot apply the steps"
}
```
### PUT /notes/:id/telepointer
It updates the position of the pointer.
#### Request
```http
PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/telepointer HTTP/1.1
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.telepointers",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"attributes": {
"sessionID": "543781490137",
"anchor": 7,
"head": 12,
"type": "textSelection"
}
}
}
```
#### Response
```http
HTTP/1.1 204 No Content
```
### POST /notes/:id/sync
It forces writing the note to the virtual file system. It may be used after the
title has been changed, or when the user quits the note.
#### Request
```http
POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/sync HTTP/1.1
```
#### Response
```http
HTTP/1.1 204 No Content
```
### GET /notes/:id/open
It return the parameters to build the URL where the note can be opened. It can
be on the same cozy instance, or on another instance if the note is shared.
If the identifier doesn't give a note, the response will be a `404 Page not
found`.
#### Request
```http
GET /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/open HTTP/1.1
Host: bob.cozy.example
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.url",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"attributes": {
"note_id": "05781bea244247fb38f2cd50262c07b5",
"subdomain": "flat",
"protocol": "https",
"instance": "alice.cozy.example",
"sharecode": "543d7eb8149c",
"public_name": "Bob"
}
}
}
```
### PUT /notes/:id/schema
It can be used to update the schema of the given note.
#### Request
```http
PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/schema HTTP/1.1
Host: alice.example.net
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.documents",
"attributes": {
"schema": {
"nodes": [
["doc", { "content": "block+" }],
[
"panel",
{
"content": "(paragraph | heading | bulletList | orderedList)+",
"group": "block",
"attrs": { "panelType": { "default": "info" } }
}
],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"version": 2,
"topNode": "doc"
}
}
}
}
```
#### Response
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.files",
"id": "bf0dbdb0-e1ed-0137-8548-543d7eb8149c",
"meta": {
"rev": "10-241a3436007b"
},
"attributes": {
"type": "file",
"name": "My new note.cozy-note",
"trashed": false,
"md5sum": "NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K",
"created_at": "2019-11-05T12:38:04Z",
"updated_at": "2019-12-10T14:49:12Z",
"tags": [],
"metadata": {
"title": "My new note",
"content": { "type": "doc", "content": [{ "type": "paragraph" }] },
"version": 0,
"schema": {
"nodes": [
["doc", { "content": "block+" }],
[
"panel",
{
"content": "(paragraph | heading | bullet_list | ordered_list)+",
"group": "block",
"attrs": { "panelType": { "default": "info" } }
}
],
["paragraph", { "content": "inline*", "group": "block" }],
["blockquote", { "content": "block+", "group": "block" }],
["horizontal_rule", { "group": "block" }],
[
"heading",
{
"content": "inline*",
"group": "block",
"attrs": { "level": { "default": 1 } }
}
],
["code_block", { "content": "text*", "marks": "", "group": "block" }],
["text", { "group": "inline" }],
[
"image",
{
"group": "inline",
"inline": true,
"attrs": { "alt": {}, "src": {}, "title": {} }
}
],
["hard_break", { "group": "inline", "inline": true }],
[
"ordered_list",
{
"content": "list_item+",
"group": "block",
"attrs": { "order": { "default": 1 } }
}
],
["bullet_list", { "content": "list_item+", "group": "block" }],
["list_item", { "content": "paragraph block*" }]
],
"marks": [
["link", { "attrs": { "href": {}, "title": {} }, "inclusive": false }],
["em", {}],
["strong", {}],
["code", {}]
],
"version": 2,
"topNode": "doc"
}
},
"size": 1,
"executable": false,
"class": "text",
"mime": "text/vnd.cozy.note+markdown",
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2019-11-05T12:38:04Z",
"createdOn": "https://alice.example.net/",
"updatedAt": "2020-12-10T14:49:12Z",
"uploadedAt": "2019-11-05T12:38:04Z",
"uploadedOn": "https://alice.example.net/"
}
},
"relationships": {
"parent": {
"links": {
"related": "/files/f48d9370-e1ec-0137-8547-543d7eb8149c"
},
"data": {
"type": "io.cozy.files",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"
}
}
}
}
}
```
### POST /notes/:id/images
This route can be used to upload an image for a note. The note will be
transformed in a tar archive in the VFS, with the image saved inside it.
This route can only be used to upload images (the content-type is checked) and
requires a POST permission on the note.
The filename of the image is given in the query string, via the `Name`
parameter. In case of conflict (another image has the same name), the stack
will rename this image.
If the image is larger than 768px, a thumbnail will be generated.
#### Request
```http
POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images?Name=diagram.jpg HTTP/1.1
Accept: application/vnd.api+json
Content-Length: 123456
Content-Type: image/jpeg
Host: cozy.example.com
<content>
```
#### Response
```http
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.images",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c",
"meta": {
"rev": "1-588ab661"
},
"attributes": {
"name": "diagram.jpg",
"mime": "image/jpeg",
"width": 1000,
"height": 1000,
"willBeResized": true,
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2021-07-12T10:58:00Z",
"createdByApp": "notes",
"createdOn": "https://cozy.example.com/",
"updatedAt": "2021-07-12T10:58:00Z",
"uploadedAt": "2021-07-12T10:58:00Z",
"uploadedOn": "https://cozy.example.com/",
"uploadedBy": {
"slug": "notes"
}
}
},
"links": {
"self": "/notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images/e57d2ec0-d281-0139-2bed-543d7eb8149c/543d7eb8149c128b"
}
}
}
```
### POST /notes/:id/:image-id/copy
Copy an existing image to another note. It is similar to `POST
/notes/:id/images` as creating an image, but can be useful to avoid downloading
and then reuploading the image content when the user makes a copy/paste.
The `:id` and `:image-id` path parameters identify the source image. The
destination note will be specified in the query-string, as `To`.
#### Query-String
| Parameter | Description |
| ---------- | ------------------------------------------------- |
| To | the ID of the note where the image will be copied |
#### Request
```http
POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c/copy?To=76ddf590-905e-013c-5ff2-18c04daba326 HTTP/1.1
Accept: application/vnd.api+json
Host: cozy.example.com
```
#### Response
```http
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json
```
```json
{
"data": {
"type": "io.cozy.notes.images",
"id": "76ddf590-905e-013c-5ff2-18c04daba326/8d146530-905e-013c-5ff3-98b45e10905e",
"meta": {
"rev": "1-18c04dab"
},
"attributes": {
"name": "diagram.jpg",
"mime": "image/jpeg",
"width": 1000,
"height": 1000,
"willBeResized": true,
"cozyMetadata": {
"doctypeVersion": "1",
"metadataVersion": 1,
"createdAt": "2024-01-08T15:18:00Z",
"createdByApp": "notes",
"createdOn": "https://cozy.example.com/",
"updatedAt": "2024-01-08T15:18:00Z",
"uploadedAt": "2024-01-08T15:18:00Z",
"uploadedOn": "https://cozy.example.com/",
"uploadedBy": {
"slug": "notes"
}
}
},
"links": {
"self": "/notes/76ddf590-905e-013c-5ff2-18c04daba326/images/8d146530-905e-013c-5ff3-98b45e10905e/d251f620d98e1740"
}
}
}
```
## Real-time via websockets
You can subscribe to the [realtime](realtime.md) API for a document with the
`io.cozy.notes.events` doctype, and the id of a note file. It requires a permission
on this file, and it will send the events for this notes: changes of the title, the
steps applied, the telepointer updates, and images processed.
### Example
```
client > {"method": "AUTH",
"payload": "xxAppOrAuthTokenxx="}
client > {"method": "SUBSCRIBE",
"payload": {"type": "io.cozy.notes.events",
"id": "f48d9370-e1ec-0137-8547-543d7eb8149c"}}
server > {"event": "UPDATED",
"payload": {"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"type": "io.cozy.notes.events",
"doc": {"doctype": "io.cozy.notes.documents",
"sessionID": "543781490137",
"title": "this is the new title of this note"}}}
server > {"event": "CREATED",
"payload": {"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"type": "io.cozy.notes.events",
"doc": {"doctype": "io.cozy.notes.steps",
"sessionID": "543781490137",
"version": 6,
"stepType": "replace",
"from": 1,
"to": 1,
"slice": {"content": [{"type": "text", "text": "H"}]}}}}
server > {"event": "UPDATED",
"payload": {"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"type": "io.cozy.notes.events",
"doc": {"doctype": "io.cozy.notes.telepointers", "sessionID": "543781490137", "anchor": 7, "head": 12, "type": "textSelection"}}}
server > {"event": "UPDATED",
"payload": {"id": "f48d9370-e1ec-0137-8547-543d7eb8149c",
"type": "io.cozy.notes.events",
"doc": {"doctype": "io.cozy.notes.images",
"image_id": "e57d2ec0-d281-0139-2bed-543d7eb8149c",
"mime": "image/jpeg",
"width": 768,
"height": 768}}}
```