diff --git a/arkindex_worker/worker/element.py b/arkindex_worker/worker/element.py
index 2d54563f04de1973a07dafa9ee17844fd8ac3e8c..985481ad0b7a6d1a7dddd630c9bcdf8802bf257a 100644
--- a/arkindex_worker/worker/element.py
+++ b/arkindex_worker/worker/element.py
@@ -497,3 +497,117 @@ class ElementMixin(object):
             )
 
         return children
+
+    def list_element_parents(
+        self,
+        element: Union[Element, CachedElement],
+        folder: Optional[bool] = None,
+        name: Optional[str] = None,
+        recursive: Optional[bool] = None,
+        transcription_worker_version: Optional[Union[str, bool]] = None,
+        transcription_worker_run: Optional[Union[str, bool]] = None,
+        type: Optional[str] = None,
+        with_classes: Optional[bool] = None,
+        with_corpus: Optional[bool] = None,
+        with_metadata: Optional[bool] = None,
+        with_has_children: Optional[bool] = None,
+        with_zone: Optional[bool] = None,
+        worker_version: Optional[Union[str, bool]] = None,
+        worker_run: Optional[Union[str, bool]] = None,
+    ) -> Iterable[dict]:
+        """
+        List parents of an element through the API.
+
+        :param element: Child element to find parents of.
+        :param folder: Restrict to or exclude elements with folder types.
+        :param name: Restrict to elements whose name contain a substring (case-insensitive).
+        :param recursive: Look for elements recursively (grand-parents, etc.)
+        :param transcription_worker_version: Restrict to elements that have a transcription created by a worker version with this UUID.
+        :param transcription_worker_run: Restrict to elements that have a transcription created by a worker run with this UUID.
+        :param type: Restrict to elements with a specific type slug
+        :param with_classes: Include each element's classifications in the response.
+        :param with_corpus: Include each element's corpus in the response.
+        :param with_has_children: Include the ``has_children`` attribute in the response,
+           indicating if this element has child elements of its own.
+        :param with_metadata: Include each element's metadata in the response.
+        :param with_zone: Include the ``zone`` attribute in the response,
+           holding the element's image and polygon.
+        :param worker_version: Restrict to elements created by a worker version with this UUID.
+        :param worker_run: Restrict to elements created by a worker run with this UUID.
+        :return: An iterable of dicts from the ``ListElementChildren`` API endpoint.
+        """
+        assert element and isinstance(
+            element, (Element, CachedElement)
+        ), "element shouldn't be null and should be an Element or CachedElement"
+        query_params = {}
+        if folder is not None:
+            assert isinstance(folder, bool), "folder should be of type bool"
+            query_params["folder"] = folder
+        if name:
+            assert isinstance(name, str), "name should be of type str"
+            query_params["name"] = name
+        if recursive is not None:
+            assert isinstance(recursive, bool), "recursive should be of type bool"
+            query_params["recursive"] = recursive
+        if transcription_worker_version is not None:
+            assert isinstance(
+                transcription_worker_version, (str, bool)
+            ), "transcription_worker_version should be of type str or bool"
+            if isinstance(transcription_worker_version, bool):
+                assert (
+                    transcription_worker_version is False
+                ), "if of type bool, transcription_worker_version can only be set to False"
+            query_params["transcription_worker_version"] = transcription_worker_version
+        if transcription_worker_run is not None:
+            assert isinstance(
+                transcription_worker_run, (str, bool)
+            ), "transcription_worker_run should be of type str or bool"
+            if isinstance(transcription_worker_run, bool):
+                assert (
+                    transcription_worker_run is False
+                ), "if of type bool, transcription_worker_run can only be set to False"
+            query_params["transcription_worker_run"] = transcription_worker_run
+        if type:
+            assert isinstance(type, str), "type should be of type str"
+            query_params["type"] = type
+        if with_classes is not None:
+            assert isinstance(with_classes, bool), "with_classes should be of type bool"
+            query_params["with_classes"] = with_classes
+        if with_corpus is not None:
+            assert isinstance(with_corpus, bool), "with_corpus should be of type bool"
+            query_params["with_corpus"] = with_corpus
+        if with_has_children is not None:
+            assert isinstance(
+                with_has_children, bool
+            ), "with_has_children should be of type bool"
+            query_params["with_has_children"] = with_has_children
+        if with_metadata is not None:
+            assert isinstance(
+                with_metadata, bool
+            ), "with_metadata should be of type bool"
+            query_params["with_metadata"] = with_metadata
+        if with_zone is not None:
+            assert isinstance(with_zone, bool), "with_zone should be of type bool"
+            query_params["with_zone"] = with_zone
+        if worker_version is not None:
+            assert isinstance(
+                worker_version, (str, bool)
+            ), "worker_version should be of type str or bool"
+            if isinstance(worker_version, bool):
+                assert (
+                    worker_version is False
+                ), "if of type bool, worker_version can only be set to False"
+            query_params["worker_version"] = worker_version
+        if worker_run is not None:
+            assert isinstance(
+                worker_run, (str, bool)
+            ), "worker_run should be of type str or bool"
+            if isinstance(worker_run, bool):
+                assert (
+                    worker_run is False
+                ), "if of type bool, worker_run can only be set to False"
+            query_params["worker_run"] = worker_run
+
+        return self.api_client.paginate(
+            "ListElementParents", id=element.id, **query_params
+        )
diff --git a/tests/test_elements_worker/test_elements.py b/tests/test_elements_worker/test_elements.py
index 12b438722866ab7932aa1fae855cf6cac7722d79..1b7f96d7aba6eae0b62b18070982bd1e8c82597e 100644
--- a/tests/test_elements_worker/test_elements.py
+++ b/tests/test_elements_worker/test_elements.py
@@ -1862,3 +1862,352 @@ def test_list_element_children_with_cache(
     assert [
         (call.request.method, call.request.url) for call in responses.calls
     ] == BASE_API_CALLS
+
+
+def test_list_element_parents_wrong_element(mock_elements_worker):
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(element=None)
+    assert (
+        str(e.value)
+        == "element shouldn't be null and should be an Element or CachedElement"
+    )
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(element="not element type")
+    assert (
+        str(e.value)
+        == "element shouldn't be null and should be an Element or CachedElement"
+    )
+
+
+def test_list_element_parents_wrong_folder(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            folder="not bool",
+        )
+    assert str(e.value) == "folder should be of type bool"
+
+
+def test_list_element_parents_wrong_name(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            name=1234,
+        )
+    assert str(e.value) == "name should be of type str"
+
+
+def test_list_element_parents_wrong_recursive(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            recursive="not bool",
+        )
+    assert str(e.value) == "recursive should be of type bool"
+
+
+def test_list_element_parents_wrong_type(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            type=1234,
+        )
+    assert str(e.value) == "type should be of type str"
+
+
+def test_list_element_parents_wrong_with_classes(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            with_classes="not bool",
+        )
+    assert str(e.value) == "with_classes should be of type bool"
+
+
+def test_list_element_parents_wrong_with_corpus(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            with_corpus="not bool",
+        )
+    assert str(e.value) == "with_corpus should be of type bool"
+
+
+def test_list_element_parents_wrong_with_has_children(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            with_has_children="not bool",
+        )
+    assert str(e.value) == "with_has_children should be of type bool"
+
+
+def test_list_element_parents_wrong_with_zone(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            with_zone="not bool",
+        )
+    assert str(e.value) == "with_zone should be of type bool"
+
+
+def test_list_element_parents_wrong_with_metadata(mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            with_metadata="not bool",
+        )
+    assert str(e.value) == "with_metadata should be of type bool"
+
+
+@pytest.mark.parametrize(
+    "param, value",
+    (
+        ("worker_version", 1234),
+        ("worker_run", 1234),
+        ("transcription_worker_version", 1234),
+        ("transcription_worker_run", 1234),
+    ),
+)
+def test_list_element_parents_wrong_worker_version(mock_elements_worker, param, value):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            **{param: value},
+        )
+    assert str(e.value) == f"{param} should be of type str or bool"
+
+
+@pytest.mark.parametrize(
+    "param",
+    (
+        ("worker_version"),
+        ("worker_run"),
+        ("transcription_worker_version"),
+        ("transcription_worker_run"),
+    ),
+)
+def test_list_element_parents_wrong_bool_worker_version(mock_elements_worker, param):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+
+    with pytest.raises(AssertionError) as e:
+        mock_elements_worker.list_element_parents(
+            element=elt,
+            **{param: True},
+        )
+    assert str(e.value) == f"if of type bool, {param} can only be set to False"
+
+
+def test_list_element_parents_api_error(responses, mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+    responses.add(
+        responses.GET,
+        "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        status=500,
+    )
+
+    with pytest.raises(
+        Exception, match="Stopping pagination as data will be incomplete"
+    ):
+        next(mock_elements_worker.list_element_parents(element=elt))
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 5
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        # We do 5 retries
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+    ]
+
+
+def test_list_element_parents(responses, mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+    expected_parents = [
+        {
+            "id": "0000",
+            "type": "page",
+            "name": "Test",
+            "corpus": {},
+            "thumbnail_url": None,
+            "zone": {},
+            "best_classes": None,
+            "has_children": None,
+            "worker_version_id": None,
+            "worker_run_id": None,
+        },
+        {
+            "id": "1111",
+            "type": "page",
+            "name": "Test 2",
+            "corpus": {},
+            "thumbnail_url": None,
+            "zone": {},
+            "best_classes": None,
+            "has_children": None,
+            "worker_version_id": None,
+            "worker_run_id": None,
+        },
+        {
+            "id": "2222",
+            "type": "page",
+            "name": "Test 3",
+            "corpus": {},
+            "thumbnail_url": None,
+            "zone": {},
+            "best_classes": None,
+            "has_children": None,
+            "worker_version_id": None,
+            "worker_run_id": None,
+        },
+    ]
+    responses.add(
+        responses.GET,
+        "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        status=200,
+        json={
+            "count": 3,
+            "next": None,
+            "results": expected_parents,
+        },
+    )
+
+    for idx, parent in enumerate(
+        mock_elements_worker.list_element_parents(element=elt)
+    ):
+        assert parent == expected_parents[idx]
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 1
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
+        ),
+    ]
+
+
+def test_list_element_parents_manual_worker_version(responses, mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+    expected_parents = [
+        {
+            "id": "0000",
+            "type": "page",
+            "name": "Test",
+            "corpus": {},
+            "thumbnail_url": None,
+            "zone": {},
+            "best_classes": None,
+            "has_children": None,
+            "worker_version_id": None,
+            "worker_run_id": None,
+        }
+    ]
+    responses.add(
+        responses.GET,
+        "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_version=False",
+        status=200,
+        json={
+            "count": 1,
+            "next": None,
+            "results": expected_parents,
+        },
+    )
+
+    for idx, parent in enumerate(
+        mock_elements_worker.list_element_parents(element=elt, worker_version=False)
+    ):
+        assert parent == expected_parents[idx]
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 1
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_version=False",
+        ),
+    ]
+
+
+def test_list_element_parents_manual_worker_run(responses, mock_elements_worker):
+    elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
+    expected_parents = [
+        {
+            "id": "0000",
+            "type": "page",
+            "name": "Test",
+            "corpus": {},
+            "thumbnail_url": None,
+            "zone": {},
+            "best_classes": None,
+            "has_children": None,
+            "worker_version_id": None,
+            "worker_run_id": None,
+        }
+    ]
+    responses.add(
+        responses.GET,
+        "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_run=False",
+        status=200,
+        json={
+            "count": 1,
+            "next": None,
+            "results": expected_parents,
+        },
+    )
+
+    for idx, parent in enumerate(
+        mock_elements_worker.list_element_parents(element=elt, worker_run=False)
+    ):
+        assert parent == expected_parents[idx]
+
+    assert len(responses.calls) == len(BASE_API_CALLS) + 1
+    assert [
+        (call.request.method, call.request.url) for call in responses.calls
+    ] == BASE_API_CALLS + [
+        (
+            "GET",
+            "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_run=False",
+        ),
+    ]