From 2e89a321397cb636e1301150800c1d3313848a31 Mon Sep 17 00:00:00 2001
From: mlbonhomme <bonhomme@teklia.com>
Date: Wed, 6 Mar 2024 18:39:57 +0100
Subject: [PATCH] wip API endpoints

---
 arkindex/documents/fixtures/data.json         | 1826 ++++++++++++++++-
 .../management/commands/build_fixtures.py     |   12 +-
 .../migrations/0029_processdataset_sets.py    |    4 +-
 arkindex/process/models.py                    |    8 +-
 arkindex/project/serializer_fields.py         |    9 +-
 arkindex/training/admin.py                    |   18 +-
 arkindex/training/api.py                      |    1 +
 arkindex/training/migrations/0001_initial.py  |    8 +-
 .../migrations/0007_datasetset_model.py       |    2 +-
 arkindex/training/models.py                   |   12 +-
 arkindex/training/serializers.py              |  114 +-
 arkindex/training/tests/test_datasets_api.py  |  270 +--
 12 files changed, 1893 insertions(+), 391 deletions(-)

diff --git a/arkindex/documents/fixtures/data.json b/arkindex/documents/fixtures/data.json
index 15e6fbb2ce..85895a434f 100644
--- a/arkindex/documents/fixtures/data.json
+++ b/arkindex/documents/fixtures/data.json
@@ -1,13 +1,111 @@
 [
 {
     "model": "process.process",
+<<<<<<< HEAD
     "pk": "76506eee-43ab-4caa-966c-9e8e5d10ef93",
+=======
+    "pk": "432278f2-a60e-4865-b474-de83833d0497",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "name": null,
         "creator": 1,
         "corpus": null,
+        "mode": "local",
+        "revision": null,
+        "activity_state": "disabled",
+        "started": null,
+        "finished": null,
+        "farm": null,
+        "element": null,
+        "folder_type": null,
+        "element_type": null,
+        "name_contains": null,
+        "ml_class": null,
+        "load_children": false,
+        "generate_thumbnails": false,
+        "chunks": 1,
+        "use_cache": false,
+        "use_gpu": false,
+        "template": null,
+        "bucket_name": null,
+        "prefix": null,
+        "files": []
+    }
+},
+{
+    "model": "process.process",
+    "pk": "c914b228-86a6-434b-81d8-f78751f02cf1",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "name": "Process fixture",
+        "creator": 2,
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "mode": "workers",
+        "revision": null,
+        "activity_state": "disabled",
+        "started": null,
+        "finished": null,
+        "farm": "ff732a3f-c9ac-43fe-8b22-c03cf82d2a4e",
+        "element": null,
+        "folder_type": null,
+        "element_type": null,
+        "name_contains": null,
+        "ml_class": null,
+        "load_children": false,
+        "generate_thumbnails": false,
+        "chunks": 1,
+        "use_cache": false,
+        "use_gpu": false,
+        "template": null,
+        "bucket_name": null,
+        "prefix": null,
+        "files": []
+    }
+},
+{
+    "model": "process.process",
+    "pk": "c992f023-baea-4c6d-92ba-e5bac0c2c0b4",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "name": null,
+        "creator": 2,
+        "corpus": null,
+        "mode": "local",
+        "revision": null,
+        "activity_state": "disabled",
+        "started": null,
+        "finished": null,
+        "farm": null,
+        "element": null,
+        "folder_type": null,
+        "element_type": null,
+        "name_contains": null,
+        "ml_class": null,
+        "load_children": false,
+        "generate_thumbnails": false,
+        "chunks": 1,
+        "use_cache": false,
+        "use_gpu": false,
+        "template": null,
+        "bucket_name": null,
+        "prefix": null,
+        "files": []
+    }
+},
+{
+    "model": "process.process",
+    "pk": "d6b43bc9-d87c-4c80-9211-f0c807506ad7",
+>>>>>>> 7912af40 (wip API endpoints)
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "name": null,
+        "creator": 1,
+        "corpus": null,
+<<<<<<< HEAD
         "mode": "local",
         "activity_state": "disabled",
         "started": null,
@@ -73,6 +171,14 @@
         "started": null,
         "finished": null,
         "farm": null,
+=======
+        "mode": "repository",
+        "revision": null,
+        "activity_state": "disabled",
+        "started": null,
+        "finished": null,
+        "farm": "ff732a3f-c9ac-43fe-8b22-c03cf82d2a4e",
+>>>>>>> 7912af40 (wip API endpoints)
         "element": null,
         "folder_type": null,
         "element_type": null,
@@ -91,6 +197,7 @@
 },
 {
     "model": "process.repository",
+<<<<<<< HEAD
     "pk": "bcfed350-d5be-4f27-b66a-042be3e6ee64",
     "fields": {
         "url": "http://gitlab/repo"
@@ -99,17 +206,35 @@
 {
     "model": "process.repository",
     "pk": "e3f470b1-fc46-4bc1-8117-30e1c62962b7",
+=======
+    "pk": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "url": "http://my_repo.fake/workers/worker"
     }
 },
+{
+    "model": "process.repository",
+    "pk": "deea5468-0e94-4215-bef3-efb8d18f0065",
+    "fields": {
+        "url": "http://gitlab/repo"
+    }
+},
 {
     "model": "process.revision",
+<<<<<<< HEAD
     "pk": "2d087aa1-82ba-4ec5-af14-c19e4213f913",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "repo": "e3f470b1-fc46-4bc1-8117-30e1c62962b7",
+=======
+    "pk": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "repo": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+>>>>>>> 7912af40 (wip API endpoints)
         "hash": "1337",
         "message": "My w0rk3r",
         "author": "Test user"
@@ -117,11 +242,19 @@
 },
 {
     "model": "process.revision",
+<<<<<<< HEAD
     "pk": "7876a435-f3a5-40f8-b30b-f388f22019bf",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "repo": "bcfed350-d5be-4f27-b66a-042be3e6ee64",
+=======
+    "pk": "6b139a49-ae71-4b64-8e69-e67a389e9cfa",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "repo": "deea5468-0e94-4215-bef3-efb8d18f0065",
+>>>>>>> 7912af40 (wip API endpoints)
         "hash": "42",
         "message": "Salve",
         "author": "Some user"
@@ -129,6 +262,7 @@
 },
 {
     "model": "process.worker",
+<<<<<<< HEAD
     "pk": "12b2344f-4871-40ad-aa1b-efaa70b5823f",
     "fields": {
         "name": "Document layout analyser",
@@ -136,12 +270,22 @@
         "type": "e84d4893-ae73-4162-acb6-13d606587644",
         "description": "",
         "repository": "e3f470b1-fc46-4bc1-8117-30e1c62962b7",
+=======
+    "pk": "049370f4-2328-40de-84a0-48e5bb45fcda",
+    "fields": {
+        "name": "Generic worker with a Model",
+        "slug": "generic",
+        "type": "3c93cbb2-97a1-4b0c-8ddf-98ee99760805",
+        "description": "",
+        "repository": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+>>>>>>> 7912af40 (wip API endpoints)
         "public": false,
         "archived": null
     }
 },
 {
     "model": "process.worker",
+<<<<<<< HEAD
     "pk": "1a18dc1d-49e3-4724-b1e3-cbc8da483610",
     "fields": {
         "name": "Worker requiring a GPU",
@@ -149,12 +293,48 @@
         "type": "20d3065e-0ef7-428b-888f-177f59e6ddd0",
         "description": "",
         "repository": "e3f470b1-fc46-4bc1-8117-30e1c62962b7",
+=======
+    "pk": "04ebb7e9-b8f8-4358-82cb-52bca4f2564b",
+    "fields": {
+        "name": "Document layout analyser",
+        "slug": "dla",
+        "type": "c2db222a-f974-4c20-979e-9e95e1a80ee7",
+        "description": "",
+        "repository": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+        "public": false,
+        "archived": null
+    }
+},
+{
+    "model": "process.worker",
+    "pk": "232e3930-353b-4840-b570-7057166ab8a7",
+    "fields": {
+        "name": "Recognizer",
+        "slug": "reco",
+        "type": "3c93cbb2-97a1-4b0c-8ddf-98ee99760805",
+        "description": "",
+        "repository": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+        "public": false,
+        "archived": null
+    }
+},
+{
+    "model": "process.worker",
+    "pk": "58c7ea56-3de0-4d49-bdc1-13d2d770202d",
+    "fields": {
+        "name": "Worker requiring a GPU",
+        "slug": "worker-gpu",
+        "type": "ea560a33-b00e-4fcb-a7fe-5d92827da405",
+        "description": "",
+        "repository": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+>>>>>>> 7912af40 (wip API endpoints)
         "public": false,
         "archived": null
     }
 },
 {
     "model": "process.worker",
+<<<<<<< HEAD
     "pk": "219444d1-2a84-49f4-94d6-d5c21e36fcb9",
     "fields": {
         "name": "Generic worker with a Model",
@@ -173,6 +353,13 @@
         "name": "Custom worker",
         "slug": "custom",
         "type": "64a618df-09d0-47eb-b999-02ceb0a114a4",
+=======
+    "pk": "8cf9ad2e-20da-42b1-8486-1b9b76d094f6",
+    "fields": {
+        "name": "Custom worker",
+        "slug": "custom",
+        "type": "8f8a02cd-e97f-479c-96d1-8d019f31e25b",
+>>>>>>> 7912af40 (wip API endpoints)
         "description": "",
         "repository": null,
         "public": false,
@@ -181,6 +368,7 @@
 },
 {
     "model": "process.worker",
+<<<<<<< HEAD
     "pk": "9775f6a1-6238-4943-b245-b69bde621912",
     "fields": {
         "name": "Recognizer",
@@ -201,12 +389,22 @@
         "type": "3a0b2c85-f53f-4ce7-942d-37c08f356880",
         "description": "",
         "repository": "e3f470b1-fc46-4bc1-8117-30e1c62962b7",
+=======
+    "pk": "de19f976-30a1-49bb-9dfb-a17300db9ccb",
+    "fields": {
+        "name": "File import",
+        "slug": "file_import",
+        "type": "1adb460c-149c-4b77-9d56-9a306ab49993",
+        "description": "",
+        "repository": "565a09bb-0f64-49b5-acbf-8e5fde104cbb",
+>>>>>>> 7912af40 (wip API endpoints)
         "public": false,
         "archived": null
     }
 },
 {
     "model": "process.workertype",
+<<<<<<< HEAD
     "pk": "20d3065e-0ef7-428b-888f-177f59e6ddd0",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -218,6 +416,9 @@
 {
     "model": "process.workertype",
     "pk": "3a0b2c85-f53f-4ce7-942d-37c08f356880",
+=======
+    "pk": "1adb460c-149c-4b77-9d56-9a306ab49993",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -227,7 +428,11 @@
 },
 {
     "model": "process.workertype",
+<<<<<<< HEAD
     "pk": "50729501-d9c4-473d-803f-a7cf25f0f9bd",
+=======
+    "pk": "3c93cbb2-97a1-4b0c-8ddf-98ee99760805",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -237,7 +442,11 @@
 },
 {
     "model": "process.workertype",
+<<<<<<< HEAD
     "pk": "64a618df-09d0-47eb-b999-02ceb0a114a4",
+=======
+    "pk": "8f8a02cd-e97f-479c-96d1-8d019f31e25b",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -247,19 +456,118 @@
 },
 {
     "model": "process.workertype",
+<<<<<<< HEAD
     "pk": "e84d4893-ae73-4162-acb6-13d606587644",
+=======
+    "pk": "c2db222a-f974-4c20-979e-9e95e1a80ee7",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "slug": "dla",
         "display_name": "Document Layout Analysis"
+<<<<<<< HEAD
+=======
+    }
+},
+{
+    "model": "process.workertype",
+    "pk": "ea560a33-b00e-4fcb-a7fe-5d92827da405",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "slug": "worker",
+        "display_name": "Worker requiring a GPU"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "process.workerversion",
+<<<<<<< HEAD
     "pk": "229fc630-728b-421b-a2de-9618bd8e401f",
     "fields": {
         "worker": "667a82ac-a19a-4e97-9239-35a3026246cb",
+=======
+    "pk": "0b84a002-efce-4fd6-b4a6-999376df80fa",
+    "fields": {
+        "worker": "04ebb7e9-b8f8-4358-82cb-52bca4f2564b",
+        "revision": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+        "version": null,
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "gpu_usage": "disabled",
+        "model_usage": "disabled",
+        "docker_image": "481b42e2-645c-47fe-937f-5b4431f10563",
+        "docker_image_iid": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
+},
+{
+    "model": "process.workerversion",
+    "pk": "110fd472-59f4-43fa-a954-0a8dd776c86d",
+    "fields": {
+        "worker": "232e3930-353b-4840-b570-7057166ab8a7",
+        "revision": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+        "version": null,
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "gpu_usage": "disabled",
+        "model_usage": "disabled",
+        "docker_image": "481b42e2-645c-47fe-937f-5b4431f10563",
+        "docker_image_iid": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
+},
+{
+    "model": "process.workerversion",
+    "pk": "2800edff-4e74-4fd0-8f31-a01cddfa4c09",
+    "fields": {
+        "worker": "58c7ea56-3de0-4d49-bdc1-13d2d770202d",
+        "revision": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+        "version": null,
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "gpu_usage": "required",
+        "model_usage": "disabled",
+        "docker_image": "481b42e2-645c-47fe-937f-5b4431f10563",
+        "docker_image_iid": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
+},
+{
+    "model": "process.workerversion",
+    "pk": "5cc66882-dfda-4800-9422-8e0fb28e0287",
+    "fields": {
+        "worker": "049370f4-2328-40de-84a0-48e5bb45fcda",
+        "revision": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+        "version": null,
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "gpu_usage": "disabled",
+        "model_usage": "required",
+        "docker_image": "481b42e2-645c-47fe-937f-5b4431f10563",
+        "docker_image_iid": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
+},
+{
+    "model": "process.workerversion",
+    "pk": "6df3f42d-36fd-4483-8261-d2550938f66e",
+    "fields": {
+        "worker": "8cf9ad2e-20da-42b1-8486-1b9b76d094f6",
+>>>>>>> 7912af40 (wip API endpoints)
         "revision": null,
         "version": 1,
         "configuration": {
@@ -276,6 +584,7 @@
 },
 {
     "model": "process.workerversion",
+<<<<<<< HEAD
     "pk": "57cd018c-43e2-491e-9684-3b939df52921",
     "fields": {
         "worker": "df6dbbb2-0526-46f9-8da2-5ada8f93826a",
@@ -354,6 +663,12 @@
     "fields": {
         "worker": "9775f6a1-6238-4943-b245-b69bde621912",
         "revision": "2d087aa1-82ba-4ec5-af14-c19e4213f913",
+=======
+    "pk": "728c1c89-5a6e-4dc9-85fb-4702b760c1f7",
+    "fields": {
+        "worker": "de19f976-30a1-49bb-9dfb-a17300db9ccb",
+        "revision": "174a7683-f6bb-402b-8ff5-3b22785f35a2",
+>>>>>>> 7912af40 (wip API endpoints)
         "version": null,
         "configuration": {
             "test": 42
@@ -361,18 +676,60 @@
         "state": "available",
         "gpu_usage": "disabled",
         "model_usage": "disabled",
+<<<<<<< HEAD
         "docker_image": null,
         "docker_image_iid": "registry.somewhere.com/something:latest",
+=======
+        "docker_image": "481b42e2-645c-47fe-937f-5b4431f10563",
+        "docker_image_iid": null,
+>>>>>>> 7912af40 (wip API endpoints)
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z"
     }
 },
 {
     "model": "process.workerrun",
+<<<<<<< HEAD
     "pk": "14356945-e3a4-4d8b-b9b2-b4bc5e9287cc",
     "fields": {
         "process": "76506eee-43ab-4caa-966c-9e8e5d10ef93",
         "version": "229fc630-728b-421b-a2de-9618bd8e401f",
+=======
+    "pk": "baf81f6a-818a-484e-8d1a-a240b20ab9e3",
+    "fields": {
+        "process": "c914b228-86a6-434b-81d8-f78751f02cf1",
+        "version": "0b84a002-efce-4fd6-b4a6-999376df80fa",
+        "model_version": null,
+        "parents": "[]",
+        "configuration": null,
+        "summary": "Worker Document layout analyser @ 0b84a0",
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "has_results": false
+    }
+},
+{
+    "model": "process.workerrun",
+    "pk": "20c4817e-b999-41e0-a061-85deb7df73df",
+    "fields": {
+        "process": "c914b228-86a6-434b-81d8-f78751f02cf1",
+        "version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
+        "model_version": null,
+        "parents": "[\"baf81f6a-818a-484e-8d1a-a240b20ab9e3\"]",
+        "configuration": null,
+        "summary": "Worker Recognizer @ 110fd4",
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "has_results": false
+    }
+},
+{
+    "model": "process.workerrun",
+    "pk": "81e444be-04be-47b6-b625-a3f2e61a4456",
+    "fields": {
+        "process": "432278f2-a60e-4865-b474-de83833d0497",
+        "version": "6df3f42d-36fd-4483-8261-d2550938f66e",
+>>>>>>> 7912af40 (wip API endpoints)
         "model_version": null,
         "parents": "[]",
         "configuration": null,
@@ -384,6 +741,7 @@
 },
 {
     "model": "process.workerrun",
+<<<<<<< HEAD
     "pk": "2f828b7f-c169-4a8e-9555-0b4060e05641",
     "fields": {
         "process": "7a6fed8c-ed9c-4714-8036-7048462ce0f2",
@@ -418,6 +776,12 @@
     "fields": {
         "process": "b6b7dbcb-e134-4274-93fd-9d6d06818c6f",
         "version": "229fc630-728b-421b-a2de-9618bd8e401f",
+=======
+    "pk": "ed5aaec9-a928-42ab-8166-81fbe92e7959",
+    "fields": {
+        "process": "c992f023-baea-4c6d-92ba-e5bac0c2c0b4",
+        "version": "6df3f42d-36fd-4483-8261-d2550938f66e",
+>>>>>>> 7912af40 (wip API endpoints)
         "model_version": null,
         "parents": "[]",
         "configuration": null,
@@ -429,7 +793,11 @@
 },
 {
     "model": "documents.corpus",
+<<<<<<< HEAD
     "pk": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+=======
+    "pk": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -442,11 +810,16 @@
 },
 {
     "model": "documents.elementtype",
+<<<<<<< HEAD
     "pk": "329625fb-1514-492a-9567-e231f7646648",
     "fields": {
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
-        "slug": "page",
-        "display_name": "Page",
+=======
+    "pk": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+    "fields": {
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "slug": "word",
+        "display_name": "Word",
         "folder": false,
         "indexable": false,
         "color": "28b62c"
@@ -454,23 +827,23 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "ab1c133b-71d0-4928-b388-7c12345a8416",
+    "pk": "18027add-0729-400d-a225-60927f1dd2d9",
     "fields": {
-        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
-        "slug": "text_line",
-        "display_name": "Line",
-        "folder": false,
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "slug": "volume",
+        "display_name": "Volume",
+        "folder": true,
         "indexable": false,
         "color": "28b62c"
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "c196f23a-6843-48e1-a885-c7cda27e64ca",
+    "pk": "1ca6552d-f876-4d2a-a167-38736ebed338",
     "fields": {
-        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
-        "slug": "act",
-        "display_name": "Act",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "slug": "text_line",
+        "display_name": "Line",
         "folder": false,
         "indexable": false,
         "color": "28b62c"
@@ -478,10 +851,72 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "d15930a5-ebb8-40aa-968d-8bd2cf504230",
+    "pk": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
     "fields": {
-        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
-        "slug": "word",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "slug": "surface",
+        "display_name": "Surface",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
+    }
+},
+{
+    "model": "documents.elementtype",
+    "pk": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+    "fields": {
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "slug": "act",
+        "display_name": "Act",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
+    }
+},
+{
+    "model": "documents.elementtype",
+    "pk": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+    "fields": {
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+>>>>>>> 7912af40 (wip API endpoints)
+        "slug": "page",
+        "display_name": "Page",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
+    }
+},
+{
+<<<<<<< HEAD
+    "model": "documents.elementtype",
+    "pk": "ab1c133b-71d0-4928-b388-7c12345a8416",
+    "fields": {
+        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+        "slug": "text_line",
+        "display_name": "Line",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
+    }
+},
+{
+    "model": "documents.elementtype",
+    "pk": "c196f23a-6843-48e1-a885-c7cda27e64ca",
+    "fields": {
+        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+        "slug": "act",
+        "display_name": "Act",
+        "folder": false,
+        "indexable": false,
+        "color": "28b62c"
+    }
+},
+{
+    "model": "documents.elementtype",
+    "pk": "d15930a5-ebb8-40aa-968d-8bd2cf504230",
+    "fields": {
+        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+        "slug": "word",
         "display_name": "Word",
         "folder": false,
         "indexable": false,
@@ -518,65 +953,217 @@
     "fields": {
         "element": "9fc5e0a3-9afb-493e-bf0f-fc2998ba4ba4",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\"]",
+=======
+    "model": "documents.elementpath",
+    "pk": "00bd8cd6-1b43-4703-868a-f6ad29891fee",
+    "fields": {
+        "element": "e590e52a-11ec-4e27-b3b1-c67cc589ced8",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"bdea4cf0-63bf-4918-b67d-b879d09f3c95\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "156e125d-4550-4a72-a124-3b5e7fe25e77",
     "fields": {
         "element": "c8e488da-28d8-467e-a651-7d6f2ad6600d",
         "path": "[\"2cd80ca1-7d55-4750-8c90-2b693e14a058\"]",
+=======
+    "pk": "057773ab-6c41-4163-aca8-73e742087b50",
+    "fields": {
+        "element": "81938246-57ff-49ad-bc79-d07de4275096",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"3dc4ff7a-9a40-431b-b692-a2b5af381ffd\"]",
+        "ordering": 1
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "05a8caeb-f351-4f3b-91c1-d0aff1ab9d73",
+    "fields": {
+        "element": "2f7f15c7-c39b-4164-aea0-050c2a0e9d34",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"454b9f6d-8b0d-4313-baa3-82ccf8856d42\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "17526830-1f55-41e1-82c5-6faf34831a0d",
     "fields": {
         "element": "7ea6161f-62f5-4bdf-9412-bbc4d13b3e6f",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"d9744e02-66ef-424e-a71c-88b94b209688\"]",
         "ordering": 0
+=======
+    "pk": "07cd2fbb-2cfd-4b53-86fe-d37fcc6d3bdb",
+    "fields": {
+        "element": "7c1ba0f5-1c2a-45d8-8ef1-6217e06e079b",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"2a08be28-27f2-48f8-8d87-437893d389ca\"]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "0a010ead-3329-41fc-83a7-b7f2d6d847f2",
+    "fields": {
+        "element": "b46d402f-385c-42c8-bca3-4cf732c6b952",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"f3a388d1-9968-4486-9e3b-e5a2a11947b1\"]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "1260e6b9-95e3-4667-abc6-d80ab1b6ecc5",
+    "fields": {
+        "element": "77ced3ba-7f04-48c7-b5fa-2b101d191c23",
+        "path": "[\"c348ff6e-786b-445a-a828-a693fb000fe8\"]",
+        "ordering": 1
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "210c3ff2-1aac-4b1d-bcff-67a76b2bc4f9",
     "fields": {
         "element": "e7027313-7910-44b4-bdff-28e8d187c0b4",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\"]",
         "ordering": 5
+=======
+    "pk": "221540c3-58b4-4839-b842-11dfbc608100",
+    "fields": {
+        "element": "fa35b384-692f-4b42-91ba-60d384ef251f",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"1444e97e-4873-4731-9b75-79f931c9dc9e\"]",
+        "ordering": 1
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "21af7d64-10db-43f4-a0dd-386be73314cd",
     "fields": {
         "element": "2df1881f-d666-43c9-8af7-507b277c4e23",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"02a6f67e-c7d4-4dec-b3a0-9f9ab3f2ee99\"]",
+=======
+    "pk": "25f13dc7-3bc1-40cf-8c9e-342ca2bc8747",
+    "fields": {
+        "element": "454b9f6d-8b0d-4313-baa3-82ccf8856d42",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "262709fc-3d1f-46e2-8ba5-5c63b8d2b96f",
     "fields": {
         "element": "d9744e02-66ef-424e-a71c-88b94b209688",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\"]",
         "ordering": 7
+=======
+    "pk": "27ca92e0-f081-4ce4-b23a-cf1a1d5b7f13",
+    "fields": {
+        "element": "549a9a87-0632-4846-962d-7799147e0225",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 4
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "32644adb-c33b-47bd-befe-f5d2142d60ee",
     "fields": {
         "element": "ec742315-a1e6-4cf2-96c0-abe2b0e0e3fc",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"9fc5e0a3-9afb-493e-bf0f-fc2998ba4ba4\"]",
+=======
+    "pk": "2ed0a5dc-1c04-49c5-b62a-4f07d804e982",
+    "fields": {
+        "element": "1f8e08ad-ee8e-4924-a0b3-740722dfae47",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"3dc4ff7a-9a40-431b-b692-a2b5af381ffd\"]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "3ceef7ee-c057-459b-b267-3e5f1de2d754",
+    "fields": {
+        "element": "d3b1f490-1ac8-430e-b0d3-eb617d90b900",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"454b9f6d-8b0d-4313-baa3-82ccf8856d42\"]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "56e3e8b7-7d46-459f-a924-98201890e80b",
+    "fields": {
+        "element": "ffffc01b-7577-4a93-9148-02fdc1f80435",
+        "path": "[\"c348ff6e-786b-445a-a828-a693fb000fe8\"]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "6b97040b-ebdb-49b8-9702-367f55ab4e49",
+    "fields": {
+        "element": "6d6b7b80-6783-42ef-88ec-15bdbe8ffb65",
+        "path": "[]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "758e2947-eb09-4ac3-9deb-2ff8d910f6b8",
+    "fields": {
+        "element": "f3a388d1-9968-4486-9e3b-e5a2a11947b1",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 3
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "78069f17-72aa-49c5-a433-2286c4bef207",
+    "fields": {
+        "element": "bdea4cf0-63bf-4918-b67d-b879d09f3c95",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 6
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "78817bcc-fb50-445a-8fdf-7f0812f2d4f0",
+    "fields": {
+        "element": "a9c73703-3711-46ac-957f-25f9bb77af76",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"454b9f6d-8b0d-4313-baa3-82ccf8856d42\"]",
+        "ordering": 1
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "9a7a9ea5-1d70-4159-a1cd-76cd03cd1bd3",
+    "fields": {
+        "element": "416d13a8-4a15-4641-9b68-36862e80c176",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"549a9a87-0632-4846-962d-7799147e0225\"]",
+        "ordering": 1
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "a15f789f-d2aa-43af-b66b-a437ad37c9a2",
+    "fields": {
+        "element": "39d46933-549e-40cc-93e4-3535db7ad8a0",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"3dc4ff7a-9a40-431b-b692-a2b5af381ffd\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "3a86e5d2-3c7c-474f-82b1-60dae09a82b4",
     "fields": {
         "element": "dc66eac3-a4e9-4c55-a4a8-d239bd79f3f6",
@@ -590,29 +1177,60 @@
     "fields": {
         "element": "b8d9cf10-dc77-4a41-90f8-badf9718ebb9",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"f530bd2f-d0ab-4f14-9d98-087486c4b1ab\"]",
+=======
+    "pk": "ad4f56ef-cccc-4dc3-8922-5fa338e93fa2",
+    "fields": {
+        "element": "1145ba8e-4bd5-4f2f-8bb1-c307295d88a0",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"549a9a87-0632-4846-962d-7799147e0225\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "650ef880-9d63-4164-8d50-b7dff16ca738",
     "fields": {
         "element": "aec1257f-bcbe-41d5-8983-966da539e912",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"e7027313-7910-44b4-bdff-28e8d187c0b4\"]",
+=======
+    "pk": "b6418b10-676e-4928-9552-921f8de4805e",
+    "fields": {
+        "element": "3dc4ff7a-9a40-431b-b692-a2b5af381ffd",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 2
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "c4abc40a-c4e2-4910-b62e-7bc95ea064f3",
+    "fields": {
+        "element": "2ef2d52a-0316-4eb6-a3f4-a48c4e25ce7c",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"1444e97e-4873-4731-9b75-79f931c9dc9e\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "666416c1-5aa0-4f57-a21f-b7585b10efd2",
     "fields": {
         "element": "f75ca797-0067-4711-b899-6ed39b0a6f1a",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\"]",
         "ordering": 4
+=======
+    "pk": "d4439a5a-5934-4b5a-b956-853ea89dd8d4",
+    "fields": {
+        "element": "9e7e2de2-e970-4e4f-81e7-b90008d474c0",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"eed5499a-e95f-4f06-baa0-145d917a5b0c\"]",
+        "ordering": 0
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "6f42e63d-d4ba-495b-8e22-e059577c669f",
     "fields": {
         "element": "f530bd2f-d0ab-4f14-9d98-087486c4b1ab",
@@ -626,19 +1244,78 @@
     "fields": {
         "element": "39210eb6-70a9-4660-8a45-5c6957508936",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\"]",
+=======
+    "pk": "d5d57a9e-97fb-401f-a128-5fc524946c0e",
+    "fields": {
+        "element": "ee161939-65e6-4e1f-be80-ea142dfb0c60",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"1444e97e-4873-4731-9b75-79f931c9dc9e\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 3
     }
 },
 {
     "model": "documents.elementpath",
+<<<<<<< HEAD
     "pk": "733ddae3-62e2-433a-b322-41bb6502ac93",
     "fields": {
         "element": "34cd2540-0a05-4812-add5-f24c08d46f73",
         "path": "[\"1d4b82fe-f9c5-4012-a9ae-c2ff83c9cc02\", \"1d0f7ea6-6455-4a8d-ade2-a853f8ab7e08\"]",
+=======
+    "pk": "deb7d260-5c5c-4159-9eeb-4f98e39e1a56",
+    "fields": {
+        "element": "c348ff6e-786b-445a-a828-a693fb000fe8",
+        "path": "[]",
+        "ordering": 0
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "ed85c4fa-f853-428c-bd3e-f084e9274f50",
+    "fields": {
+        "element": "6953caa3-b8bb-46a8-a222-1f386ff539f5",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\", \"1444e97e-4873-4731-9b75-79f931c9dc9e\"]",
+        "ordering": 2
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "f59638f1-17e6-4715-9672-8832bd12c5fb",
+    "fields": {
+        "element": "eed5499a-e95f-4f06-baa0-145d917a5b0c",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 5
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "f663a425-1981-4c25-9e3c-123a1a025db5",
+    "fields": {
+        "element": "2a08be28-27f2-48f8-8d87-437893d389ca",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+        "ordering": 7
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "ff0bca17-626f-4671-bc4e-70a9f44ad702",
+    "fields": {
+        "element": "97394f5f-6146-42be-8038-0d735e12d5f1",
+        "path": "[\"c348ff6e-786b-445a-a828-a693fb000fe8\"]",
+        "ordering": 2
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "ff852e37-1ca6-43dd-b47a-c4530c0d46c1",
+    "fields": {
+        "element": "1444e97e-4873-4731-9b75-79f931c9dc9e",
+        "path": "[\"6d6b7b80-6783-42ef-88ec-15bdbe8ffb65\"]",
+>>>>>>> 7912af40 (wip API endpoints)
         "ordering": 0
     }
 },
 {
+<<<<<<< HEAD
     "model": "documents.elementpath",
     "pk": "79ecb1ed-8036-4e88-a659-605fb3b5c8aa",
     "fields": {
@@ -844,6 +1521,21 @@
         "worker_run": null,
         "image": "f5ddf7e0-3dd3-4f4f-ada6-f42de7be869d",
         "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+=======
+    "model": "documents.element",
+    "pk": "1145ba8e-4bd5-4f2f-8bb1-c307295d88a0",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface B",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
+>>>>>>> 7912af40 (wip API endpoints)
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -851,6 +1543,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "2cd80ca1-7d55-4750-8c90-2b693e14a058",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -858,6 +1551,53 @@
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
         "type": "e28100cb-49a4-4837-a9ae-81a519ebb43f",
         "name": "Volume 2",
+=======
+    "pk": "1444e97e-4873-4731-9b75-79f931c9dc9e",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 1, page 1r",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "1f8e08ad-ee8e-4924-a0b3-740722dfae47",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "PARIS",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "2a08be28-27f2-48f8-8d87-437893d389ca",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+        "name": "Act 5",
+>>>>>>> 7912af40 (wip API endpoints)
         "creator": null,
         "worker_version": null,
         "worker_run": null,
@@ -870,6 +1610,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "2df1881f-d666-43c9-8af7-507b277c4e23",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -882,6 +1623,20 @@
         "worker_run": null,
         "image": "a38b69a3-a4f8-4dfc-a6b9-38ea2e52c713",
         "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+=======
+    "pk": "2ef2d52a-0316-4eb6-a3f4-a48c4e25ce7c",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "PARIS",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+>>>>>>> 7912af40 (wip API endpoints)
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -889,17 +1644,30 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "2e8101c4-6fca-49b6-9b7b-41554facfa01",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
         "type": "d15930a5-ebb8-40aa-968d-8bd2cf504230",
+=======
+    "pk": "2f7f15c7-c39b-4164-aea0-050c2a0e9d34",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "DATUM",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
+<<<<<<< HEAD
         "image": "a38b69a3-a4f8-4dfc-a6b9-38ea2e52c713",
+=======
+        "image": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+>>>>>>> 7912af40 (wip API endpoints)
         "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
         "rotation_angle": 0,
         "mirrored": false,
@@ -908,6 +1676,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "344f6b5b-b001-4084-950c-1925fdd2eef4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -920,6 +1689,20 @@
         "worker_run": null,
         "image": "f250d3f3-bd56-4a2f-bffc-fc3a33cd1902",
         "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+=======
+    "pk": "39d46933-549e-40cc-93e4-3535db7ad8a0",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "DATUM",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+>>>>>>> 7912af40 (wip API endpoints)
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -927,6 +1710,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "34cd2540-0a05-4812-add5-f24c08d46f73",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -939,6 +1723,20 @@
         "worker_run": null,
         "image": "a38b69a3-a4f8-4dfc-a6b9-38ea2e52c713",
         "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)",
+=======
+    "pk": "3dc4ff7a-9a40-431b-b692-a2b5af381ffd",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 1, page 2r",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+>>>>>>> 7912af40 (wip API endpoints)
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -946,6 +1744,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "39210eb6-70a9-4660-8a45-5c6957508936",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -953,11 +1752,19 @@
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
         "type": "c196f23a-6843-48e1-a885-c7cda27e64ca",
         "name": "Act 1",
+=======
+    "pk": "416d13a8-4a15-4641-9b68-36862e80c176",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface C",
         "creator": null,
         "worker_version": null,
         "worker_run": null,
-        "image": null,
-        "polygon": null,
+        "image": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -965,7 +1772,47 @@
 },
 {
     "model": "documents.element",
-    "pk": "4fed0e6a-9e3f-4e59-9c70-c5e74cc6d73c",
+    "pk": "454b9f6d-8b0d-4313-baa3-82ccf8856d42",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 1, page 1v",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "549a9a87-0632-4846-962d-7799147e0225",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+        "name": "Act 2",
+>>>>>>> 7912af40 (wip API endpoints)
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": null,
+        "polygon": null,
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+<<<<<<< HEAD
+    "pk": "4fed0e6a-9e3f-4e59-9c70-c5e74cc6d73c",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -996,6 +1843,20 @@
         "worker_run": null,
         "image": "a38b69a3-a4f8-4dfc-a6b9-38ea2e52c713",
         "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
+=======
+    "pk": "6953caa3-b8bb-46a8-a222-1f386ff539f5",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "DATUM",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)",
+>>>>>>> 7912af40 (wip API endpoints)
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
@@ -1003,6 +1864,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "86304b47-3d6a-48dd-a903-d0e09cde91ba",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -1200,6 +2062,15 @@
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
         "type": "c196f23a-6843-48e1-a885-c7cda27e64ca",
         "name": "Act 5",
+=======
+    "pk": "6d6b7b80-6783-42ef-88ec-15bdbe8ffb65",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "18027add-0729-400d-a225-60927f1dd2d9",
+        "name": "Volume 1",
+>>>>>>> 7912af40 (wip API endpoints)
         "creator": null,
         "worker_version": null,
         "worker_run": null,
@@ -1212,6 +2083,7 @@
 },
 {
     "model": "documents.element",
+<<<<<<< HEAD
     "pk": "dc66eac3-a4e9-4c55-a4a8-d239bd79f3f6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -1322,10 +2194,322 @@
         "rotation_angle": 0,
         "mirrored": false,
         "confidence": null
+=======
+    "pk": "77ced3ba-7f04-48c7-b5fa-2b101d191c23",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 2, page 1v",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "d9c10a6b-6d15-4d60-a934-15a79d0b0bce",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "7c1ba0f5-1c2a-45d8-8ef1-6217e06e079b",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface F",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "81938246-57ff-49ad-bc79-d07de4275096",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "ROY",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "97394f5f-6146-42be-8038-0d735e12d5f1",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 2, page 2r",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "a6d3f3bc-986d-4618-8a87-fb1b86d9b866",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "9e7e2de2-e970-4e4f-81e7-b90008d474c0",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface D",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "a9c73703-3711-46ac-957f-25f9bb77af76",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "ROY",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "b46d402f-385c-42c8-bca3-4cf732c6b952",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface A",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "bdea4cf0-63bf-4918-b67d-b879d09f3c95",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+        "name": "Act 4",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": null,
+        "polygon": null,
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "c348ff6e-786b-445a-a828-a693fb000fe8",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "18027add-0729-400d-a225-60927f1dd2d9",
+        "name": "Volume 2",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": null,
+        "polygon": null,
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "d3b1f490-1ac8-430e-b0d3-eb617d90b900",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "PARIS",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "e590e52a-11ec-4e27-b3b1-c67cc589ced8",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "2bee95f7-e16e-41ae-a61d-51b9a22c3fa0",
+        "name": "Surface E",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "ee161939-65e6-4e1f-be80-ea142dfb0c60",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "1ca6552d-f876-4d2a-a167-38736ebed338",
+        "name": "Text line",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "eed5499a-e95f-4f06-baa0-145d917a5b0c",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+        "name": "Act 3",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": null,
+        "polygon": null,
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "f3a388d1-9968-4486-9e3b-e5a2a11947b1",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "571f6a9b-e38b-4bd6-b22f-85bd66cc1a5e",
+        "name": "Act 1",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": null,
+        "polygon": null,
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "fa35b384-692f-4b42-91ba-60d384ef251f",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "167b45fd-13a2-4ef8-b937-47f64e2665a8",
+        "name": "ROY",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.element",
+    "pk": "ffffc01b-7577-4a93-9148-02fdc1f80435",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "a8f287b7-31f2-491a-b13f-cd2aa0c461d4",
+        "name": "Volume 2, page 1r",
+        "creator": null,
+        "worker_version": null,
+        "worker_run": null,
+        "image": "0e219e81-b8ab-484b-a8f2-cb848a9c8b45",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)",
+        "rotation_angle": 0,
+        "mirrored": false,
+        "confidence": null
+    }
+},
+{
+    "model": "documents.entitytype",
+    "pk": "270158cd-aaa6-46c6-b62f-036cdcc77e9b",
+    "fields": {
+        "name": "person",
+        "color": "ff0000",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.entitytype",
+<<<<<<< HEAD
     "pk": "0199d0f3-a2e6-4422-9202-2be9fe6d9dff",
     "fields": {
         "name": "number",
@@ -1349,44 +2533,174 @@
         "name": "organization",
         "color": "ff0000",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12"
+=======
+    "pk": "2cb12ff7-fc14-4d6b-a0dd-0845333171f5",
+    "fields": {
+        "name": "organization",
+        "color": "ff0000",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.entitytype",
+<<<<<<< HEAD
     "pk": "7051555a-449f-4ebb-a519-f5b65517a520",
     "fields": {
         "name": "person",
         "color": "ff0000",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12"
+=======
+    "pk": "67190699-79a4-4f85-aaed-60e05adefd1a",
+    "fields": {
+        "name": "number",
+        "color": "ff0000",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.entitytype",
+<<<<<<< HEAD
     "pk": "c6cb242c-688d-484f-87d1-42cabd41f67f",
     "fields": {
         "name": "date",
         "color": "ff0000",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12"
+=======
+    "pk": "a5e2132e-f991-4ed9-ad10-a9fabd1401df",
+    "fields": {
+        "name": "date",
+        "color": "ff0000",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9"
+    }
+},
+{
+    "model": "documents.entitytype",
+    "pk": "feaa7348-a77e-4af7-9763-2ca98b22c623",
+    "fields": {
+        "name": "location",
+        "color": "ff0000",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9"
+>>>>>>> 7912af40 (wip API endpoints)
+    }
+},
+{
+    "model": "documents.transcription",
+<<<<<<< HEAD
+    "pk": "05882194-0210-441a-a167-f0b58cca0d2e",
+    "fields": {
+        "element": "2df1881f-d666-43c9-8af7-507b277c4e23",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "ROY",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+    "pk": "29dca1b6-8661-4bb5-933f-0b05ac7c30bb",
+    "fields": {
+        "element": "86304b47-3d6a-48dd-a903-d0e09cde91ba",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "ROY",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+    "pk": "413a4b08-c496-4925-a440-e9edad4a9dc1",
+    "fields": {
+        "element": "b8d9cf10-dc77-4a41-90f8-badf9718ebb9",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "PARIS",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+    "pk": "5107512b-9bda-4f59-98e0-a0ff40c76d11",
+    "fields": {
+        "element": "ec742315-a1e6-4cf2-96c0-abe2b0e0e3fc",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "DATUM",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+    "pk": "5b4bd0f0-63fa-43d1-970f-a79c44784392",
+    "fields": {
+        "element": "344f6b5b-b001-4084-950c-1925fdd2eef4",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "PARIS",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+    "pk": "7e865edb-f16e-4406-a497-682e5a946593",
+    "fields": {
+        "element": "9fc5e0a3-9afb-493e-bf0f-fc2998ba4ba4",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+=======
+    "pk": "0028aefa-a8d3-4a0f-8634-6d1f0b619bb1",
+    "fields": {
+        "element": "1444e97e-4873-4731-9b75-79f931c9dc9e",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
+>>>>>>> 7912af40 (wip API endpoints)
+        "worker_run": null,
+        "text": "Lorem ipsum dolor sit amet",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
+    }
+},
+{
+    "model": "documents.transcription",
+<<<<<<< HEAD
+    "pk": "b3ec03c1-fa36-4347-b3ad-64abf63ce10c",
+    "fields": {
+        "element": "2039b7b8-15cb-4b1f-a9e6-c681aa20e13a",
+        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "worker_run": null,
+        "text": "DATUM",
+        "orientation": "horizontal-lr",
+        "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "05882194-0210-441a-a167-f0b58cca0d2e",
+    "pk": "bf9dddc1-c158-487c-99b4-37e0f7f44759",
     "fields": {
-        "element": "2df1881f-d666-43c9-8af7-507b277c4e23",
+        "element": "4fed0e6a-9e3f-4e59-9c70-c5e74cc6d73c",
         "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
         "worker_run": null,
-        "text": "ROY",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "29dca1b6-8661-4bb5-933f-0b05ac7c30bb",
+    "pk": "e1978d01-9182-4a42-a76f-7ae776aaaf55",
     "fields": {
-        "element": "86304b47-3d6a-48dd-a903-d0e09cde91ba",
+        "element": "e9aa6eb2-eb0b-4503-9bbf-c3d27b9cce5f",
         "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+=======
+    "pk": "3db65ed1-320a-4008-a887-747e3a3c6add",
+    "fields": {
+        "element": "a9c73703-3711-46ac-957f-25f9bb77af76",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
+>>>>>>> 7912af40 (wip API endpoints)
         "worker_run": null,
         "text": "ROY",
         "orientation": "horizontal-lr",
@@ -1395,10 +2709,16 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "413a4b08-c496-4925-a440-e9edad4a9dc1",
+<<<<<<< HEAD
+    "pk": "f5b81d19-ebb7-412d-9deb-455d72aaf829",
     "fields": {
-        "element": "b8d9cf10-dc77-4a41-90f8-badf9718ebb9",
+        "element": "2e8101c4-6fca-49b6-9b7b-41554facfa01",
         "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+=======
+    "pk": "5e252d09-6240-43fe-b531-ea5f8d150c91",
+    "fields": {
+        "element": "d3b1f490-1ac8-430e-b0d3-eb617d90b900",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
         "text": "PARIS",
         "orientation": "horizontal-lr",
@@ -1407,46 +2727,55 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "5107512b-9bda-4f59-98e0-a0ff40c76d11",
+    "pk": "6fb2d310-d2ce-4de8-89fc-2af120735fc1",
     "fields": {
-        "element": "ec742315-a1e6-4cf2-96c0-abe2b0e0e3fc",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "2ef2d52a-0316-4eb6-a3f4-a48c4e25ce7c",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
-        "text": "DATUM",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "5b4bd0f0-63fa-43d1-970f-a79c44784392",
+    "pk": "9fd17563-7f50-4073-b286-42ddf7e47fcc",
     "fields": {
-        "element": "344f6b5b-b001-4084-950c-1925fdd2eef4",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "39d46933-549e-40cc-93e4-3535db7ad8a0",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
+>>>>>>> 7912af40 (wip API endpoints)
         "worker_run": null,
-        "text": "PARIS",
+        "text": "DATUM",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
+<<<<<<< HEAD
+    "model": "documents.allowedmetadata",
+    "pk": "6437fdd1-97c0-4fff-a325-039d0379bdbe",
+    "fields": {
+        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+        "type": "text",
+        "name": "folio"
+=======
     "model": "documents.transcription",
-    "pk": "7e865edb-f16e-4406-a497-682e5a946593",
+    "pk": "b1260aaa-bcba-43ed-bab9-27a6effa99e0",
     "fields": {
-        "element": "9fc5e0a3-9afb-493e-bf0f-fc2998ba4ba4",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "1f8e08ad-ee8e-4924-a0b3-740722dfae47",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
-        "text": "Lorem ipsum dolor sit amet",
+        "text": "PARIS",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "b3ec03c1-fa36-4347-b3ad-64abf63ce10c",
+    "pk": "b58a6fca-0ef0-4a9a-b020-cfc5d2bf0c38",
     "fields": {
-        "element": "2039b7b8-15cb-4b1f-a9e6-c681aa20e13a",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "2f7f15c7-c39b-4164-aea0-050c2a0e9d34",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
         "text": "DATUM",
         "orientation": "horizontal-lr",
@@ -1455,22 +2784,22 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "bf9dddc1-c158-487c-99b4-37e0f7f44759",
+    "pk": "bfa7949c-ad04-4c20-a92f-2e67006c4b5e",
     "fields": {
-        "element": "4fed0e6a-9e3f-4e59-9c70-c5e74cc6d73c",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "81938246-57ff-49ad-bc79-d07de4275096",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
-        "text": "PARIS",
+        "text": "ROY",
         "orientation": "horizontal-lr",
         "confidence": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "e1978d01-9182-4a42-a76f-7ae776aaaf55",
+    "pk": "e66cc126-2d3c-4419-bd18-c4f8f0cb4bbb",
     "fields": {
-        "element": "e9aa6eb2-eb0b-4503-9bbf-c3d27b9cce5f",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "fa35b384-692f-4b42-91ba-60d384ef251f",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
         "text": "ROY",
         "orientation": "horizontal-lr",
@@ -1479,35 +2808,52 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "f5b81d19-ebb7-412d-9deb-455d72aaf829",
+    "pk": "ebce2b3b-c593-4a72-bf99-ffd16d552aa0",
     "fields": {
-        "element": "2e8101c4-6fca-49b6-9b7b-41554facfa01",
-        "worker_version": "f62b2301-0447-4848-9848-a731ad801d60",
+        "element": "6953caa3-b8bb-46a8-a222-1f386ff539f5",
+        "worker_version": "110fd472-59f4-43fa-a954-0a8dd776c86d",
         "worker_run": null,
         "text": "DATUM",
         "orientation": "horizontal-lr",
         "confidence": 1.0
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "6437fdd1-97c0-4fff-a325-039d0379bdbe",
+<<<<<<< HEAD
+    "pk": "89efa0fd-a187-4177-8de5-f3477dde921f",
     "fields": {
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+=======
+    "pk": "1645d910-5282-4ea0-8de9-b9495bfc4fd3",
+    "fields": {
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "type": "date",
+        "name": "date"
+    }
+},
+{
+    "model": "documents.allowedmetadata",
+    "pk": "4f1b7592-fd60-41a9-adb1-c31afd86d8b7",
+    "fields": {
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
         "type": "text",
         "name": "folio"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "89efa0fd-a187-4177-8de5-f3477dde921f",
+    "pk": "e44b9326-0e8c-4e0f-a735-3d701bda3852",
     "fields": {
-        "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+>>>>>>> 7912af40 (wip API endpoints)
         "type": "location",
         "name": "location"
     }
 },
 {
+<<<<<<< HEAD
     "model": "documents.allowedmetadata",
     "pk": "ab34cc71-a15a-40d9-8cc5-f680adca898b",
     "fields": {
@@ -1547,6 +2893,12 @@
     "pk": "52139b43-747a-4ffe-9f5c-cd43e0ad2b39",
     "fields": {
         "element": "e7027313-7910-44b4-bdff-28e8d187c0b4",
+=======
+    "model": "documents.metadata",
+    "pk": "24d2c357-1f9f-4aeb-b680-b7426144d301",
+    "fields": {
+        "element": "549a9a87-0632-4846-962d-7799147e0225",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "number",
         "type": "text",
         "value": "3",
@@ -1557,9 +2909,54 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "62347283-e04f-4401-a8a9-ff402766ac2d",
     "fields": {
         "element": "c8e488da-28d8-467e-a651-7d6f2ad6600d",
+=======
+    "pk": "2d466cc6-bd16-462e-81e3-57f7d3406ed5",
+    "fields": {
+        "element": "77ced3ba-7f04-48c7-b5fa-2b101d191c23",
+        "name": "folio",
+        "type": "text",
+        "value": "1v",
+        "entity": null,
+        "worker_version": null,
+        "worker_run": null
+    }
+},
+{
+    "model": "documents.metadata",
+    "pk": "2ed9bece-59a6-41e3-b7fa-23a17a1fc720",
+    "fields": {
+        "element": "f3a388d1-9968-4486-9e3b-e5a2a11947b1",
+        "name": "number",
+        "type": "text",
+        "value": "1",
+        "entity": null,
+        "worker_version": null,
+        "worker_run": null
+    }
+},
+{
+    "model": "documents.metadata",
+    "pk": "32b3e87e-37b2-43fe-b2e9-5c2720f548fe",
+    "fields": {
+        "element": "bdea4cf0-63bf-4918-b67d-b879d09f3c95",
+        "name": "number",
+        "type": "text",
+        "value": "4",
+        "entity": null,
+        "worker_version": null,
+        "worker_run": null
+    }
+},
+{
+    "model": "documents.metadata",
+    "pk": "4d4ccd74-5144-423b-98ef-ff6f27ef0cde",
+    "fields": {
+        "element": "3dc4ff7a-9a40-431b-b692-a2b5af381ffd",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "folio",
         "type": "text",
         "value": "2r",
@@ -1570,9 +2967,15 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "660e0182-f139-4a4b-b65e-b60b3051ef4c",
     "fields": {
         "element": "9c42123c-b940-4695-b083-5b19392f68a6",
+=======
+    "pk": "5935cea1-4176-4ba8-bc7e-7d399427ab86",
+    "fields": {
+        "element": "1444e97e-4873-4731-9b75-79f931c9dc9e",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "folio",
         "type": "text",
         "value": "1r",
@@ -1583,6 +2986,7 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "af1f94f7-b9a8-4963-9e21-d4a8c34b2627",
     "fields": {
         "element": "39210eb6-70a9-4660-8a45-5c6957508936",
@@ -1612,6 +3016,11 @@
     "pk": "da44df4c-a8ac-4bdc-a10b-ab6939ac76cd",
     "fields": {
         "element": "dc66eac3-a4e9-4c55-a4a8-d239bd79f3f6",
+=======
+    "pk": "5e861243-06eb-4e72-b904-86e04bb61fa0",
+    "fields": {
+        "element": "454b9f6d-8b0d-4313-baa3-82ccf8856d42",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "folio",
         "type": "text",
         "value": "1v",
@@ -1622,12 +3031,21 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "f55c81b9-bc87-4086-8cb1-b3a0eea6d491",
     "fields": {
         "element": "f530bd2f-d0ab-4f14-9d98-087486c4b1ab",
         "name": "folio",
         "type": "text",
         "value": "1v",
+=======
+    "pk": "752125f4-6e63-46e3-be1d-6a5c74e1acd5",
+    "fields": {
+        "element": "2a08be28-27f2-48f8-8d87-437893d389ca",
+        "name": "number",
+        "type": "text",
+        "value": "5",
+>>>>>>> 7912af40 (wip API endpoints)
         "entity": null,
         "worker_version": null,
         "worker_run": null
@@ -1635,9 +3053,28 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "fb0bedec-cc2d-424e-86bf-05239865e3fd",
     "fields": {
         "element": "02a6f67e-c7d4-4dec-b3a0-9f9ab3f2ee99",
+=======
+    "pk": "7f85231d-47f9-415d-a0d2-156a58cf70bc",
+    "fields": {
+        "element": "eed5499a-e95f-4f06-baa0-145d917a5b0c",
+        "name": "number",
+        "type": "text",
+        "value": "3",
+        "entity": null,
+        "worker_version": null,
+        "worker_run": null
+    }
+},
+{
+    "model": "documents.metadata",
+    "pk": "abbea23e-5dc2-481c-a34b-2e4bd18bace8",
+    "fields": {
+        "element": "97394f5f-6146-42be-8038-0d735e12d5f1",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "folio",
         "type": "text",
         "value": "2r",
@@ -1648,9 +3085,15 @@
 },
 {
     "model": "documents.metadata",
+<<<<<<< HEAD
     "pk": "fe60529e-30d4-4824-bb87-3534a652da81",
     "fields": {
         "element": "9fc5e0a3-9afb-493e-bf0f-fc2998ba4ba4",
+=======
+    "pk": "ad4154e1-2017-4028-9f81-a9611e6a439b",
+    "fields": {
+        "element": "ffffc01b-7577-4a93-9148-02fdc1f80435",
+>>>>>>> 7912af40 (wip API endpoints)
         "name": "folio",
         "type": "text",
         "value": "1r",
@@ -1676,6 +3119,7 @@
 },
 {
     "model": "images.image",
+<<<<<<< HEAD
     "pk": "27c0757d-4d15-4f0e-bfc1-ec63bfada9e7",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -1691,6 +3135,9 @@
 {
     "model": "images.image",
     "pk": "468df2f7-e22a-4dba-96d2-9c464ba6c2b0",
+=======
+    "pk": "0e219e81-b8ab-484b-a8f2-cb848a9c8b45",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1704,7 +3151,39 @@
 },
 {
     "model": "images.image",
+<<<<<<< HEAD
     "pk": "53421855-db25-4abd-aba4-d86710a76d5d",
+=======
+    "pk": "40210c9c-bf96-4364-a715-17ca2cf675cc",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "server": 1,
+        "path": "img3",
+        "width": 1000,
+        "height": 1000,
+        "hash": null,
+        "status": "unchecked"
+    }
+},
+{
+    "model": "images.image",
+    "pk": "4e80d190-2343-4e72-b60f-fda6b3d70b0d",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "server": 1,
+        "path": "img1",
+        "width": 1000,
+        "height": 1000,
+        "hash": null,
+        "status": "unchecked"
+    }
+},
+{
+    "model": "images.image",
+    "pk": "a6d3f3bc-986d-4618-8a87-fb1b86d9b866",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1718,6 +3197,7 @@
 },
 {
     "model": "images.image",
+<<<<<<< HEAD
     "pk": "a38b69a3-a4f8-4dfc-a6b9-38ea2e52c713",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
@@ -1767,10 +3247,37 @@
         "content_type": 19,
         "content_id": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
         "level": 100
+=======
+    "pk": "bd7d9ffd-013c-4970-9df8-1d18bbe88bd5",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "server": 1,
+        "path": "img2",
+        "width": 1000,
+        "height": 1000,
+        "hash": null,
+        "status": "unchecked"
+    }
+},
+{
+    "model": "images.image",
+    "pk": "d9c10a6b-6d15-4d60-a934-15a79d0b0bce",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "server": 1,
+        "path": "img5",
+        "width": 1000,
+        "height": 1000,
+        "hash": null,
+        "status": "unchecked"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "users.right",
+<<<<<<< HEAD
     "pk": "2a7d975d-4f18-41f4-964f-817aeae09582",
     "fields": {
         "user": 2,
@@ -1783,22 +3290,71 @@
 {
     "model": "users.right",
     "pk": "7e2ea5d2-2408-49b4-b1b4-2ea0e12da7e4",
+=======
+    "pk": "053ed1e1-850b-4554-b0d0-d05576b71696",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "user": 2,
         "group": null,
         "content_type": 34,
+<<<<<<< HEAD
         "content_id": "8f459bd8-0440-444e-940b-3c14b10bdb0d",
         "level": 100
+=======
+        "content_id": "18eabf1f-18b6-43d9-b104-7abfcb5b9baa",
+        "level": 50
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "users.right",
+<<<<<<< HEAD
     "pk": "db08fb62-277f-475c-ae92-cfb4a515b146",
+=======
+    "pk": "09f17812-99b6-4aa0-987b-541efc0d9eab",
+    "fields": {
+        "user": 2,
+        "group": null,
+        "content_type": 19,
+        "content_id": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+        "level": 100
+    }
+},
+{
+    "model": "users.right",
+    "pk": "0dcde7a7-c2a1-4e91-85c5-f5d392c511a6",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "user": 4,
         "group": null,
         "content_type": 34,
+<<<<<<< HEAD
         "content_id": "8f459bd8-0440-444e-940b-3c14b10bdb0d",
+=======
+        "content_id": "18eabf1f-18b6-43d9-b104-7abfcb5b9baa",
+        "level": 10
+    }
+},
+{
+    "model": "users.right",
+    "pk": "42da1a2f-2ff0-4480-b530-30b0934eb6be",
+    "fields": {
+        "user": 2,
+        "group": null,
+        "content_type": 34,
+        "content_id": "18eabf1f-18b6-43d9-b104-7abfcb5b9baa",
+        "level": 100
+    }
+},
+{
+    "model": "users.right",
+    "pk": "9323c83d-637f-43b5-8829-03c71505f4fb",
+    "fields": {
+        "user": 2,
+        "group": null,
+        "content_type": 11,
+        "content_id": "ff732a3f-c9ac-43fe-8b22-c03cf82d2a4e",
+>>>>>>> 7912af40 (wip API endpoints)
         "level": 10
     }
 },
@@ -1817,7 +3373,11 @@
     "model": "users.user",
     "pk": 1,
     "fields": {
+<<<<<<< HEAD
         "password": "pbkdf2_sha256$390000$n41pgYuMjEMc9yABOJDuv7$szqrPzEEMyrNyvxRF5ekrtgzLra4rnw09jkS/Rlb65M=",
+=======
+        "password": "pbkdf2_sha256$390000$K7ghXs3mkOALU9T2ri8k6D$Hw9rIqH0Mdlvd2vaMSsj7lH3TLerOKfpkHUVk4ZfZPM=",
+>>>>>>> 7912af40 (wip API endpoints)
         "last_login": null,
         "email": "root@root.fr",
         "display_name": "Admin",
@@ -1832,7 +3392,11 @@
     "model": "users.user",
     "pk": 2,
     "fields": {
+<<<<<<< HEAD
         "password": "pbkdf2_sha256$390000$82MV7wfiM1CYxnR3JI9dRw$vavB8EAQRE2Z0REJhhWU7bRyrQqZF5wazXjl1rOrvTY=",
+=======
+        "password": "pbkdf2_sha256$390000$4SWGc0rfBPkIHNBjmvIVhM$F81VX9tQd5l9iKOdb970liPhie/hbyyHNsYO7O7fOKE=",
+>>>>>>> 7912af40 (wip API endpoints)
         "last_login": null,
         "email": "user@user.fr",
         "display_name": "Test user",
@@ -1875,7 +3439,11 @@
 },
 {
     "model": "users.group",
+<<<<<<< HEAD
     "pk": "8f459bd8-0440-444e-940b-3c14b10bdb0d",
+=======
+    "pk": "18eabf1f-18b6-43d9-b104-7abfcb5b9baa",
+>>>>>>> 7912af40 (wip API endpoints)
     "fields": {
         "name": "User group",
         "public": false,
@@ -3871,42 +5439,188 @@
         "codename": "view_datasetelement"
     }
 },
+{
+    "model": "auth.permission",
+    "pk": 222,
+    "fields": {
+        "name": "Can add dataset set",
+        "content_type": 57,
+        "codename": "add_datasetset"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 223,
+    "fields": {
+        "name": "Can change dataset set",
+        "content_type": 57,
+        "codename": "change_datasetset"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 224,
+    "fields": {
+        "name": "Can delete dataset set",
+        "content_type": 57,
+        "codename": "delete_datasetset"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 225,
+    "fields": {
+        "name": "Can view dataset set",
+        "content_type": 57,
+        "codename": "view_datasetset"
+    }
+},
 {
     "model": "ponos.farm",
+<<<<<<< HEAD
     "pk": "395522d1-94a0-407a-b5cb-347fa68ec2c4",
     "fields": {
         "name": "Wheat farm",
         "seed": "444809637bf8b3088a181de520a02151a99477edd051710e90a2d1fcdf860dbb"
+=======
+    "pk": "ff732a3f-c9ac-43fe-8b22-c03cf82d2a4e",
+    "fields": {
+        "name": "Wheat farm",
+        "seed": "91901d0fec5faf1551277b5c76546b41902b8aefb819c3dbd10c3a643e6bb93c"
+    }
+},
+{
+    "model": "ponos.task",
+    "pk": "5c722e0d-2a2f-4ee8-9609-6033e450fd53",
+    "fields": {
+        "run": 0,
+        "depth": 0,
+        "slug": "docker_build",
+        "priority": 10,
+        "state": "completed",
+        "image": "",
+        "shm_size": null,
+        "command": null,
+        "env": "{}",
+        "has_docker_socket": false,
+        "image_artifact": null,
+        "agent": null,
+        "requires_gpu": false,
+        "gpu": null,
+        "process": "d6b43bc9-d87c-4c80-9211-f0c807506ad7",
+        "worker_run": null,
+        "container": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "expiry": "2100-12-31T23:59:59.999Z",
+        "extra_files": "{}",
+        "token": "OhbumqNZSmuGnj0MZ3lhJYRc3nHBm0WGrv9RNdtYpJk=",
+        "parents": []
+    }
+},
+{
+    "model": "ponos.artifact",
+    "pk": "481b42e2-645c-47fe-937f-5b4431f10563",
+    "fields": {
+        "task": "5c722e0d-2a2f-4ee8-9609-6033e450fd53",
+        "path": "/path/to/docker_build",
+        "size": 42000,
+        "content_type": "application/octet-stream",
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+>>>>>>> 7912af40 (wip API endpoints)
     }
 },
 {
     "model": "training.dataset",
+<<<<<<< HEAD
     "pk": "4a844b36-08bd-4284-918e-5e03d543df13",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+=======
+    "pk": "170bc276-0e11-483a-9486-88a4bf2079b2",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+>>>>>>> 7912af40 (wip API endpoints)
         "creator": 2,
         "task": null,
         "name": "Second Dataset",
         "description": "dataset number two",
-        "state": "open",
-        "sets": "[\"training\", \"test\", \"validation\"]"
+        "state": "open"
     }
 },
 {
     "model": "training.dataset",
+<<<<<<< HEAD
     "pk": "630d1cf5-3ba8-4335-b0be-d1be4cb18782",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "corpus": "f34313ec-45ec-4ac4-92e5-43d7eb045c12",
+=======
+    "pk": "6b32dab0-e3f2-4fff-b0ad-2ea1ee550810",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "corpus": "3a30b730-9c9e-4b5a-828e-abc4365ea1b9",
+>>>>>>> 7912af40 (wip API endpoints)
         "creator": 2,
         "task": null,
         "name": "First Dataset",
         "description": "dataset number one",
-        "state": "open",
-        "sets": "[\"training\", \"test\", \"validation\"]"
+        "state": "open"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "00e3b37b-f1ed-4adb-a1de-a1c103edaa24",
+    "fields": {
+        "name": "Test",
+        "dataset": "170bc276-0e11-483a-9486-88a4bf2079b2"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "95255ff4-7bca-424c-8e7e-d8b5c33c585f",
+    "fields": {
+        "name": "Train",
+        "dataset": "170bc276-0e11-483a-9486-88a4bf2079b2"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "b21e4b31-1dc1-4015-9933-3a8e180cf2e0",
+    "fields": {
+        "name": "Validation",
+        "dataset": "170bc276-0e11-483a-9486-88a4bf2079b2"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "b76d919c-ce7e-4896-94c3-9b47862b997a",
+    "fields": {
+        "name": "Validation",
+        "dataset": "6b32dab0-e3f2-4fff-b0ad-2ea1ee550810"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "d5f4d410-0588-4d19-8d08-b57a11bad67f",
+    "fields": {
+        "name": "Train",
+        "dataset": "6b32dab0-e3f2-4fff-b0ad-2ea1ee550810"
+    }
+},
+{
+    "model": "training.datasetset",
+    "pk": "db70ad8a-8d6b-44c6-b8d3-837bf5a4ab8e",
+    "fields": {
+        "name": "Test",
+        "dataset": "6b32dab0-e3f2-4fff-b0ad-2ea1ee550810"
     }
 }
 ]
diff --git a/arkindex/documents/management/commands/build_fixtures.py b/arkindex/documents/management/commands/build_fixtures.py
index b0e5d50103..03036d1fff 100644
--- a/arkindex/documents/management/commands/build_fixtures.py
+++ b/arkindex/documents/management/commands/build_fixtures.py
@@ -20,6 +20,7 @@ from arkindex.process.models import (
     WorkerVersionState,
 )
 from arkindex.project.tools import fake_now
+from arkindex.training.models import DatasetSet
 from arkindex.users.models import Group, Right, Role, User
 
 
@@ -271,8 +272,15 @@ class Command(BaseCommand):
         )
 
         # Create 2 datasets
-        corpus.datasets.create(name="First Dataset", description="dataset number one", creator=user)
-        corpus.datasets.create(name="Second Dataset", description="dataset number two", creator=user)
+        dataset_1 = corpus.datasets.create(name="First Dataset", description="dataset number one", creator=user)
+        dataset_2 = corpus.datasets.create(name="Second Dataset", description="dataset number two", creator=user)
+        # Create their sets
+        DatasetSet.objects.bulk_create(
+            DatasetSet(name=name, dataset_id=dataset_1.id) for name in ["Train", "Validation", "Test"]
+        )
+        DatasetSet.objects.bulk_create(
+            DatasetSet(name=name, dataset_id=dataset_2.id) for name in ["Train", "Validation", "Test"]
+        )
 
         # Create 2 volumes
         vol1 = Element.objects.create(
diff --git a/arkindex/process/migrations/0029_processdataset_sets.py b/arkindex/process/migrations/0029_processdataset_sets.py
index 868c1cc29f..f1b1cda509 100644
--- a/arkindex/process/migrations/0029_processdataset_sets.py
+++ b/arkindex/process/migrations/0029_processdataset_sets.py
@@ -1,8 +1,8 @@
 import django.core.validators
 from django.db import migrations, models
 
+import arkindex.process.models
 import arkindex.project.fields
-import arkindex.training.models
 
 
 class Migration(migrations.Migration):
@@ -37,7 +37,7 @@ class Migration(migrations.Migration):
                     validators=[django.core.validators.MinLengthValidator(1)]
                 ),
                 size=None,
-                validators=[django.core.validators.MinLengthValidator(1), arkindex.training.models.validate_unique_set_names]
+                validators=[django.core.validators.MinLengthValidator(1), arkindex.process.models.validate_unique_set_names]
             ),
         ),
     ]
diff --git a/arkindex/process/models.py b/arkindex/process/models.py
index 75774d7048..fa349eb6c4 100644
--- a/arkindex/process/models.py
+++ b/arkindex/process/models.py
@@ -5,6 +5,7 @@ from typing import Optional
 
 from django.conf import settings
 from django.contrib.contenttypes.fields import GenericRelation
+from django.core.exceptions import ValidationError
 from django.core.validators import MinLengthValidator, MinValueValidator
 from django.db import models, transaction
 from django.db.models import F, Q
@@ -28,7 +29,7 @@ from arkindex.project.aws import S3FileMixin, S3FileStatus
 from arkindex.project.fields import ArrayField, MD5HashField
 from arkindex.project.models import IndexableModel
 from arkindex.project.validators import MaxValueValidator
-from arkindex.training.models import ModelVersion, ModelVersionState, validate_unique_set_names
+from arkindex.training.models import ModelVersion, ModelVersionState
 from arkindex.users.models import Role
 
 
@@ -40,6 +41,11 @@ def process_max_chunks():
     return settings.MAX_CHUNKS
 
 
+def validate_unique_set_names(sets):
+    if len(set(sets)) != len(sets):
+        raise ValidationError("Set names must be unique.")
+
+
 class ActivityState(Enum):
     """
     Store the state of the workers activity tracking for a process.
diff --git a/arkindex/project/serializer_fields.py b/arkindex/project/serializer_fields.py
index cefaaf14ec..7667083d86 100644
--- a/arkindex/project/serializer_fields.py
+++ b/arkindex/project/serializer_fields.py
@@ -12,6 +12,7 @@ from arkindex.documents.models import MetaType
 from arkindex.ponos.utils import get_process_from_task_auth
 from arkindex.process.models import ProcessMode, WorkerRun
 from arkindex.project.gis import ensure_linear_ring
+from arkindex.training.models import DatasetElement
 
 
 class EnumField(serializers.ChoiceField):
@@ -283,12 +284,12 @@ class DatasetSetsCountField(serializers.DictField):
     def get_attribute(self, instance):
         if not self.context.get("sets_count", True):
             return None
-        elts_count = {k: 0 for k in instance.sets}
+        elts_count = {k.name: 0 for k in instance.sets.all()}
         elts_count.update(
-            instance.dataset_elements
-            .values("set")
+            DatasetElement.objects.filter(set__dataset_id=instance.id)
+            .values("set__name")
             .annotate(count=Count("id"))
-            .values_list("set", "count")
+            .values_list("set__name", "count")
         )
         return elts_count
 
diff --git a/arkindex/training/admin.py b/arkindex/training/admin.py
index 858f40be14..66f3626575 100644
--- a/arkindex/training/admin.py
+++ b/arkindex/training/admin.py
@@ -2,7 +2,7 @@ from django.contrib import admin
 from enumfields.admin import EnumFieldListFilter
 
 from arkindex.project.admin import ArchivedListFilter
-from arkindex.training.models import Dataset, MetricKey, MetricValue, Model, ModelVersion
+from arkindex.training.models import Dataset, DatasetSet, MetricKey, MetricValue, Model, ModelVersion
 
 
 class ModelAdmin(admin.ModelAdmin):
@@ -31,21 +31,17 @@ class MetricKeyAdmin(admin.ModelAdmin):
     inlines = [MetricValueInline, ]
 
 
+class DatasetSetInLine(admin.StackedInline):
+    model = DatasetSet
+
+
 class DatasetAdmin(admin.ModelAdmin):
     list_display = ("name", "corpus", "state")
     list_filter = (("state", EnumFieldListFilter), "corpus")
     search_fields = ("name", "description")
-    fields = ("id", "name", "created", "updated", "description", "corpus", "creator", "task", "sets")
+    fields = ("id", "name", "created", "updated", "description", "corpus", "creator", "task")
     readonly_fields = ("id", "created", "updated", "task")
-
-    def get_form(self, *args, **kwargs):
-        form = super().get_form(*args, **kwargs)
-        # Add a help text to mention that the set names should be comma-separated.
-        # This is only done here and not through the usual `help_text=…` in the model
-        # because this is only relevant to the Django admin and should not appear in
-        # DRF serializers or the API docs.
-        form.base_fields["sets"].help_text = "Comma-separated list of set names"
-        return form
+    inlines = [DatasetSetInLine, ]
 
 
 admin.site.register(Model, ModelAdmin)
diff --git a/arkindex/training/api.py b/arkindex/training/api.py
index 353dc6e928..06034116e9 100644
--- a/arkindex/training/api.py
+++ b/arkindex/training/api.py
@@ -609,6 +609,7 @@ class CorpusDataset(CorpusACLMixin, ListCreateAPIView):
     def get_queryset(self):
         return Dataset.objects \
             .select_related("creator") \
+            .prefetch_related("sets") \
             .filter(corpus=self.corpus) \
             .order_by("name")
 
diff --git a/arkindex/training/migrations/0001_initial.py b/arkindex/training/migrations/0001_initial.py
index 154f97adfd..ba280c7d4a 100644
--- a/arkindex/training/migrations/0001_initial.py
+++ b/arkindex/training/migrations/0001_initial.py
@@ -8,9 +8,13 @@ import django.db.models.deletion
 import enumfields.fields
 from django.db import migrations, models
 
+import arkindex.process.models
 import arkindex.project.aws
 import arkindex.project.fields
-import arkindex.training.models
+
+
+def default_sets():
+    return ["training", "test", "validation"]
 
 
 class Migration(migrations.Migration):
@@ -32,7 +36,7 @@ class Migration(migrations.Migration):
                 ("name", models.CharField(max_length=100, validators=[django.core.validators.MinLengthValidator(1)])),
                 ("description", models.TextField(validators=[django.core.validators.MinLengthValidator(1)])),
                 ("state", enumfields.fields.EnumField(default="open", enum=arkindex.training.models.DatasetState, max_length=10)),
-                ("sets", django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50, validators=[django.core.validators.MinLengthValidator(1)]), default=arkindex.training.models.default_sets, size=None, validators=[django.core.validators.MinLengthValidator(1), arkindex.training.models.validate_unique_set_names])),
+                ("sets", django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50, validators=[django.core.validators.MinLengthValidator(1)]), default=default_sets, size=None, validators=[django.core.validators.MinLengthValidator(1), arkindex.process.models.validate_unique_set_names])),
                 ("corpus", models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name="datasets", to="documents.corpus")),
             ],
         ),
diff --git a/arkindex/training/migrations/0007_datasetset_model.py b/arkindex/training/migrations/0007_datasetset_model.py
index 94e1b35bfc..8630baa593 100644
--- a/arkindex/training/migrations/0007_datasetset_model.py
+++ b/arkindex/training/migrations/0007_datasetset_model.py
@@ -83,7 +83,7 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name="datasetelement",
             name="set",
-            field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name="dataset_elements", to="training.datasetset"),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name="set_elements", to="training.datasetset"),
         ),
         migrations.RemoveField(
             model_name="dataset",
diff --git a/arkindex/training/models.py b/arkindex/training/models.py
index 363393d2b8..06f4f84c5f 100644
--- a/arkindex/training/models.py
+++ b/arkindex/training/models.py
@@ -4,7 +4,6 @@ from hashlib import sha256
 
 from django.conf import settings
 from django.contrib.contenttypes.fields import GenericRelation
-from django.core.exceptions import ValidationError
 from django.core.validators import MinLengthValidator
 from django.db import models
 from django.db.models import Q
@@ -241,15 +240,6 @@ class DatasetState(Enum):
     Error = "error"
 
 
-def validate_unique_set_names(sets):
-    if len(set(sets)) != len(sets):
-        raise ValidationError("Set names must be unique.")
-
-
-def default_sets():
-    return ["training", "test", "validation"]
-
-
 class Dataset(models.Model):
     id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
     created = models.DateTimeField(auto_now_add=True)
@@ -316,6 +306,6 @@ class DatasetElement(models.Model):
     )
     set = models.ForeignKey(
         DatasetSet,
-        related_name="dataset_elements",
+        related_name="set_elements",
         on_delete=models.DO_NOTHING,
     )
diff --git a/arkindex/training/serializers.py b/arkindex/training/serializers.py
index ab1e300b58..4acb03a663 100644
--- a/arkindex/training/serializers.py
+++ b/arkindex/training/serializers.py
@@ -6,18 +6,19 @@ from textwrap import dedent
 from django.db import transaction
 from django.db.models import Count, Q
 from drf_spectacular.utils import extend_schema_field
-from rest_framework import serializers
+from rest_framework import permissions, serializers
 from rest_framework.exceptions import PermissionDenied, ValidationError
 from rest_framework.validators import UniqueTogetherValidator
 
 from arkindex.documents.models import Element
 from arkindex.documents.serializers.elements import ElementListSerializer
 from arkindex.ponos.models import Task
-from arkindex.process.models import ProcessDataset, Worker
+from arkindex.process.models import Worker
 from arkindex.project.serializer_fields import ArchivedField, DatasetSetsCountField, EnumField
 from arkindex.training.models import (
     Dataset,
     DatasetElement,
+    DatasetSet,
     DatasetState,
     MetricKey,
     MetricMode,
@@ -479,6 +480,12 @@ class MetricValueBulkSerializer(serializers.Serializer):
         return validated_data
 
 
+class DatasetSetSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = DatasetSet
+        fields = ("id", "name",)
+
+
 class DatasetSerializer(serializers.ModelSerializer):
     state = EnumField(
         DatasetState,
@@ -505,6 +512,9 @@ class DatasetSerializer(serializers.ModelSerializer):
         help_text="Display name of the user who created the dataset.",
     )
 
+    set_names = serializers.ListField(child=serializers.CharField(max_length=50), write_only=True, default=["Training", "Validation", "Test"])
+    sets = DatasetSetSerializer(many=True, read_only=True)
+
     # When creating the dataset, the dataset's corpus comes from the URL, so the APIView passes it through
     corpus = serializers.HiddenField(default=_corpus_from_context)
 
@@ -517,16 +527,6 @@ class DatasetSerializer(serializers.ModelSerializer):
         help_text="Distribution of elements in sets. This value is set to null when listing multiple datasets.",
     )
 
-    def sets_diff(self, new_sets):
-        """
-        Returns a list of removed sets, and a list of added sets for updates
-        """
-        if not isinstance(self.instance, Dataset):
-            return [], new_sets
-        current_sets = set(self.instance.sets)
-        new_sets = set(new_sets)
-        return list(current_sets - new_sets), list(new_sets - current_sets)
-
     def validate_state(self, state):
         """
         Dataset's state update is limited to these transitions:
@@ -550,27 +550,12 @@ class DatasetSerializer(serializers.ModelSerializer):
             raise ValidationError(f"Transition from {self.instance.state} to {state} is not allowed.")
         return state
 
-    def validate_sets(self, sets):
-        """
-        Ensure sets are updated in a comprehensible way.
-        It is either possible to add multiple sets,
-        remove multiple sets or update a single set.
-        """
-        if sets is not None and len(set(sets)) != len(sets):
+    def validate_set_names(self, set_names):
+        if self.context["request"].method not in permissions.SAFE_METHODS and self.context["request"].method != "POST":
+            raise ValidationError("This API endpoint does not allow updating a dataset's sets.")
+        if set_names is not None and len(set(set_names)) != len(set_names):
             raise ValidationError("Set names must be unique.")
-
-        removed, added = self.sets_diff(sets)
-        if removed and ProcessDataset.objects.filter(sets__overlap=removed, dataset_id=self.instance.id).exists():
-            # Sets that are used in a ProcessDataset cannot be renamed or deleted
-            raise ValidationError("These sets cannot be updated because one or more are selected in a dataset process.")
-        if not removed or not added:
-            # Some sets have either been added or removed, but not both; do nothing
-            return sets
-        elif len(removed) == 1 and len(added) == 1:
-            # A single set has been renamed. Move its elements later, while performing the update
-            return sets
-        else:
-            raise ValidationError("Updating those sets is ambiguous because several have changed.")
+        return set_names
 
     def validate(self, data):
         data = super().validate(data)
@@ -598,13 +583,17 @@ class DatasetSerializer(serializers.ModelSerializer):
 
         return data
 
-    @transaction.atomic()
-    def update(self, instance, validated_data):
-        removed, added = self.sets_diff(validated_data.get("sets", self.instance.sets))
-        if len(removed) == 1 and len(added) == 1:
-            set_from, set_to = *removed, *added
-            instance.dataset_elements.filter(set=set_from).update(set=set_to)
-        return super().update(instance, validated_data)
+    @transaction.atomic
+    def create(self, validated_data):
+        sets = validated_data.pop("set_names")
+        dataset = Dataset.objects.create(**validated_data)
+        DatasetSet.objects.bulk_create(
+            DatasetSet(
+                name=set_name,
+                dataset_id=dataset.id
+            ) for set_name in sets
+        )
+        return dataset
 
     class Meta:
         model = Dataset
@@ -613,6 +602,7 @@ class DatasetSerializer(serializers.ModelSerializer):
             "name",
             "description",
             "sets",
+            "set_names",
             "set_elements",
             "state",
             # Only the corpus ID is actually serialized
@@ -647,13 +637,7 @@ class DatasetSerializer(serializers.ModelSerializer):
             "sets": {
                 "error_messages": {
                     "empty": "Either do not specify set names to use the default values, or specify a non-empty list of names."
-                },
-                "help_text": dedent(
-                    """
-                    Updating the sets array must either add or remove sets (in this case nothing specific is done),
-                    or rename a single set within the array (all elements linked to the previous set will be moved).
-                    """
-                ).strip(),
+                }
             }
         }
 
@@ -726,35 +710,29 @@ class ElementDatasetSerializer(serializers.ModelSerializer):
 
 
 class SelectionDatasetElementSerializer(serializers.Serializer):
-    dataset_id = serializers.PrimaryKeyRelatedField(
-        queryset=Dataset.objects.all(),
-        source="dataset",
+    set_id = serializers.PrimaryKeyRelatedField(
+        queryset=DatasetSet.objects.none(),
+        source="set",
         write_only=True,
-        help_text="UUID of a dataset to add elements from your corpus' selection.",
+        help_text="UUID of a dataset set the elements will be added to.",
         style={"base_template": "input.html"},
     )
-    set = serializers.CharField(
-        max_length=50,
-        write_only=True,
-        help_text="Name of the set elements will be added to.",
-    )
 
-    def validate_dataset_id(self, dataset):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.fields["set_id"].queryset = DatasetSet.objects.filter(
+            dataset__corpus_id=self.context["corpus"].id
+        ).select_related("dataset")
+
+    def validate_set_id(self, set):
         if (
             (corpus := self.context.get("corpus"))
-            and dataset.corpus_id != corpus.id
+            and set.dataset.corpus_id != corpus.id
         ):
-            raise ValidationError(f"Dataset {dataset.id} is not part of corpus {corpus.name}.")
-        if dataset.state == DatasetState.Complete:
-            raise ValidationError(f"Dataset {dataset.id} is marked as completed.")
-        return dataset
-
-    def validate(self, data):
-        data = super().validate(data)
-        dataset = data["dataset"]
-        if data["set"] not in dataset.sets:
-            raise ValidationError({"set": [f'This dataset only allows one of {", ".join(dataset.sets)}.']})
-        return data
+            raise ValidationError(f"Dataset {set.dataset.id} is not part of corpus {corpus.name}.")
+        if set.dataset.state == DatasetState.Complete:
+            raise ValidationError(f"Dataset {set.dataset.id} is marked as completed.")
+        return set
 
     def create(self, validated_data):
         user = self.context["request"].user
diff --git a/arkindex/training/tests/test_datasets_api.py b/arkindex/training/tests/test_datasets_api.py
index 3cba65910c..618d806ed1 100644
--- a/arkindex/training/tests/test_datasets_api.py
+++ b/arkindex/training/tests/test_datasets_api.py
@@ -9,7 +9,7 @@ from arkindex.documents.models import Corpus
 from arkindex.process.models import Process, ProcessDataset, ProcessMode
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.project.tools import fake_now
-from arkindex.training.models import Dataset, DatasetState
+from arkindex.training.models import Dataset, DatasetSet, DatasetState
 from arkindex.users.models import Role, User
 
 # Using the fake DB fixtures creation date when needed
@@ -33,6 +33,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
         ProcessDataset.objects.create(process=cls.process, dataset=cls.dataset, sets=["training", "test", "validation"])
         ProcessDataset.objects.create(process=cls.process, dataset=cls.dataset2, sets=["test"])
         cls.private_dataset = Dataset.objects.create(name="Private Dataset", description="Dead Sea Scrolls", corpus=cls.private_corpus, creator=cls.dataset_creator)
+        cls.private_dataset_set = DatasetSet.objects.create(dataset=cls.private_dataset, name="Private set")
         cls.vol = cls.corpus.elements.get(name="Volume 1")
         cls.page1 = cls.corpus.elements.get(name="Volume 1, page 1r")
         cls.page2 = cls.corpus.elements.get(name="Volume 1, page 1v")
@@ -75,7 +76,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
 
     def test_list(self):
         self.client.force_login(self.user)
-        with self.assertNumQueries(5):
+        with self.assertNumQueries(6):
             response = self.client.get(reverse("api:corpus-datasets", kwargs={"pk": self.corpus.pk}))
             self.assertEqual(response.status_code, status.HTTP_200_OK)
         self.assertEqual(response.json()["results"], [
@@ -83,7 +84,13 @@ class TestDatasetsAPI(FixtureAPITestCase):
                 "name": "First Dataset",
                 "description": "dataset number one",
                 "id": str(self.dataset.pk),
-                "sets": ["training", "test", "validation"],
+                "sets": [
+                    {
+                        "id": str(ds.id),
+                        "name": ds.name
+                    }
+                    for ds in self.dataset.sets.all()
+                ],
                 "set_elements": None,
                 "state": "open",
                 "creator": "Test user",
@@ -96,7 +103,13 @@ class TestDatasetsAPI(FixtureAPITestCase):
                 "name": "Second Dataset",
                 "description": "dataset number two",
                 "id": str(self.dataset2.pk),
-                "sets": ["training", "test", "validation"],
+                "sets": [
+                    {
+                        "id": str(ds.id),
+                        "name": ds.name
+                    }
+                    for ds in self.dataset2.sets.all()
+                ],
                 "set_elements": None,
                 "state": "open",
                 "creator": "Test user",
@@ -254,7 +267,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
 
     def test_create(self):
         self.client.force_login(self.user)
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(10):
             response = self.client.post(
                 reverse("api:corpus-datasets", kwargs={"pk": self.corpus.pk}),
                 data={"name": "My dataset", "description": "My dataset for my experiments."},
@@ -266,11 +279,11 @@ class TestDatasetsAPI(FixtureAPITestCase):
             "id": str(created_dataset.id),
             "name": "My dataset",
             "description": "My dataset for my experiments.",
-            "sets": ["training", "test", "validation"],
+            "sets": {},
             "set_elements": {
-                "training": 0,
-                "test": 0,
-                "validation": 0,
+                "Training": 0,
+                "Test": 0,
+                "Validation": 0,
             },
             "state": "open",
             "creator": "Test user",
@@ -494,199 +507,21 @@ class TestDatasetsAPI(FixtureAPITestCase):
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {"description": ["This field is required."]})
 
-    def test_update_add_sets(self):
-        self.client.force_login(self.user)
-        self.assertIsNone(self.dataset.task_id)
-        with self.assertNumQueries(8):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    "sets": self.dataset.sets + ["unit-01", "unit-02"],
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.dataset.refresh_from_db()
-        self.assertEqual(self.dataset.state, DatasetState.Open)
-        self.assertEqual(self.dataset.name, "Shin Seiki Evangelion")
-        self.assertEqual(self.dataset.description, "Omedeto!")
-        self.assertListEqual(self.dataset.sets, ["training", "test", "validation", "unit-01", "unit-02"])
-        self.assertIsNone(self.dataset.task_id)
-
-    def test_update_remove_sets(self):
-        """
-        It is possible to remove many sets, no elements are moved
-        """
-        # Remove ProcessDataset relation
-        ProcessDataset.objects.get(process=self.process, dataset=self.dataset).delete()
-        self.client.force_login(self.user)
-        dataset_elt = self.dataset.dataset_elements.create(element=self.page1, set="training")
-        with self.assertNumQueries(9):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    # train and validation sets are removed
-                    "sets": ["test"],
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.dataset.refresh_from_db()
-        self.assertEqual(self.dataset.state, DatasetState.Open)
-        self.assertEqual(self.dataset.name, "Shin Seiki Evangelion")
-        self.assertEqual(self.dataset.description, "Omedeto!")
-        self.assertListEqual(self.dataset.sets, ["test"])
-        self.assertIsNone(self.dataset.task_id)
-        dataset_elt.refresh_from_db()
-        self.assertEqual(dataset_elt.element, self.page1)
-        self.assertEqual(dataset_elt.dataset, self.dataset)
-        # Element is still linked to a set that does not exist anymore on the dataset
-        self.assertEqual(dataset_elt.set, "training")
-
-    def test_update_sets_update_single_set(self):
-        """
-        It is possible to rename a single set, if it is not referenced by a ProcessDataset
-        """
-        ProcessDataset.objects.get(process=self.process, dataset=self.dataset, sets=["training", "test", "validation"]).delete()
+    def test_update_sets_forbidden(self):
         self.client.force_login(self.user)
-        self.dataset.dataset_elements.create(element_id=self.page1.id, set="training")
-        self.dataset.dataset_elements.create(element_id=self.page2.id, set="validation")
-        self.dataset.dataset_elements.create(element_id=self.page3.id, set="validation")
-        with self.assertNumQueries(10):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    # validation set is renamed to AAAAAAA
-                    "sets": ["test", "training", "AAAAAAA"],
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.dataset.refresh_from_db()
-        self.assertEqual(self.dataset.state, DatasetState.Open)
-        self.assertEqual(self.dataset.name, "Shin Seiki Evangelion")
-        self.assertEqual(self.dataset.description, "Omedeto!")
-        self.assertListEqual(self.dataset.sets, ["test", "training", "AAAAAAA"])
-        self.assertIsNone(self.dataset.task_id)
-        self.assertQuerysetEqual(
-            self.dataset.dataset_elements.values_list("set", "element__name").order_by("element__name"),
-            [
-                ("training", "Volume 1, page 1r"),
-                ("AAAAAAA", "Volume 1, page 1v"),
-                ("AAAAAAA", "Volume 1, page 2r"),
-            ]
-        )
-
-    def test_update_sets_processdataset_reference(self):
-        """
-        If a dataset's sets are referenced by a ProcessDataset, they cannot be updated
-        """
-        self.client.force_login(self.user)
-        self.dataset.dataset_elements.create(element_id=self.page1.id, set="training")
-        self.dataset.dataset_elements.create(element_id=self.page2.id, set="validation")
-        self.dataset.dataset_elements.create(element_id=self.page3.id, set="validation")
-        with self.assertNumQueries(4):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    # validation set is renamed to AAAAAAA
-                    "sets": ["test", "training", "AAAAAAA"],
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {"sets": ["These sets cannot be updated because one or more are selected in a dataset process."]})
-        self.dataset.refresh_from_db()
-        self.assertEqual(self.dataset.state, DatasetState.Open)
-        self.assertEqual(self.dataset.name, "First Dataset")
-        self.assertEqual(self.dataset.description, "dataset number one")
-        self.assertListEqual(self.dataset.sets, ["training", "test", "validation"])
         self.assertIsNone(self.dataset.task_id)
-        self.assertQuerysetEqual(
-            self.dataset.dataset_elements.values_list("set", "element__name").order_by("element__name"),
-            [
-                ("training", "Volume 1, page 1r"),
-                ("validation", "Volume 1, page 1v"),
-                ("validation", "Volume 1, page 2r"),
-            ]
-        )
-
-    def test_update_sets_ambiguous(self):
-        """
-        No more than one set can be updated
-        """
-        # Remove ProcessDataset relation
-        ProcessDataset.objects.get(process=self.process, dataset=self.dataset).delete()
-        self.client.force_login(self.user)
-        with self.assertNumQueries(4):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    "sets": ["test", "AAAAAAA", "BBBBBBB"],
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(response.json(), {"sets": ["Updating those sets is ambiguous because several have changed."]})
-
-    def test_update_sets_length(self):
-        self.client.force_login(self.user)
         with self.assertNumQueries(3):
             response = self.client.put(
                 reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
                 data={
                     "name": "Shin Seiki Evangelion",
                     "description": "Omedeto!",
-                    "sets": []
+                    "set_names": ["unit-01", "unit-02"],
                 },
                 format="json"
             )
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {"sets": ["Either do not specify set names to use the default values, or specify a non-empty list of names."]})
-
-    def test_update_sets_unique_names(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "Shin Seiki Evangelion",
-                    "description": "Omedeto!",
-                    "sets": ["unit-01", "unit-01", "unit-02"]
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {"sets": ["Set names must be unique."]})
-
-    def test_update_sets_name_too_long(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.put(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "name": "My Dataset",
-                    "description": "My dataset for my experiments.",
-                    "sets": ["unit-00", "Etiam accumsan ullamcorper mauris eget mattis. Ut porttitor."]
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {
-            "sets": {
-                "1": ["Ensure this field has no more than 50 characters."]
-            }
-        })
+        self.assertDictEqual(response.json(), {"set_names": ["This API endpoint does not allow updating a dataset's sets."]})
 
     def test_update_empty_or_blank_description_or_name(self):
         self.client.force_login(self.user)
@@ -696,15 +531,13 @@ class TestDatasetsAPI(FixtureAPITestCase):
                 data={
                     "name": "",
                     "description": "          ",
-                    "sets": "",
                 },
                 format="json"
             )
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
             "name": ["This field may not be blank."],
-            "description": ["This field may not be blank."],
-            "sets": ['Expected a list of items but got type "str".'],
+            "description": ["This field may not be blank."]
         })
 
     def test_update_all_errors(self):
@@ -715,7 +548,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
                 data={
                     "name": "",
                     "description": "          ",
-                    "sets": ["unit-00", "unit-00", "unit-02"]
+                    "set_names": ["unit-00", "unit-00", "unit-02"]
                 },
                 format="json"
             )
@@ -723,7 +556,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
         self.assertDictEqual(response.json(), {
             "name": ["This field may not be blank."],
             "description": ["This field may not be blank."],
-            "sets": ["Set names must be unique."]
+            "set_names": ["This API endpoint does not allow updating a dataset's sets."]
         })
 
     def test_update_state_requires_ponos_auth(self):
@@ -1022,23 +855,6 @@ class TestDatasetsAPI(FixtureAPITestCase):
         self.dataset.refresh_from_db()
         self.assertEqual(self.dataset.state, DatasetState.Open)
 
-    def test_partial_update_sets_name_too_long(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(3):
-            response = self.client.patch(
-                reverse("api:dataset-update", kwargs={"pk": self.dataset.pk}),
-                data={
-                    "sets": ["unit-00", "Etiam accumsan ullamcorper mauris eget mattis. Ut porttitor."]
-                },
-                format="json"
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {
-            "sets": {
-                "1": ["Ensure this field has no more than 50 characters."]
-            }
-        })
-
     def test_partial_update_ponos_task_state_forbidden(self):
         """Dataset's state update is limited to specific transitions"""
         op, build, complete, error = [DatasetState[state] for state in ("Open", "Building", "Complete", "Error")]
@@ -1652,6 +1468,8 @@ class TestDatasetsAPI(FixtureAPITestCase):
             [("training", "Volume 1, page 1r")]
         )
 
+    # CreateDatasetElementSelection
+
     def test_add_from_selection_requires_login(self):
         with self.assertNumQueries(0):
             response = self.client.post(reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}))
@@ -1710,8 +1528,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
             response = self.client.post(reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}))
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
-            "dataset_id": ["This field is required."],
-            "set": ["This field is required."],
+            "set_id": ["This field is required."],
         })
 
     def test_add_from_selection_wrong_values(self):
@@ -1719,13 +1536,12 @@ class TestDatasetsAPI(FixtureAPITestCase):
         with self.assertNumQueries(3):
             response = self.client.post(
                 reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}),
-                data={"set": {}, "dataset_id": "AAA"},
+                data={"set_id": "AAA"},
                 format="json",
             )
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
-            "dataset_id": ["“AAA” is not a valid UUID."],
-            "set": ["Not a valid string."],
+            "set_id": ["`AAA` is not a valid UUID."],
         })
 
     def test_add_from_selection_wrong_dataset(self):
@@ -1733,7 +1549,7 @@ class TestDatasetsAPI(FixtureAPITestCase):
         with self.assertNumQueries(4):
             response = self.client.post(
                 reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}),
-                data={"set": "aaa", "dataset_id": self.private_dataset.id},
+                data={"set_id": self.private_dataset_set.id},
                 format="json",
             )
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
@@ -1743,31 +1559,19 @@ class TestDatasetsAPI(FixtureAPITestCase):
 
     def test_add_from_selection_completed_dataset(self):
         """A dataset in the Complete state is immutable"""
+        test_set = self.dataset.sets.first()
         self.client.force_login(self.user)
         self.dataset.state = DatasetState.Complete
         self.dataset.save()
         with self.assertNumQueries(4):
             response = self.client.post(
                 reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}),
-                data={"set": "aaa", "dataset_id": self.dataset.id},
-                format="json",
-            )
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {
-            "dataset_id": [f"Dataset {self.dataset.id} is marked as completed."]
-        })
-
-    def test_add_from_selection_wrong_set(self):
-        self.client.force_login(self.user)
-        with self.assertNumQueries(4):
-            response = self.client.post(
-                reverse("api:dataset-elements-selection", kwargs={"pk": self.corpus.id}),
-                data={"set": "aaa", "dataset_id": self.dataset.id},
+                data={"set_id": test_set.id},
                 format="json",
             )
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
-            "set": ["This dataset only allows one of training, test, validation."],
+            "set_id": [f"Dataset {self.dataset.id} is marked as completed."]
         })
 
     def test_add_from_selection(self):
-- 
GitLab