diff --git a/arkindex/documents/serializers/entities.py b/arkindex/documents/serializers/entities.py
index cb19bed3c8eb5f5b8477cbe31b57f8a0f84b682f..e7d573ebfc4110b05db367f15acd9eb3cf84e79a 100644
--- a/arkindex/documents/serializers/entities.py
+++ b/arkindex/documents/serializers/entities.py
@@ -10,7 +10,7 @@ from arkindex.documents.models import Corpus, Entity, EntityLink, EntityRole, En
 from arkindex.documents.serializers.light import CorpusLightSerializer, EntityTypeLightSerializer
 from arkindex.documents.serializers.ml import WorkerRunSummarySerializer
 from arkindex.process.models import WorkerRun
-from arkindex.project.serializer_fields import ForbiddenField
+from arkindex.project.serializer_fields import ForbiddenField, WorkerRunIDField
 from arkindex.project.validators import ForbiddenValidator
 
 
@@ -237,11 +237,16 @@ class EntityCreateSerializer(BaseEntitySerializer):
             Creating new entities with a WorkerVersion is forbidden. Use `worker_run_id` instead.
         """),
     )
-    worker_run_id = serializers.PrimaryKeyRelatedField(
-        queryset=WorkerRun.objects.all(),
+    worker_run_id = WorkerRunIDField(
         default=None,
-        source='worker_run',
-        style={'base_template': 'input.html'},
+        help_text=dedent("""
+            A WorkerRun ID that the new entity will refer to.
+
+            Regular users may only use the WorkerRuns of their own `Local` process.
+
+            Tasks authenticated via the Ponos task authentication may only use the WorkerRuns of their process.
+        """).strip(),
+
     )
     type_id = serializers.PrimaryKeyRelatedField(
         queryset=EntityType.objects.all(),
diff --git a/arkindex/documents/tests/test_entities_api.py b/arkindex/documents/tests/test_entities_api.py
index 54401e055793aba84844d838eb4ec4b07cedb87b..3b9967933a59661febf000a1e2c1ca9ed6527629 100644
--- a/arkindex/documents/tests/test_entities_api.py
+++ b/arkindex/documents/tests/test_entities_api.py
@@ -26,6 +26,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         cls.private_corpus = Corpus.objects.create(name='private')
         cls.worker_version_1 = WorkerVersion.objects.get(worker__slug='reco')
         cls.worker_version_2 = WorkerVersion.objects.get(worker__slug='dla')
+        cls.local_worker_run = cls.worker_version_1.worker_runs.filter(process__mode=ProcessMode.Local).get()
         cls.worker_run_1 = cls.worker_version_1.worker_runs.filter(process__mode=ProcessMode.Workers).get()
         cls.worker_run_2 = cls.worker_version_2.worker_runs.filter(process__mode=ProcessMode.Workers).get()
         cls.page = cls.corpus.elements.get(name='Volume 1, page 1r')
@@ -370,7 +371,10 @@ class TestEntitiesAPI(FixtureAPITestCase):
             response = self.client.post(reverse('api:entity-create'), data=data, format='json')
             self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
-    def test_create_entity_with_worker_version(self):
+    def test_create_entity_no_worker_version(self):
+        """
+        Only a worker run can be used to create an entity, not a worker version
+        """
         data = {
             'name': 'entity',
             'type_id': str(self.person_type.id),
@@ -389,19 +393,149 @@ class TestEntitiesAPI(FixtureAPITestCase):
             'worker_version': ['This field is forbidden.'],
         })
 
-    def test_create_entity_with_worker_run(self):
+    def test_create_entity_with_unknown_worker_run(self):
         data = {
             'name': 'entity',
             'type_id': str(self.person_type.id),
             'corpus': str(self.corpus.id),
-            'worker_run_id': str(self.worker_run_1.id),
+            'worker_run_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
             'metas': {
                 'key': 'value',
                 'other key': 'other value'
             },
         }
         self.client.force_login(self.user)
-        with self.assertNumQueries(10):
+        with self.assertNumQueries(7):
+            response = self.client.post(reverse('api:entity-create'), data=data, format='json')
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {'worker_run_id': ['Invalid pk "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" - object does not exist.']})
+
+    def test_create_entity(self):
+        """
+        A user can create an entity without a worker run
+        """
+        self.client.force_login(self.user)
+        with self.assertNumQueries(9):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'test',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'metas': {'pokemon': 'Wo-Chien'},
+                },
+            )
+            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        data = response.json()
+        entity = Entity.objects.get(id=data['id'])
+        self.assertEqual(entity.name, 'test')
+        self.assertEqual(entity.type, self.person_type)
+        self.assertEqual(entity.corpus, self.corpus)
+        self.assertFalse(entity.validated)
+        self.assertEqual(entity.metas, {'pokemon': 'Wo-Chien'})
+        self.assertEqual(entity.worker_version_id, None)
+        self.assertEqual(entity.worker_run, None)
+
+    def test_create_entity_worker_run_non_local(self):
+        """
+        A regular user cannot create an entity with a WorkerRun of a non-local process
+        """
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(5):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'test',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'worker_run_id': str(self.worker_run_1.id),
+                },
+            )
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'worker_run_id': [
+                "Ponos task authentication is required to use a WorkerRun "
+                "of a process other than the user's local process."
+            ]
+
+        })
+
+    def test_create_entity_worker_run_other_user(self):
+        """
+        A regular user cannot create an entity with a WorkerRun of someone else's local process
+        """
+        private_worker_run = self.user.processes.get(mode=ProcessMode.Local).worker_runs.first()
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(5):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'test',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'worker_run_id': str(private_worker_run.id),
+                },
+            )
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'worker_run_id': [
+                "Ponos task authentication is required to use a WorkerRun "
+                "of a process other than the user's local process."
+            ]
+
+        })
+
+    def test_create_entity_worker_run_other_process(self):
+        """
+        A Ponos task cannot create an entity with a WorkerRun of another process
+        """
+        process2 = self.worker_run_1.process.creator.processes.create(
+            mode=ProcessMode.Workers,
+            corpus=self.corpus,
+        )
+        other_worker_run = process2.worker_runs.create(version=self.worker_version_1, parents=[])
+        self.worker_run_1.process.start()
+        task = self.worker_run_1.process.workflow.tasks.first()
+
+        with self.assertNumQueries(6):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'Bunnelby',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'worker_run_id': str(other_worker_run.id),
+                },
+                HTTP_AUTHORIZATION=f'Ponos {task.token}',
+            )
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        self.assertDictEqual(response.json(), {
+            'worker_run_id': [
+                "Only the WorkerRuns of the authenticated task's process may be used."
+            ]
+        })
+
+    def test_create_entity_local_worker_run(self):
+        """
+        A regular user can create an entity with a WorkerRun of their own local process
+        """
+        data = {
+            'name': 'entity',
+            'type_id': str(self.person_type.id),
+            'corpus': str(self.corpus.id),
+            'worker_run_id': str(self.local_worker_run.id),
+            'metas': {
+                'key': 'value',
+                'other key': 'other value'
+            },
+        }
+        self.client.force_login(self.superuser)
+        with self.assertNumQueries(8):
             response = self.client.post(reverse('api:entity-create'), data=data, format='json')
             self.assertEqual(response.status_code, status.HTTP_201_CREATED)
 
@@ -415,8 +549,8 @@ class TestEntitiesAPI(FixtureAPITestCase):
             'key': 'value',
             'other key': 'other value',
         })
-        self.assertEqual(entity.worker_version, self.worker_run_1.version)
-        self.assertEqual(entity.worker_run, self.worker_run_1)
+        self.assertEqual(entity.worker_version_id, self.local_worker_run.version_id)
+        self.assertEqual(entity.worker_run, self.local_worker_run)
 
         self.assertDictEqual(data, {
             'id': str(entity.id),
@@ -437,50 +571,80 @@ class TestEntitiesAPI(FixtureAPITestCase):
             },
             'validated': False,
             'worker_run': {
-                'id': str(self.worker_run_1.id),
-                'summary': self.worker_run_1.summary,
+                'id': str(self.local_worker_run.id),
+                'summary': self.local_worker_run.summary,
             },
-            'worker_version_id': str(self.worker_version_1.id),
+            'worker_version_id': str(self.local_worker_run.version_id),
             'parents': [],
             'children': [],
         })
 
-    def test_create_entity_with_unknown_worker_run(self):
-        data = {
-            'name': 'entity',
-            'type_id': str(self.person_type.id),
-            'corpus': str(self.corpus.id),
-            'worker_run_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
-            'metas': {
-                'key': 'value',
-                'other key': 'other value'
-            },
-        }
-        self.client.force_login(self.user)
-        with self.assertNumQueries(7):
-            response = self.client.post(reverse('api:entity-create'), data=data, format='json')
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {'worker_run_id': ['Invalid pk "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" - object does not exist.']})
+    def test_create_entity_task_auth(self):
+        """
+        An entity can be created with a WorkerRun of a non-local process
+        when authenticated as a Ponos task of this process
+        """
+        self.worker_run_1.process.start()
+        task = self.worker_run_1.process.workflow.tasks.first()
 
-    def test_create_entity_with_worker_run_and_worker_version(self):
-        data = {
-            'name': 'entity',
-            'type_id': str(self.person_type.id),
-            'corpus': str(self.corpus.id),
-            'worker_version': str(self.worker_version_1.id),
-            'worker_run_id': str(self.worker_run_1.id),
-            'metas': {
-                'key': 'value',
-                'other key': 'other value'
-            },
-        }
-        self.client.force_login(self.user)
-        with self.assertNumQueries(7):
-            response = self.client.post(reverse('api:entity-create'), data=data, format='json')
-            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertDictEqual(response.json(), {
-            'worker_version': ['This field is forbidden.'],
-        })
+        with self.assertNumQueries(9):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'test',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'worker_run_id': str(self.worker_run_1.id),
+                },
+                HTTP_AUTHORIZATION=f'Ponos {task.token}',
+            )
+            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        data = response.json()
+        entity = Entity.objects.get(id=data['id'])
+        self.assertEqual(entity.name, 'test')
+        self.assertEqual(entity.type, self.person_type)
+        self.assertEqual(entity.corpus, self.corpus)
+        self.assertFalse(entity.validated)
+        self.assertEqual(entity.metas, None)
+        self.assertEqual(entity.worker_version, self.worker_version_1)
+        self.assertEqual(entity.worker_run, self.worker_run_1)
+
+    def test_create_entity_worker_run_local_task_auth(self):
+        """
+        An entity can be created with a WorkerRun of a Local process
+        even when authenticated as a Ponos task from a different process
+        """
+        local_process = self.user.processes.get(mode=ProcessMode.Local)
+        local_worker_run = local_process.worker_runs.get()
+
+        self.worker_run_1.process.start()
+        task = self.worker_run_1.process.workflow.tasks.first()
+
+        with self.assertNumQueries(9):
+            response = self.client.post(
+                reverse('api:entity-create'),
+                format='json',
+                data={
+                    'name': 'Bunnelby',
+                    'type_id': str(self.person_type.id),
+                    'corpus': str(self.corpus.id),
+                    'worker_run_id': str(local_worker_run.id),
+                },
+                HTTP_AUTHORIZATION=f'Ponos {task.token}',
+            )
+            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+        data = response.json()
+        entity = Entity.objects.get(id=data['id'])
+        self.assertEqual(entity.name, 'Bunnelby')
+        self.assertEqual(entity.type, self.person_type)
+        self.assertEqual(entity.corpus, self.corpus)
+        self.assertFalse(entity.validated)
+        self.assertEqual(entity.metas, None)
+        self.assertEqual(entity.worker_version_id, local_worker_run.version_id)
+        self.assertEqual(entity.worker_run, local_worker_run)
 
     def test_create_link(self):
         child = Entity.objects.create(