easypaperless.resources

Resource Classes

The following resource classes are _internal classes. Methods can be accessed via the instance of easypaperless.PaperlessClient or easypaperless.SyncPaperlessClient

Example:

async with PaperlessClient(url="http://localhost:8000", api_key="abc") as client: docs = await client.documents.list(max_results=10)

 1"""Resource Classes
 2
 3The following resource classes are _internal classes. Methods can be accessed via the instance of 
 4`easypaperless.PaperlessClient` or `easypaperless.SyncPaperlessClient`
 5
 6Example:
 7    async with PaperlessClient(url="http://localhost:8000", api_key="abc") as client:
 8        docs = await client.documents.list(max_results=10)
 9
10"""
11
12# internal comment: the doc string above is also rendered in the pdoc documentation. 
13#
14# original was: 
15#
16# Public resource classes — for type annotations and IDE support.
17# 
18# Re-exports all async and sync resource classes from the internal modules
19# so that pdoc can document them as a full page with all methods.
20#
21# Example:
22#    from easypaperless.resources import DocumentsResource
23
24
25from easypaperless._internal.resources.correspondents import CorrespondentsResource
26from easypaperless._internal.resources.custom_fields import CustomFieldsResource
27from easypaperless._internal.resources.document_types import DocumentTypesResource
28from easypaperless._internal.resources.documents import DocumentsResource, NotesResource
29from easypaperless._internal.resources.storage_paths import StoragePathsResource
30from easypaperless._internal.resources.tags import TagsResource
31from easypaperless._internal.sync_resources.correspondents import SyncCorrespondentsResource
32from easypaperless._internal.sync_resources.custom_fields import SyncCustomFieldsResource
33from easypaperless._internal.sync_resources.document_types import SyncDocumentTypesResource
34from easypaperless._internal.sync_resources.documents import (
35    SyncDocumentsResource,
36    SyncNotesResource,
37)
38from easypaperless._internal.sync_resources.storage_paths import SyncStoragePathsResource
39from easypaperless._internal.sync_resources.tags import SyncTagsResource
40
41__all__ = [
42    "CorrespondentsResource",
43    "CustomFieldsResource",
44    "DocumentTypesResource",
45    "DocumentsResource",
46    "NotesResource",
47    "StoragePathsResource",
48    "TagsResource",
49    "SyncCorrespondentsResource",
50    "SyncCustomFieldsResource",
51    "SyncDocumentTypesResource",
52    "SyncDocumentsResource",
53    "SyncNotesResource",
54    "SyncStoragePathsResource",
55    "SyncTagsResource",
56]
class CorrespondentsResource:
 17class CorrespondentsResource:
 18    """Accessor for correspondents: ``client.correspondents``."""
 19
 20    def __init__(self, core: _ClientCore) -> None:
 21        self._core = core
 22
 23    async def list(
 24        self,
 25        *,
 26        ids: List[int] | None = None,
 27        name_contains: str | None = None,
 28        name_exact: str | None = None,
 29        page: int | None = None,
 30        page_size: int | None = None,
 31        ordering: str | None = None,
 32        descending: bool = False,
 33    ) -> List[Correspondent]:
 34        """Return correspondents defined in paperless-ngx.
 35
 36        Args:
 37            ids: Return only correspondents whose ID is in this list.
 38            name_contains: Case-insensitive substring filter on name.
 39            name_exact: Case-insensitive exact match on name.
 40            page: Return only this specific page (1-based).
 41            page_size: Number of results per page.
 42            ordering: Field to sort by.
 43            descending: When ``True``, reverses the sort direction.
 44
 45        Returns:
 46            List of :class:`~easypaperless.models.correspondents.Correspondent` objects.
 47        """
 48        params: dict[str, Any] = {}
 49        if ids is not None:
 50            params["id__in"] = ",".join(str(i) for i in ids)
 51        if name_contains is not None:
 52            params["name__icontains"] = name_contains
 53        if name_exact is not None:
 54            params["name__iexact"] = name_exact
 55        if page is not None:
 56            params["page"] = page
 57        if page_size is not None:
 58            params["page_size"] = page_size
 59        if ordering is not None:
 60            params["ordering"] = f"-{ordering}" if descending else ordering
 61        return cast(
 62            List[Correspondent],
 63            await self._core._list_resource("correspondents", Correspondent, params or None),
 64        )
 65
 66    async def get(self, id: int) -> Correspondent:
 67        """Fetch a single correspondent by its ID.
 68
 69        Args:
 70            id: Numeric correspondent ID.
 71
 72        Returns:
 73            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
 74
 75        Raises:
 76            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
 77        """
 78        return cast(
 79            Correspondent, await self._core._get_resource("correspondents", id, Correspondent)
 80        )
 81
 82    async def create(
 83        self,
 84        *,
 85        name: str,
 86        match: str | None | _Unset = UNSET,
 87        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 88        is_insensitive: bool = True,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> Correspondent:
 92        """Create a new correspondent.
 93
 94        Args:
 95            name: Correspondent name. Must be unique.
 96            match: Auto-matching pattern.
 97            matching_algorithm: Controls how ``match`` is applied.
 98            is_insensitive: When ``True``, ``match`` is case-insensitive.
 99                Defaults to ``True``, matching the paperless-ngx API default.
100            owner: Numeric user ID to assign as owner.
101            set_permissions: Explicit view/change permission sets.
102
103        Returns:
104            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
105        """
106        return cast(
107            Correspondent,
108            await self._core._create_resource(
109                "correspondents",
110                Correspondent,
111                owner=owner,
112                set_permissions=set_permissions,
113                name=name,
114                match=match,
115                matching_algorithm=matching_algorithm,
116                is_insensitive=is_insensitive,
117            ),
118        )
119
120    async def update(
121        self,
122        id: int,
123        *,
124        name: str | None | _Unset = UNSET,
125        match: str | None | _Unset = UNSET,
126        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
127        is_insensitive: bool | None | _Unset = UNSET,
128        owner: int | None | _Unset = UNSET,
129        set_permissions: SetPermissions | None | _Unset = UNSET,
130    ) -> Correspondent:
131        """Partially update a correspondent (PATCH semantics).
132
133        Args:
134            id: Numeric ID of the correspondent to update.
135            name: Correspondent name.
136            match: Auto-matching pattern.
137            matching_algorithm: Controls how ``match`` is applied.
138            is_insensitive: When ``True``, ``match`` is case-insensitive.
139            owner: Numeric user ID to assign as owner.
140                Pass ``None`` to clear the owner.
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            set_permissions: Explicit view/change permission sets.
143                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
144
145        Returns:
146            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
147        """
148        _set_perms: dict[str, Any] | _Unset = (
149            UNSET
150            if isinstance(set_permissions, _Unset)
151            else (set_permissions or SetPermissions()).model_dump()
152        )
153        return cast(
154            Correspondent,
155            await self._core._update_resource(
156                "correspondents",
157                id,
158                Correspondent,
159                name=name,
160                match=match,
161                matching_algorithm=matching_algorithm,
162                is_insensitive=is_insensitive,
163                owner=owner,
164                set_permissions=_set_perms,
165            ),
166        )
167
168    async def delete(self, id: int) -> None:
169        """Delete a correspondent.
170
171        Args:
172            id: Numeric ID of the correspondent to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
176        """
177        await self._core._delete_resource("correspondents", id)
178
179    async def bulk_delete(self, ids: List[int]) -> None:
180        """Permanently delete multiple correspondents in a single request.
181
182        Args:
183            ids: List of correspondent IDs to delete.
184        """
185        await self._core._bulk_edit_objects("correspondents", ids, "delete")
186
187    async def bulk_set_permissions(
188        self,
189        ids: List[int],
190        *,
191        set_permissions: SetPermissions | None = None,
192        owner: int | None = None,
193        merge: bool = False,
194    ) -> None:
195        """Set permissions and/or owner on multiple correspondents.
196
197        Args:
198            ids: List of correspondent IDs to modify.
199            set_permissions: Explicit view/change permission sets.
200            owner: Numeric user ID to assign as owner.
201            merge: When ``True``, new permissions are merged with existing ones.
202        """
203        params: dict[str, Any] = {"merge": merge}
204        if set_permissions is not None:
205            params["permissions"] = set_permissions.model_dump()
206        if owner is not None:
207            params["owner"] = owner
208        await self._core._bulk_edit_objects("correspondents", ids, "set_permissions", **params)

Accessor for correspondents: client.correspondents.

CorrespondentsResource(core: easypaperless.client._ClientCore)
20    def __init__(self, core: _ClientCore) -> None:
21        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.Correspondent]:
23    async def list(
24        self,
25        *,
26        ids: List[int] | None = None,
27        name_contains: str | None = None,
28        name_exact: str | None = None,
29        page: int | None = None,
30        page_size: int | None = None,
31        ordering: str | None = None,
32        descending: bool = False,
33    ) -> List[Correspondent]:
34        """Return correspondents defined in paperless-ngx.
35
36        Args:
37            ids: Return only correspondents whose ID is in this list.
38            name_contains: Case-insensitive substring filter on name.
39            name_exact: Case-insensitive exact match on name.
40            page: Return only this specific page (1-based).
41            page_size: Number of results per page.
42            ordering: Field to sort by.
43            descending: When ``True``, reverses the sort direction.
44
45        Returns:
46            List of :class:`~easypaperless.models.correspondents.Correspondent` objects.
47        """
48        params: dict[str, Any] = {}
49        if ids is not None:
50            params["id__in"] = ",".join(str(i) for i in ids)
51        if name_contains is not None:
52            params["name__icontains"] = name_contains
53        if name_exact is not None:
54            params["name__iexact"] = name_exact
55        if page is not None:
56            params["page"] = page
57        if page_size is not None:
58            params["page_size"] = page_size
59        if ordering is not None:
60            params["ordering"] = f"-{ordering}" if descending else ordering
61        return cast(
62            List[Correspondent],
63            await self._core._list_resource("correspondents", Correspondent, params or None),
64        )

Return correspondents defined in paperless-ngx.

Arguments:
  • ids: Return only correspondents whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.correspondents.Correspondent objects.

async def get(self, id: int) -> easypaperless.Correspondent:
66    async def get(self, id: int) -> Correspondent:
67        """Fetch a single correspondent by its ID.
68
69        Args:
70            id: Numeric correspondent ID.
71
72        Returns:
73            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
74
75        Raises:
76            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
77        """
78        return cast(
79            Correspondent, await self._core._get_resource("correspondents", id, Correspondent)
80        )

Fetch a single correspondent by its ID.

Arguments:
  • id: Numeric correspondent ID.
Returns:

The ~easypaperless.models.correspondents.Correspondent with the given ID.

Raises:
async def create( self, *, name: str, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.Correspondent:
 82    async def create(
 83        self,
 84        *,
 85        name: str,
 86        match: str | None | _Unset = UNSET,
 87        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 88        is_insensitive: bool = True,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> Correspondent:
 92        """Create a new correspondent.
 93
 94        Args:
 95            name: Correspondent name. Must be unique.
 96            match: Auto-matching pattern.
 97            matching_algorithm: Controls how ``match`` is applied.
 98            is_insensitive: When ``True``, ``match`` is case-insensitive.
 99                Defaults to ``True``, matching the paperless-ngx API default.
100            owner: Numeric user ID to assign as owner.
101            set_permissions: Explicit view/change permission sets.
102
103        Returns:
104            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
105        """
106        return cast(
107            Correspondent,
108            await self._core._create_resource(
109                "correspondents",
110                Correspondent,
111                owner=owner,
112                set_permissions=set_permissions,
113                name=name,
114                match=match,
115                matching_algorithm=matching_algorithm,
116                is_insensitive=is_insensitive,
117            ),
118        )

Create a new correspondent.

Arguments:
  • name: Correspondent name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.correspondents.Correspondent.

async def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Correspondent:
120    async def update(
121        self,
122        id: int,
123        *,
124        name: str | None | _Unset = UNSET,
125        match: str | None | _Unset = UNSET,
126        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
127        is_insensitive: bool | None | _Unset = UNSET,
128        owner: int | None | _Unset = UNSET,
129        set_permissions: SetPermissions | None | _Unset = UNSET,
130    ) -> Correspondent:
131        """Partially update a correspondent (PATCH semantics).
132
133        Args:
134            id: Numeric ID of the correspondent to update.
135            name: Correspondent name.
136            match: Auto-matching pattern.
137            matching_algorithm: Controls how ``match`` is applied.
138            is_insensitive: When ``True``, ``match`` is case-insensitive.
139            owner: Numeric user ID to assign as owner.
140                Pass ``None`` to clear the owner.
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            set_permissions: Explicit view/change permission sets.
143                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
144
145        Returns:
146            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
147        """
148        _set_perms: dict[str, Any] | _Unset = (
149            UNSET
150            if isinstance(set_permissions, _Unset)
151            else (set_permissions or SetPermissions()).model_dump()
152        )
153        return cast(
154            Correspondent,
155            await self._core._update_resource(
156                "correspondents",
157                id,
158                Correspondent,
159                name=name,
160                match=match,
161                matching_algorithm=matching_algorithm,
162                is_insensitive=is_insensitive,
163                owner=owner,
164                set_permissions=_set_perms,
165            ),
166        )

Partially update a correspondent (PATCH semantics).

Arguments:
  • id: Numeric ID of the correspondent to update.
  • name: Correspondent name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.correspondents.Correspondent.

async def delete(self, id: int) -> None:
168    async def delete(self, id: int) -> None:
169        """Delete a correspondent.
170
171        Args:
172            id: Numeric ID of the correspondent to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
176        """
177        await self._core._delete_resource("correspondents", id)

Delete a correspondent.

Arguments:
  • id: Numeric ID of the correspondent to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
179    async def bulk_delete(self, ids: List[int]) -> None:
180        """Permanently delete multiple correspondents in a single request.
181
182        Args:
183            ids: List of correspondent IDs to delete.
184        """
185        await self._core._bulk_edit_objects("correspondents", ids, "delete")

Permanently delete multiple correspondents in a single request.

Arguments:
  • ids: List of correspondent IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
187    async def bulk_set_permissions(
188        self,
189        ids: List[int],
190        *,
191        set_permissions: SetPermissions | None = None,
192        owner: int | None = None,
193        merge: bool = False,
194    ) -> None:
195        """Set permissions and/or owner on multiple correspondents.
196
197        Args:
198            ids: List of correspondent IDs to modify.
199            set_permissions: Explicit view/change permission sets.
200            owner: Numeric user ID to assign as owner.
201            merge: When ``True``, new permissions are merged with existing ones.
202        """
203        params: dict[str, Any] = {"merge": merge}
204        if set_permissions is not None:
205            params["permissions"] = set_permissions.model_dump()
206        if owner is not None:
207            params["owner"] = owner
208        await self._core._bulk_edit_objects("correspondents", ids, "set_permissions", **params)

Set permissions and/or owner on multiple correspondents.

Arguments:
  • ids: List of correspondent IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class CustomFieldsResource:
 16class CustomFieldsResource:
 17    """Accessor for custom fields: ``client.custom_fields``."""
 18
 19    def __init__(self, core: _ClientCore) -> None:
 20        self._core = core
 21
 22    async def list(
 23        self,
 24        *,
 25        name_contains: str | None = None,
 26        name_exact: str | None = None,
 27        page: int | None = None,
 28        page_size: int | None = None,
 29        ordering: str | None = None,
 30        descending: bool = False,
 31    ) -> List[CustomField]:
 32        """Return all custom fields defined in paperless-ngx.
 33
 34        Args:
 35            name_contains: Case-insensitive substring filter on name.
 36            name_exact: Case-insensitive exact match on name.
 37            page: Return only this specific page (1-based).
 38            page_size: Number of results per page.
 39            ordering: Field to sort by.
 40            descending: When ``True``, reverses the sort direction.
 41
 42        Returns:
 43            List of :class:`~easypaperless.models.custom_fields.CustomField` objects.
 44        """
 45        params: dict[str, Any] = {}
 46        if name_contains is not None:
 47            params["name__icontains"] = name_contains
 48        if name_exact is not None:
 49            params["name__iexact"] = name_exact
 50        if page is not None:
 51            params["page"] = page
 52        if page_size is not None:
 53            params["page_size"] = page_size
 54        if ordering is not None:
 55            params["ordering"] = f"-{ordering}" if descending else ordering
 56        return cast(
 57            List[CustomField],
 58            await self._core._list_resource("custom_fields", CustomField, params or None),
 59        )
 60
 61    async def get(self, id: int) -> CustomField:
 62        """Fetch a single custom field by its ID.
 63
 64        Args:
 65            id: Numeric custom-field ID.
 66
 67        Returns:
 68            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
 69
 70        Raises:
 71            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
 72        """
 73        return cast(CustomField, await self._core._get_resource("custom_fields", id, CustomField))
 74
 75    async def create(
 76        self,
 77        *,
 78        name: str,
 79        data_type: str,
 80        extra_data: Any | None = None,
 81        owner: int | None | _Unset = UNSET,
 82        set_permissions: SetPermissions | None = None,
 83    ) -> CustomField:
 84        """Create a new custom field.
 85
 86        Args:
 87            name: Field name shown in the UI. Must be unique.
 88            data_type: Value type. One of ``"string"``, ``"boolean"``,
 89                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 90                ``"url"``, ``"documentlink"``, ``"select"``.
 91            extra_data: Additional configuration for the field type.
 92            owner: Numeric user ID to assign as owner.
 93            set_permissions: Explicit view/change permission sets.
 94
 95        Returns:
 96            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
 97        """
 98        return cast(
 99            CustomField,
100            await self._core._create_resource(
101                "custom_fields",
102                CustomField,
103                owner=owner,
104                set_permissions=set_permissions,
105                name=name,
106                data_type=data_type,
107                extra_data=extra_data,
108            ),
109        )
110
111    async def update(
112        self,
113        id: int,
114        *,
115        name: str | None | _Unset = UNSET,
116        data_type: str | None | _Unset = UNSET,
117        extra_data: Any | None | _Unset = UNSET,
118    ) -> CustomField:
119        """Partially update a custom field (PATCH semantics).
120
121        Args:
122            id: Numeric ID of the custom field to update.
123            name: Field name shown in the UI.
124            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
125                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
126            extra_data: Additional configuration for the field type.
127
128        Returns:
129            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
130        """
131        return cast(
132            CustomField,
133            await self._core._update_resource(
134                "custom_fields",
135                id,
136                CustomField,
137                name=name,
138                data_type=data_type,
139                extra_data=extra_data,
140            ),
141        )
142
143    async def delete(self, id: int) -> None:
144        """Delete a custom field.
145
146        Args:
147            id: Numeric ID of the custom field to delete.
148
149        Raises:
150            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
151        """
152        await self._core._delete_resource("custom_fields", id)

Accessor for custom fields: client.custom_fields.

CustomFieldsResource(core: easypaperless.client._ClientCore)
19    def __init__(self, core: _ClientCore) -> None:
20        self._core = core
async def list( self, *, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.CustomField]:
22    async def list(
23        self,
24        *,
25        name_contains: str | None = None,
26        name_exact: str | None = None,
27        page: int | None = None,
28        page_size: int | None = None,
29        ordering: str | None = None,
30        descending: bool = False,
31    ) -> List[CustomField]:
32        """Return all custom fields defined in paperless-ngx.
33
34        Args:
35            name_contains: Case-insensitive substring filter on name.
36            name_exact: Case-insensitive exact match on name.
37            page: Return only this specific page (1-based).
38            page_size: Number of results per page.
39            ordering: Field to sort by.
40            descending: When ``True``, reverses the sort direction.
41
42        Returns:
43            List of :class:`~easypaperless.models.custom_fields.CustomField` objects.
44        """
45        params: dict[str, Any] = {}
46        if name_contains is not None:
47            params["name__icontains"] = name_contains
48        if name_exact is not None:
49            params["name__iexact"] = name_exact
50        if page is not None:
51            params["page"] = page
52        if page_size is not None:
53            params["page_size"] = page_size
54        if ordering is not None:
55            params["ordering"] = f"-{ordering}" if descending else ordering
56        return cast(
57            List[CustomField],
58            await self._core._list_resource("custom_fields", CustomField, params or None),
59        )

Return all custom fields defined in paperless-ngx.

Arguments:
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.custom_fields.CustomField objects.

async def get(self, id: int) -> easypaperless.CustomField:
61    async def get(self, id: int) -> CustomField:
62        """Fetch a single custom field by its ID.
63
64        Args:
65            id: Numeric custom-field ID.
66
67        Returns:
68            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
69
70        Raises:
71            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
72        """
73        return cast(CustomField, await self._core._get_resource("custom_fields", id, CustomField))

Fetch a single custom field by its ID.

Arguments:
  • id: Numeric custom-field ID.
Returns:

The ~easypaperless.models.custom_fields.CustomField with the given ID.

Raises:
async def create( self, *, name: str, data_type: str, extra_data: typing.Any | None = None, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.CustomField:
 75    async def create(
 76        self,
 77        *,
 78        name: str,
 79        data_type: str,
 80        extra_data: Any | None = None,
 81        owner: int | None | _Unset = UNSET,
 82        set_permissions: SetPermissions | None = None,
 83    ) -> CustomField:
 84        """Create a new custom field.
 85
 86        Args:
 87            name: Field name shown in the UI. Must be unique.
 88            data_type: Value type. One of ``"string"``, ``"boolean"``,
 89                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 90                ``"url"``, ``"documentlink"``, ``"select"``.
 91            extra_data: Additional configuration for the field type.
 92            owner: Numeric user ID to assign as owner.
 93            set_permissions: Explicit view/change permission sets.
 94
 95        Returns:
 96            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
 97        """
 98        return cast(
 99            CustomField,
100            await self._core._create_resource(
101                "custom_fields",
102                CustomField,
103                owner=owner,
104                set_permissions=set_permissions,
105                name=name,
106                data_type=data_type,
107                extra_data=extra_data,
108            ),
109        )

Create a new custom field.

Arguments:
  • name: Field name shown in the UI. Must be unique.
  • data_type: Value type. One of "string", "boolean", "integer", "float", "monetary", "date", "url", "documentlink", "select".
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.custom_fields.CustomField.

async def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, data_type: str | None | easypaperless._internal.sentinel._Unset = UNSET, extra_data: typing.Any | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.CustomField:
111    async def update(
112        self,
113        id: int,
114        *,
115        name: str | None | _Unset = UNSET,
116        data_type: str | None | _Unset = UNSET,
117        extra_data: Any | None | _Unset = UNSET,
118    ) -> CustomField:
119        """Partially update a custom field (PATCH semantics).
120
121        Args:
122            id: Numeric ID of the custom field to update.
123            name: Field name shown in the UI.
124            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
125                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
126            extra_data: Additional configuration for the field type.
127
128        Returns:
129            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
130        """
131        return cast(
132            CustomField,
133            await self._core._update_resource(
134                "custom_fields",
135                id,
136                CustomField,
137                name=name,
138                data_type=data_type,
139                extra_data=extra_data,
140            ),
141        )

Partially update a custom field (PATCH semantics).

Arguments:
  • id: Numeric ID of the custom field to update.
  • name: Field name shown in the UI.
  • data_type: Value type (e.g. "string", "boolean", "integer"). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • extra_data: Additional configuration for the field type.
Returns:

The updated ~easypaperless.models.custom_fields.CustomField.

async def delete(self, id: int) -> None:
143    async def delete(self, id: int) -> None:
144        """Delete a custom field.
145
146        Args:
147            id: Numeric ID of the custom field to delete.
148
149        Raises:
150            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
151        """
152        await self._core._delete_resource("custom_fields", id)

Delete a custom field.

Arguments:
  • id: Numeric ID of the custom field to delete.
Raises:
class DocumentTypesResource:
 17class DocumentTypesResource:
 18    """Accessor for document types: ``client.document_types``."""
 19
 20    def __init__(self, core: _ClientCore) -> None:
 21        self._core = core
 22
 23    async def list(
 24        self,
 25        *,
 26        ids: List[int] | None = None,
 27        name_contains: str | None = None,
 28        name_exact: str | None = None,
 29        page: int | None = None,
 30        page_size: int | None = None,
 31        ordering: str | None = None,
 32        descending: bool = False,
 33    ) -> List[DocumentType]:
 34        """Return document types defined in paperless-ngx.
 35
 36        Args:
 37            ids: Return only document types whose ID is in this list.
 38            name_contains: Case-insensitive substring filter on name.
 39            name_exact: Case-insensitive exact match on name.
 40            page: Return only this specific page (1-based).
 41            page_size: Number of results per page.
 42            ordering: Field to sort by.
 43            descending: When ``True``, reverses the sort direction.
 44
 45        Returns:
 46            List of :class:`~easypaperless.models.document_types.DocumentType` objects.
 47        """
 48        params: dict[str, Any] = {}
 49        if ids is not None:
 50            params["id__in"] = ",".join(str(i) for i in ids)
 51        if name_contains is not None:
 52            params["name__icontains"] = name_contains
 53        if name_exact is not None:
 54            params["name__iexact"] = name_exact
 55        if page is not None:
 56            params["page"] = page
 57        if page_size is not None:
 58            params["page_size"] = page_size
 59        if ordering is not None:
 60            params["ordering"] = f"-{ordering}" if descending else ordering
 61        return cast(
 62            List[DocumentType],
 63            await self._core._list_resource("document_types", DocumentType, params or None),
 64        )
 65
 66    async def get(self, id: int) -> DocumentType:
 67        """Fetch a single document type by its ID.
 68
 69        Args:
 70            id: Numeric document-type ID.
 71
 72        Returns:
 73            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
 74
 75        Raises:
 76            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
 77        """
 78        return cast(
 79            DocumentType, await self._core._get_resource("document_types", id, DocumentType)
 80        )
 81
 82    async def create(
 83        self,
 84        *,
 85        name: str,
 86        match: str | None | _Unset = UNSET,
 87        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 88        is_insensitive: bool = True,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> DocumentType:
 92        """Create a new document type.
 93
 94        Args:
 95            name: Document-type name. Must be unique.
 96            match: Auto-matching pattern.
 97            matching_algorithm: Controls how ``match`` is applied.
 98            is_insensitive: When ``True``, ``match`` is case-insensitive.
 99                Defaults to ``True``, matching the paperless-ngx API default.
100            owner: Numeric user ID to assign as owner.
101            set_permissions: Explicit view/change permission sets.
102
103        Returns:
104            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
105        """
106        return cast(
107            DocumentType,
108            await self._core._create_resource(
109                "document_types",
110                DocumentType,
111                owner=owner,
112                set_permissions=set_permissions,
113                name=name,
114                match=match,
115                matching_algorithm=matching_algorithm,
116                is_insensitive=is_insensitive,
117            ),
118        )
119
120    async def update(
121        self,
122        id: int,
123        *,
124        name: str | None | _Unset = UNSET,
125        match: str | None | _Unset = UNSET,
126        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
127        is_insensitive: bool | None | _Unset = UNSET,
128        owner: int | None | _Unset = UNSET,
129        set_permissions: SetPermissions | None | _Unset = UNSET,
130    ) -> DocumentType:
131        """Partially update a document type (PATCH semantics).
132
133        Args:
134            id: Numeric ID of the document type to update.
135            name: Document-type name.
136            match: Auto-matching pattern.
137            matching_algorithm: Controls how ``match`` is applied.
138            is_insensitive: When ``True``, ``match`` is case-insensitive.
139            owner: Numeric user ID to assign as owner.
140                Pass ``None`` to clear the owner.
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            set_permissions: Explicit view/change permission sets.
143                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
144
145        Returns:
146            The updated :class:`~easypaperless.models.document_types.DocumentType`.
147        """
148        _set_perms: dict[str, Any] | _Unset = (
149            UNSET
150            if isinstance(set_permissions, _Unset)
151            else (set_permissions or SetPermissions()).model_dump()
152        )
153        return cast(
154            DocumentType,
155            await self._core._update_resource(
156                "document_types",
157                id,
158                DocumentType,
159                name=name,
160                match=match,
161                matching_algorithm=matching_algorithm,
162                is_insensitive=is_insensitive,
163                owner=owner,
164                set_permissions=_set_perms,
165            ),
166        )
167
168    async def delete(self, id: int) -> None:
169        """Delete a document type.
170
171        Args:
172            id: Numeric ID of the document type to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
176        """
177        await self._core._delete_resource("document_types", id)
178
179    async def bulk_delete(self, ids: List[int]) -> None:
180        """Permanently delete multiple document types in a single request.
181
182        Args:
183            ids: List of document type IDs to delete.
184        """
185        await self._core._bulk_edit_objects("document_types", ids, "delete")
186
187    async def bulk_set_permissions(
188        self,
189        ids: List[int],
190        *,
191        set_permissions: SetPermissions | None = None,
192        owner: int | None = None,
193        merge: bool = False,
194    ) -> None:
195        """Set permissions and/or owner on multiple document types.
196
197        Args:
198            ids: List of document type IDs to modify.
199            set_permissions: Explicit view/change permission sets.
200            owner: Numeric user ID to assign as owner.
201            merge: When ``True``, new permissions are merged with existing ones.
202        """
203        params: dict[str, Any] = {"merge": merge}
204        if set_permissions is not None:
205            params["permissions"] = set_permissions.model_dump()
206        if owner is not None:
207            params["owner"] = owner
208        await self._core._bulk_edit_objects("document_types", ids, "set_permissions", **params)

Accessor for document types: client.document_types.

DocumentTypesResource(core: easypaperless.client._ClientCore)
20    def __init__(self, core: _ClientCore) -> None:
21        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.DocumentType]:
23    async def list(
24        self,
25        *,
26        ids: List[int] | None = None,
27        name_contains: str | None = None,
28        name_exact: str | None = None,
29        page: int | None = None,
30        page_size: int | None = None,
31        ordering: str | None = None,
32        descending: bool = False,
33    ) -> List[DocumentType]:
34        """Return document types defined in paperless-ngx.
35
36        Args:
37            ids: Return only document types whose ID is in this list.
38            name_contains: Case-insensitive substring filter on name.
39            name_exact: Case-insensitive exact match on name.
40            page: Return only this specific page (1-based).
41            page_size: Number of results per page.
42            ordering: Field to sort by.
43            descending: When ``True``, reverses the sort direction.
44
45        Returns:
46            List of :class:`~easypaperless.models.document_types.DocumentType` objects.
47        """
48        params: dict[str, Any] = {}
49        if ids is not None:
50            params["id__in"] = ",".join(str(i) for i in ids)
51        if name_contains is not None:
52            params["name__icontains"] = name_contains
53        if name_exact is not None:
54            params["name__iexact"] = name_exact
55        if page is not None:
56            params["page"] = page
57        if page_size is not None:
58            params["page_size"] = page_size
59        if ordering is not None:
60            params["ordering"] = f"-{ordering}" if descending else ordering
61        return cast(
62            List[DocumentType],
63            await self._core._list_resource("document_types", DocumentType, params or None),
64        )

Return document types defined in paperless-ngx.

Arguments:
  • ids: Return only document types whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.document_types.DocumentType objects.

async def get(self, id: int) -> easypaperless.DocumentType:
66    async def get(self, id: int) -> DocumentType:
67        """Fetch a single document type by its ID.
68
69        Args:
70            id: Numeric document-type ID.
71
72        Returns:
73            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
74
75        Raises:
76            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
77        """
78        return cast(
79            DocumentType, await self._core._get_resource("document_types", id, DocumentType)
80        )

Fetch a single document type by its ID.

Arguments:
  • id: Numeric document-type ID.
Returns:

The ~easypaperless.models.document_types.DocumentType with the given ID.

Raises:
async def create( self, *, name: str, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.DocumentType:
 82    async def create(
 83        self,
 84        *,
 85        name: str,
 86        match: str | None | _Unset = UNSET,
 87        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 88        is_insensitive: bool = True,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> DocumentType:
 92        """Create a new document type.
 93
 94        Args:
 95            name: Document-type name. Must be unique.
 96            match: Auto-matching pattern.
 97            matching_algorithm: Controls how ``match`` is applied.
 98            is_insensitive: When ``True``, ``match`` is case-insensitive.
 99                Defaults to ``True``, matching the paperless-ngx API default.
100            owner: Numeric user ID to assign as owner.
101            set_permissions: Explicit view/change permission sets.
102
103        Returns:
104            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
105        """
106        return cast(
107            DocumentType,
108            await self._core._create_resource(
109                "document_types",
110                DocumentType,
111                owner=owner,
112                set_permissions=set_permissions,
113                name=name,
114                match=match,
115                matching_algorithm=matching_algorithm,
116                is_insensitive=is_insensitive,
117            ),
118        )

Create a new document type.

Arguments:
  • name: Document-type name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.document_types.DocumentType.

async def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.DocumentType:
120    async def update(
121        self,
122        id: int,
123        *,
124        name: str | None | _Unset = UNSET,
125        match: str | None | _Unset = UNSET,
126        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
127        is_insensitive: bool | None | _Unset = UNSET,
128        owner: int | None | _Unset = UNSET,
129        set_permissions: SetPermissions | None | _Unset = UNSET,
130    ) -> DocumentType:
131        """Partially update a document type (PATCH semantics).
132
133        Args:
134            id: Numeric ID of the document type to update.
135            name: Document-type name.
136            match: Auto-matching pattern.
137            matching_algorithm: Controls how ``match`` is applied.
138            is_insensitive: When ``True``, ``match`` is case-insensitive.
139            owner: Numeric user ID to assign as owner.
140                Pass ``None`` to clear the owner.
141                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
142            set_permissions: Explicit view/change permission sets.
143                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
144
145        Returns:
146            The updated :class:`~easypaperless.models.document_types.DocumentType`.
147        """
148        _set_perms: dict[str, Any] | _Unset = (
149            UNSET
150            if isinstance(set_permissions, _Unset)
151            else (set_permissions or SetPermissions()).model_dump()
152        )
153        return cast(
154            DocumentType,
155            await self._core._update_resource(
156                "document_types",
157                id,
158                DocumentType,
159                name=name,
160                match=match,
161                matching_algorithm=matching_algorithm,
162                is_insensitive=is_insensitive,
163                owner=owner,
164                set_permissions=_set_perms,
165            ),
166        )

Partially update a document type (PATCH semantics).

Arguments:
  • id: Numeric ID of the document type to update.
  • name: Document-type name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.document_types.DocumentType.

async def delete(self, id: int) -> None:
168    async def delete(self, id: int) -> None:
169        """Delete a document type.
170
171        Args:
172            id: Numeric ID of the document type to delete.
173
174        Raises:
175            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
176        """
177        await self._core._delete_resource("document_types", id)

Delete a document type.

Arguments:
  • id: Numeric ID of the document type to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
179    async def bulk_delete(self, ids: List[int]) -> None:
180        """Permanently delete multiple document types in a single request.
181
182        Args:
183            ids: List of document type IDs to delete.
184        """
185        await self._core._bulk_edit_objects("document_types", ids, "delete")

Permanently delete multiple document types in a single request.

Arguments:
  • ids: List of document type IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
187    async def bulk_set_permissions(
188        self,
189        ids: List[int],
190        *,
191        set_permissions: SetPermissions | None = None,
192        owner: int | None = None,
193        merge: bool = False,
194    ) -> None:
195        """Set permissions and/or owner on multiple document types.
196
197        Args:
198            ids: List of document type IDs to modify.
199            set_permissions: Explicit view/change permission sets.
200            owner: Numeric user ID to assign as owner.
201            merge: When ``True``, new permissions are merged with existing ones.
202        """
203        params: dict[str, Any] = {"merge": merge}
204        if set_permissions is not None:
205            params["permissions"] = set_permissions.model_dump()
206        if owner is not None:
207            params["owner"] = owner
208        await self._core._bulk_edit_objects("document_types", ids, "set_permissions", **params)

Set permissions and/or owner on multiple document types.

Arguments:
  • ids: List of document type IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class DocumentsResource:
105class DocumentsResource:
106    """Accessor for documents: ``client.documents``."""
107
108    def __init__(self, core: _ClientCore) -> None:
109        self._core = core
110        self.notes = NotesResource(core)
111
112    @staticmethod
113    def _format_date_value(value: date | datetime | str) -> str:
114        if isinstance(value, datetime):
115            return value.isoformat()
116        if isinstance(value, date):
117            return value.isoformat()
118        return value
119
120    @staticmethod
121    def _is_datetime(value: date | datetime | str) -> bool:
122        if isinstance(value, datetime):
123            return True
124        if isinstance(value, str):
125            return bool(_DATETIME_STR_RE.match(value))
126        return False
127
128    async def get(self, id: int, *, include_metadata: bool = False) -> Document:
129        """Fetch a single document by its ID.
130
131        Args:
132            id: Numeric paperless-ngx document ID.
133            include_metadata: When ``True``, the extended file-level metadata
134                is fetched concurrently and attached to the document.
135                Default: ``False``.
136
137        Returns:
138            The :class:`~easypaperless.models.documents.Document` with the
139            given ID.
140
141        Raises:
142            ~easypaperless.exceptions.NotFoundError: If no document exists
143                with that ID.
144        """
145        if include_metadata:
146            doc_resp, meta_resp = await asyncio.gather(
147                self._core._session.get(f"/documents/{id}/"),
148                self._core._session.get(f"/documents/{id}/metadata/"),
149            )
150            data = doc_resp.json()
151            data["metadata"] = meta_resp.json()
152        else:
153            resp = await self._core._session.get(f"/documents/{id}/")
154            data = resp.json()
155        return Document.model_validate(data)
156
157    async def get_metadata(self, id: int) -> DocumentMetadata:
158        """Fetch the extended file-level metadata for a document.
159
160        Args:
161            id: Numeric paperless-ngx document ID.
162
163        Returns:
164            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
165
166        Raises:
167            ~easypaperless.exceptions.NotFoundError: If no document exists
168                with that ID.
169        """
170        resp = await self._core._session.get(f"/documents/{id}/metadata/")
171        return DocumentMetadata.model_validate(resp.json())
172
173    async def list(
174        self,
175        *,
176        search: str | None = None,
177        search_mode: str = "title_or_content",
178        ids: List[int] | None = None,
179        tags: List[int | str] | None = None,
180        any_tags: List[int | str] | None = None,
181        exclude_tags: List[int | str] | None = None,
182        correspondent: int | str | None | _Unset = UNSET,
183        any_correspondent: List[int | str] | None = None,
184        exclude_correspondents: List[int | str] | None = None,
185        document_type: int | str | None | _Unset = UNSET,
186        document_type_name_contains: str | None = None,
187        document_type_name_exact: str | None = None,
188        any_document_type: List[int | str] | None = None,
189        exclude_document_types: List[int | str] | None = None,
190        storage_path: int | str | None | _Unset = UNSET,
191        any_storage_paths: List[int | str] | None = None,
192        exclude_storage_paths: List[int | str] | None = None,
193        owner: int | None | _Unset = UNSET,
194        exclude_owners: List[int] | None = None,
195        custom_fields: List[int | str] | None = None,
196        any_custom_fields: List[int | str] | None = None,
197        exclude_custom_fields: List[int | str] | None = None,
198        custom_field_query: List[Any] | None = None,
199        archive_serial_number: int | None | _Unset = UNSET,
200        archive_serial_number_from: int | None = None,
201        archive_serial_number_till: int | None = None,
202        created_after: date | str | None = None,
203        created_before: date | str | None = None,
204        added_after: date | datetime | str | None = None,
205        added_from: date | datetime | str | None = None,
206        added_before: date | datetime | str | None = None,
207        added_until: date | datetime | str | None = None,
208        modified_after: date | datetime | str | None = None,
209        modified_from: date | datetime | str | None = None,
210        modified_before: date | datetime | str | None = None,
211        modified_until: date | datetime | str | None = None,
212        checksum: str | None = None,
213        page_size: int = 25,
214        page: int | None = None,
215        ordering: str | None = None,
216        descending: bool = False,
217        max_results: int | None = None,
218        on_page: Callable[[int, int | None], None] | None = None,
219    ) -> List[Document]:
220        """Return a filtered list of documents.
221
222        All tag, correspondent, document-type, storage-path, and custom-field
223        parameters accept either integer IDs or string names.
224
225        Args:
226            search: Search string.  Behaviour depends on ``search_mode``.
227            search_mode: How ``search`` is applied.  One of:
228                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
229                ``"original_filename"``.
230            ids: Return only documents whose ID is in this list.
231            tags: Documents must have **all** of these tags (AND semantics).
232            any_tags: Documents must have **at least one** of these tags.
233            exclude_tags: Documents must have **none** of these tags.
234            correspondent: Filter to documents assigned to this correspondent.
235                Pass ``None`` to return only documents with no correspondent set.
236            any_correspondent: Filter to documents assigned to any of these.
237            exclude_correspondents: Exclude documents assigned to any of these.
238            document_type: Filter to documents of exactly this type.
239                Pass ``None`` to return only documents with no document type set.
240            document_type_name_contains: Case-insensitive substring filter on document type name.
241            document_type_name_exact: Case-insensitive exact match on document type name.
242            any_document_type: Filter to documents whose type is any of these.
243            exclude_document_types: Exclude documents whose type is any of these.
244            storage_path: Filter to documents assigned to this storage path.
245                Pass ``None`` to return only documents with no storage path set.
246            any_storage_paths: Filter to documents assigned to any of these paths.
247            exclude_storage_paths: Exclude documents assigned to any of these paths.
248            owner: Filter to documents owned by this user ID.
249                Pass ``None`` to return only documents with no owner set.
250            exclude_owners: Exclude documents owned by any of these user IDs.
251            custom_fields: Documents must have **all** of these custom fields set.
252            any_custom_fields: Documents must have **at least one** of these fields.
253            exclude_custom_fields: Documents must have **none** of these fields.
254            custom_field_query: Filter documents by custom field values.
255            archive_serial_number: Filter by exact archive serial number.
256                Pass ``None`` to return only documents with no ASN set.
257            archive_serial_number_from: Filter by ASN >= this value.
258            archive_serial_number_till: Filter by ASN <= this value.
259            created_after: Only documents created after this date.
260            created_before: Only documents created before this date.
261            added_after: Only documents added after this date/time.
262            added_from: Only documents added on or after this date/time.
263            added_before: Only documents added before this date/time.
264            added_until: Only documents added on or before this date/time.
265            modified_after: Only documents modified after this date/time.
266            modified_from: Only documents modified on or after this date/time.
267            modified_before: Only documents modified before this date/time.
268            modified_until: Only documents modified on or before this date/time.
269            checksum: MD5 checksum of the original file (exact match).
270            page_size: Number of results per API page.  Default: ``25``.
271            page: Return only this specific page (1-based).
272            ordering: Field name to sort by.
273            descending: When ``True``, reverses the sort direction.
274            max_results: Stop after collecting this many documents.
275            on_page: Callback invoked after each page fetch.
276
277        Returns:
278            List of :class:`~easypaperless.models.documents.Document` objects.
279        """
280        resolver = self._core._resolver
281        params: dict[str, Any] = {"page_size": page_size}
282
283        if search is not None:
284            api_param = _SEARCH_MODE_MAP.get(search_mode, "search")
285            params[api_param] = search
286
287        if ids is not None:
288            params["id__in"] = ",".join(str(i) for i in ids)
289
290        if tags is not None:
291            resolved = await resolver.resolve_list("tags", tags)
292            params["tags__id__all"] = ",".join(str(t) for t in resolved)
293
294        if any_tags is not None:
295            resolved = await resolver.resolve_list("tags", any_tags)
296            params["tags__id__in"] = ",".join(str(t) for t in resolved)
297
298        if exclude_tags is not None:
299            resolved = await resolver.resolve_list("tags", exclude_tags)
300            params["tags__id__none"] = ",".join(str(t) for t in resolved)
301
302        if any_correspondent is not None:
303            resolved = await resolver.resolve_list("correspondents", any_correspondent)
304            params["correspondent__id__in"] = ",".join(str(c) for c in resolved)
305        elif not isinstance(correspondent, _Unset):
306            if correspondent is None:
307                params["correspondent__isnull"] = "true"
308            else:
309                resolved_id = await resolver.resolve("correspondents", correspondent)
310                params["correspondent__id__in"] = resolved_id
311
312        if exclude_correspondents is not None:
313            resolved = await resolver.resolve_list("correspondents", exclude_correspondents)
314            params["correspondent__id__none"] = ",".join(str(c) for c in resolved)
315
316        if document_type_name_contains is not None:
317            params["document_type__name__icontains"] = document_type_name_contains
318        if document_type_name_exact is not None:
319            params["document_type__name__iexact"] = document_type_name_exact
320
321        if any_document_type is not None:
322            resolved = await resolver.resolve_list("document_types", any_document_type)
323            params["document_type__id__in"] = ",".join(str(d) for d in resolved)
324        elif not isinstance(document_type, _Unset):
325            if document_type is None:
326                params["document_type__isnull"] = "true"
327            else:
328                resolved_id = await resolver.resolve("document_types", document_type)
329                params["document_type"] = resolved_id
330
331        if exclude_document_types is not None:
332            resolved = await resolver.resolve_list("document_types", exclude_document_types)
333            params["document_type__id__none"] = ",".join(str(d) for d in resolved)
334
335        if any_storage_paths is not None:
336            resolved = await resolver.resolve_list("storage_paths", any_storage_paths)
337            params["storage_path__id__in"] = ",".join(str(s) for s in resolved)
338        elif not isinstance(storage_path, _Unset):
339            if storage_path is None:
340                params["storage_path__isnull"] = "true"
341            else:
342                resolved_id = await resolver.resolve("storage_paths", storage_path)
343                params["storage_path__id__in"] = resolved_id
344
345        if exclude_storage_paths is not None:
346            resolved = await resolver.resolve_list("storage_paths", exclude_storage_paths)
347            params["storage_path__id__none"] = ",".join(str(s) for s in resolved)
348
349        if not isinstance(owner, _Unset):
350            if owner is None:
351                params["owner__isnull"] = "true"
352            else:
353                params["owner__id__in"] = owner
354
355        if exclude_owners is not None:
356            params["owner__id__none"] = ",".join(str(o) for o in exclude_owners)
357
358        if custom_fields is not None:
359            resolved = await resolver.resolve_list("custom_fields", custom_fields)
360            params["custom_fields__id__all"] = ",".join(str(f) for f in resolved)
361
362        if any_custom_fields is not None:
363            resolved = await resolver.resolve_list("custom_fields", any_custom_fields)
364            params["custom_fields__id__in"] = ",".join(str(f) for f in resolved)
365
366        if exclude_custom_fields is not None:
367            resolved = await resolver.resolve_list("custom_fields", exclude_custom_fields)
368            params["custom_fields__id__none"] = ",".join(str(f) for f in resolved)
369
370        if custom_field_query is not None:
371            params["custom_field_query"] = json.dumps(custom_field_query)
372
373        if not isinstance(archive_serial_number, _Unset):
374            if archive_serial_number is None:
375                params["archive_serial_number__isnull"] = "true"
376            else:
377                params["archive_serial_number"] = archive_serial_number
378
379        if archive_serial_number_from is not None:
380            params["archive_serial_number__gte"] = archive_serial_number_from
381
382        if archive_serial_number_till is not None:
383            params["archive_serial_number__lte"] = archive_serial_number_till
384
385        if created_after is not None:
386            params["created__date__gt"] = self._format_date_value(created_after)
387
388        if created_before is not None:
389            params["created__date__lt"] = self._format_date_value(created_before)
390
391        if added_after is not None:
392            key = "added__gt" if self._is_datetime(added_after) else "added__date__gt"
393            params[key] = self._format_date_value(added_after)
394
395        if added_from is not None:
396            key = "added__gte" if self._is_datetime(added_from) else "added__date__gte"
397            params[key] = self._format_date_value(added_from)
398
399        if added_before is not None:
400            key = "added__lt" if self._is_datetime(added_before) else "added__date__lt"
401            params[key] = self._format_date_value(added_before)
402
403        if added_until is not None:
404            key = "added__lte" if self._is_datetime(added_until) else "added__date__lte"
405            params[key] = self._format_date_value(added_until)
406
407        if modified_after is not None:
408            key = "modified__gt" if self._is_datetime(modified_after) else "modified__date__gt"
409            params[key] = self._format_date_value(modified_after)
410
411        if modified_from is not None:
412            key = "modified__gte" if self._is_datetime(modified_from) else "modified__date__gte"
413            params[key] = self._format_date_value(modified_from)
414
415        if modified_before is not None:
416            key = "modified__lt" if self._is_datetime(modified_before) else "modified__date__lt"
417            params[key] = self._format_date_value(modified_before)
418
419        if modified_until is not None:
420            key = "modified__lte" if self._is_datetime(modified_until) else "modified__date__lte"
421            params[key] = self._format_date_value(modified_until)
422
423        if checksum is not None:
424            params["checksum__iexact"] = checksum
425
426        if ordering is not None:
427            params["ordering"] = f"-{ordering}" if descending else ordering
428
429        if page is not None:
430            params["page"] = page
431            resp = await self._core._session.get("/documents/", params=params)
432            items = resp.json().get("results", [])
433            if max_results is not None:
434                items = items[:max_results]
435            return [Document.model_validate(item) for item in items]
436
437        items = await self._core._session.get_all_pages(
438            "/documents/", params, max_results=max_results, on_page=on_page
439        )
440        return [Document.model_validate(item) for item in items]
441
442    async def update(
443        self,
444        id: int,
445        *,
446        title: str | None | _Unset = UNSET,
447        content: str | None | _Unset = UNSET,
448        created: date | str | None | _Unset = UNSET,
449        correspondent: int | str | None | _Unset = UNSET,
450        document_type: int | str | None | _Unset = UNSET,
451        storage_path: int | str | None | _Unset = UNSET,
452        tags: List[int | str] | None | _Unset = UNSET,
453        archive_serial_number: int | None | _Unset = UNSET,
454        custom_fields: List[dict[str, Any]] | None | _Unset = UNSET,
455        owner: int | None | _Unset = UNSET,
456        set_permissions: SetPermissions | None | _Unset = UNSET,
457        remove_inbox_tags: bool | None | _Unset = UNSET,
458    ) -> Document:
459        """Partially update a document (PATCH semantics).
460
461        Args:
462            id: Numeric ID of the document to update.
463            title: New document title.
464            content: OCR text content of the document.
465            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
466                :class:`~datetime.date` object.
467            correspondent: Correspondent to assign, as an ID or name.
468                Pass ``None`` to clear the correspondent.
469            document_type: Document type to assign, as an ID or name.
470                Pass ``None`` to clear the document type.
471            storage_path: Storage path to assign, as an ID or name.
472                Pass ``None`` to clear the storage path.
473            tags: Full replacement list of tags (IDs or names).
474            archive_serial_number: Archive serial number to assign.
475                Pass ``None`` to clear the archive serial number.
476            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
477            owner: Numeric user ID to assign as document owner.
478                Pass ``None`` to clear the owner.
479            set_permissions: Explicit view/change permission sets.
480            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
481
482        Returns:
483            The updated :class:`~easypaperless.models.documents.Document`.
484        """
485        logger.debug("Updating document id=%d", id)
486        resolver = self._core._resolver
487        payload: dict[str, Any] = {}
488
489        if not isinstance(title, _Unset):
490            payload["title"] = title
491        if not isinstance(content, _Unset):
492            payload["content"] = content
493        if not isinstance(created, _Unset):
494            payload["created"] = self._format_date_value(created) if created is not None else None
495        if not isinstance(correspondent, _Unset):
496            payload["correspondent"] = (
497                None
498                if correspondent is None
499                else await resolver.resolve("correspondents", correspondent)
500            )
501        if not isinstance(document_type, _Unset):
502            payload["document_type"] = (
503                None
504                if document_type is None
505                else await resolver.resolve("document_types", document_type)
506            )
507        if not isinstance(storage_path, _Unset):
508            payload["storage_path"] = (
509                None
510                if storage_path is None
511                else await resolver.resolve("storage_paths", storage_path)
512            )
513        if not isinstance(tags, _Unset):
514            payload["tags"] = await resolver.resolve_list("tags", tags or [])
515        if not isinstance(archive_serial_number, _Unset):
516            payload["archive_serial_number"] = archive_serial_number
517        if not isinstance(custom_fields, _Unset):
518            payload["custom_fields"] = custom_fields
519        if not isinstance(owner, _Unset):
520            payload["owner"] = owner
521        if not isinstance(set_permissions, _Unset):
522            payload["set_permissions"] = (set_permissions or SetPermissions()).model_dump()
523        if not isinstance(remove_inbox_tags, _Unset):
524            payload["remove_inbox_tags"] = remove_inbox_tags
525
526        resp = await self._core._session.patch(f"/documents/{id}/", json=payload)
527        return Document.model_validate(resp.json())
528
529    async def delete(self, id: int) -> None:
530        """Permanently delete a document.
531
532        Args:
533            id: Numeric ID of the document to delete.
534
535        Raises:
536            ~easypaperless.exceptions.NotFoundError: If no document exists
537                with that ID.
538        """
539        logger.debug("Deleting document id=%d", id)
540        await self._core._session.delete(f"/documents/{id}/")
541
542    async def download(self, id: int, *, original: bool = False) -> bytes:
543        """Download the binary content of a document.
544
545        Args:
546            id: Numeric ID of the document to download.
547            original: If ``False`` *(default)*, returns the archived PDF.
548                If ``True``, returns the original uploaded file.
549
550        Returns:
551            Raw file bytes.
552        """
553        endpoint = "download" if original else "archive"
554        resp = await self._core._session.get_download(f"/documents/{id}/{endpoint}/")
555        content_type = resp.headers.get("content-type", "")
556        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
557            raise ServerError(
558                f"Download returned an HTML page (content-type: {content_type!r}). "
559                "The server redirected to a login page even after re-attaching auth.",
560                status_code=None,
561            )
562        return resp.content
563
564    async def upload(
565        self,
566        file: str | Path,
567        *,
568        title: str | None = None,
569        created: date | str | None = None,
570        correspondent: int | str | None | _Unset = UNSET,
571        document_type: int | str | None | _Unset = UNSET,
572        storage_path: int | str | None | _Unset = UNSET,
573        tags: List[int | str] | None = None,
574        archive_serial_number: int | None | _Unset = UNSET,
575        custom_fields: List[dict[str, Any]] | None = None,
576        wait: bool = False,
577        poll_interval: float | None = None,
578        poll_timeout: float | None = None,
579    ) -> str | Document:
580        """Upload a document to paperless-ngx.
581
582        Args:
583            file: Path to the file to upload.
584            title: Title to assign to the document.
585            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
586                :class:`~datetime.date` object.
587            correspondent: Correspondent to assign, as an ID or name.
588            document_type: Document type to assign, as an ID or name.
589            storage_path: Storage path to assign, as an ID or name.
590            tags: Tags to assign, as IDs or names.
591            archive_serial_number: Archive serial number to assign.
592            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
593            wait: If ``False`` *(default)*, returns immediately with the task ID.
594                If ``True``, polls until processing completes.
595            poll_interval: Override the client-level ``poll_interval`` (in seconds).
596            poll_timeout: Override the client-level ``poll_timeout`` (in seconds).
597
598        Returns:
599            The Celery task ID string when ``wait=False``, or the fully
600            processed :class:`~easypaperless.models.documents.Document`
601            when ``wait=True``.
602
603        Raises:
604            ~easypaperless.exceptions.UploadError: If processing fails.
605            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
606        """
607        resolver = self._core._resolver
608        file_path = Path(file)
609        file_bytes = file_path.read_bytes()
610        logger.info("Uploading %r (%d bytes)", file_path.name, len(file_bytes))
611
612        data: dict[str, Any] = {}
613        if title is not None:
614            data["title"] = title
615        if created is not None:
616            data["created"] = self._format_date_value(created)
617        if not isinstance(correspondent, _Unset) and correspondent is not None:
618            data["correspondent"] = await resolver.resolve("correspondents", correspondent)
619        if not isinstance(document_type, _Unset) and document_type is not None:
620            data["document_type"] = await resolver.resolve("document_types", document_type)
621        if not isinstance(storage_path, _Unset) and storage_path is not None:
622            data["storage_path"] = await resolver.resolve("storage_paths", storage_path)
623        if tags is not None:
624            resolved = await resolver.resolve_list("tags", tags)
625            data["tags"] = resolved
626        if not isinstance(archive_serial_number, _Unset) and archive_serial_number is not None:
627            data["archive_serial_number"] = archive_serial_number
628        if custom_fields is not None:
629            data["custom_fields"] = json.dumps(custom_fields)
630
631        files = {"document": (file_path.name, file_bytes)}
632        resp = await self._core._session.post("/documents/post_document/", data=data, files=files)
633        task_id: str = resp.text.strip('"')
634        logger.debug("Upload accepted, task_id=%r", task_id)
635
636        if not wait:
637            return task_id
638
639        interval = poll_interval if poll_interval is not None else self._core._poll_interval
640        timeout = poll_timeout if poll_timeout is not None else self._core._poll_timeout
641        return await self._poll_task(task_id, poll_interval=interval, poll_timeout=timeout)
642
643    async def _poll_task(
644        self, task_id: str, *, poll_interval: float, poll_timeout: float
645    ) -> Document:
646        start = time.monotonic()
647        deadline = start + poll_timeout
648        while time.monotonic() < deadline:
649            resp = await self._core._session.get("/tasks/", params={"task_id": task_id})
650            tasks = resp.json()
651            if not tasks:
652                await asyncio.sleep(poll_interval)
653                continue
654
655            task = Task.model_validate(tasks[0])
656            elapsed = time.monotonic() - start
657            logger.debug(
658                "Polling task %r (status=%s, elapsed=%.1fs)",
659                task_id,
660                task.status.value if task.status is not None else "unknown",
661                elapsed,
662            )
663            if task.status == TaskStatus.SUCCESS:
664                if task.related_document is None:
665                    raise UploadError(f"Task {task_id!r} succeeded but returned no document ID")
666                doc_id = int(task.related_document)
667                logger.info("Task %r succeeded, document_id=%d", task_id, doc_id)
668                return await self.get(doc_id)
669            elif task.status == TaskStatus.FAILURE:
670                logger.warning("Task %r failed: %s", task_id, task.result)
671                raise UploadError(f"Document processing failed: {task.result}")
672            elif task.status == TaskStatus.REVOKED:
673                logger.warning("Task %r was revoked", task_id)
674                raise UploadError(f"Task {task_id!r} was revoked")
675            await asyncio.sleep(poll_interval)
676
677        elapsed = time.monotonic() - start
678        logger.warning("Task %r timed out after %.1fs", task_id, elapsed)
679        raise TaskTimeoutError(f"Task {task_id!r} did not complete within {poll_timeout}s")
680
681    # -------------------------------------------------------------------------
682    # Document bulk operations
683    # -------------------------------------------------------------------------
684
685    async def _bulk_edit(self, document_ids: List[int], method: str, **parameters: Any) -> None:
686        """Execute a bulk-edit operation on a list of documents.
687
688        Args:
689            document_ids: List of document IDs to operate on.
690            method: Bulk-edit method name (e.g. ``"add_tag"``, ``"delete"``).
691            **parameters: Additional keyword arguments forwarded to the API.
692        """
693        payload = {"documents": document_ids, "method": method, "parameters": parameters}
694        await self._core._session.post("/documents/bulk_edit/", json=payload, timeout=120.0)
695
696    async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
697        """Add a tag to multiple documents in a single request.
698
699        Args:
700            document_ids: List of document IDs to tag.
701            tag: Tag to add, as an ID or name.
702        """
703        tag_id = await self._core._resolver.resolve("tags", tag)
704        await self._bulk_edit(document_ids, "add_tag", tag=tag_id)
705
706    async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
707        """Remove a tag from multiple documents in a single request.
708
709        Args:
710            document_ids: List of document IDs to un-tag.
711            tag: Tag to remove, as an ID or name.
712        """
713        tag_id = await self._core._resolver.resolve("tags", tag)
714        await self._bulk_edit(document_ids, "remove_tag", tag=tag_id)
715
716    async def bulk_modify_tags(
717        self,
718        document_ids: List[int],
719        *,
720        add_tags: List[int | str] | None = None,
721        remove_tags: List[int | str] | None = None,
722    ) -> None:
723        """Add and/or remove tags on multiple documents atomically.
724
725        Args:
726            document_ids: List of document IDs to modify.
727            add_tags: Tags to add, as IDs or names.
728            remove_tags: Tags to remove, as IDs or names.
729        """
730        resolver = self._core._resolver
731        add_ids = await resolver.resolve_list("tags", add_tags or [])
732        remove_ids = await resolver.resolve_list("tags", remove_tags or [])
733        await self._bulk_edit(document_ids, "modify_tags", add_tags=add_ids, remove_tags=remove_ids)
734
735    async def bulk_delete(self, document_ids: List[int]) -> None:
736        """Permanently delete multiple documents in a single request.
737
738        Args:
739            document_ids: List of document IDs to delete.
740        """
741        await self._bulk_edit(document_ids, "delete")
742
743    async def bulk_set_correspondent(
744        self, document_ids: List[int], correspondent: int | str | None
745    ) -> None:
746        """Assign a correspondent to multiple documents in a single request.
747
748        Args:
749            document_ids: List of document IDs to modify.
750            correspondent: Correspondent to assign, as an ID or name.
751                Pass ``None`` to clear.
752        """
753        cor_id: int | None = None
754        if correspondent is not None:
755            cor_id = await self._core._resolver.resolve("correspondents", correspondent)
756        await self._bulk_edit(document_ids, "set_correspondent", correspondent=cor_id)
757
758    async def bulk_set_document_type(
759        self, document_ids: List[int], document_type: int | str | None
760    ) -> None:
761        """Assign a document type to multiple documents in a single request.
762
763        Args:
764            document_ids: List of document IDs to modify.
765            document_type: Document type to assign, as an ID or name.
766                Pass ``None`` to clear.
767        """
768        dt_id: int | None = None
769        if document_type is not None:
770            dt_id = await self._core._resolver.resolve("document_types", document_type)
771        await self._bulk_edit(document_ids, "set_document_type", document_type=dt_id)
772
773    async def bulk_set_storage_path(
774        self, document_ids: List[int], storage_path: int | str | None
775    ) -> None:
776        """Assign a storage path to multiple documents in a single request.
777
778        Args:
779            document_ids: List of document IDs to modify.
780            storage_path: Storage path to assign, as an ID or name.
781                Pass ``None`` to clear.
782        """
783        sp_id: int | None = None
784        if storage_path is not None:
785            sp_id = await self._core._resolver.resolve("storage_paths", storage_path)
786        await self._bulk_edit(document_ids, "set_storage_path", storage_path=sp_id)
787
788    async def bulk_modify_custom_fields(
789        self,
790        document_ids: List[int],
791        *,
792        add_fields: List[dict[str, Any]] | None = None,
793        remove_fields: List[int] | None = None,
794    ) -> None:
795        """Add and/or remove custom field values on multiple documents.
796
797        Args:
798            document_ids: List of document IDs to modify.
799            add_fields: Custom-field value dicts to add.
800            remove_fields: Custom-field IDs whose values should be removed.
801        """
802        await self._bulk_edit(
803            document_ids,
804            "modify_custom_fields",
805            add_custom_fields=add_fields or [],
806            remove_custom_fields=remove_fields or [],
807        )
808
809    async def bulk_set_permissions(
810        self,
811        document_ids: List[int],
812        *,
813        set_permissions: SetPermissions | None = None,
814        owner: int | None = None,
815        merge: bool = False,
816    ) -> None:
817        """Set permissions and/or owner on multiple documents.
818
819        Args:
820            document_ids: List of document IDs to modify.
821            set_permissions: Explicit view/change permission sets.
822            owner: Numeric user ID to assign as document owner.
823            merge: When ``True``, new permissions are merged with existing ones.
824        """
825        params: dict[str, Any] = {"merge": merge}
826        if set_permissions is not None:
827            params["set_permissions"] = set_permissions.model_dump()
828        if owner is not None:
829            params["owner"] = owner
830        await self._bulk_edit(document_ids, "set_permissions", **params)

Accessor for documents: client.documents.

DocumentsResource(core: easypaperless.client._ClientCore)
108    def __init__(self, core: _ClientCore) -> None:
109        self._core = core
110        self.notes = NotesResource(core)
notes
async def get( self, id: int, *, include_metadata: bool = False) -> easypaperless.Document:
128    async def get(self, id: int, *, include_metadata: bool = False) -> Document:
129        """Fetch a single document by its ID.
130
131        Args:
132            id: Numeric paperless-ngx document ID.
133            include_metadata: When ``True``, the extended file-level metadata
134                is fetched concurrently and attached to the document.
135                Default: ``False``.
136
137        Returns:
138            The :class:`~easypaperless.models.documents.Document` with the
139            given ID.
140
141        Raises:
142            ~easypaperless.exceptions.NotFoundError: If no document exists
143                with that ID.
144        """
145        if include_metadata:
146            doc_resp, meta_resp = await asyncio.gather(
147                self._core._session.get(f"/documents/{id}/"),
148                self._core._session.get(f"/documents/{id}/metadata/"),
149            )
150            data = doc_resp.json()
151            data["metadata"] = meta_resp.json()
152        else:
153            resp = await self._core._session.get(f"/documents/{id}/")
154            data = resp.json()
155        return Document.model_validate(data)

Fetch a single document by its ID.

Arguments:
  • id: Numeric paperless-ngx document ID.
  • include_metadata: When True, the extended file-level metadata is fetched concurrently and attached to the document. Default: False.
Returns:

The ~easypaperless.models.documents.Document with the given ID.

Raises:
async def get_metadata(self, id: int) -> easypaperless.DocumentMetadata:
157    async def get_metadata(self, id: int) -> DocumentMetadata:
158        """Fetch the extended file-level metadata for a document.
159
160        Args:
161            id: Numeric paperless-ngx document ID.
162
163        Returns:
164            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
165
166        Raises:
167            ~easypaperless.exceptions.NotFoundError: If no document exists
168                with that ID.
169        """
170        resp = await self._core._session.get(f"/documents/{id}/metadata/")
171        return DocumentMetadata.model_validate(resp.json())

Fetch the extended file-level metadata for a document.

Arguments:
  • id: Numeric paperless-ngx document ID.
Returns:

A ~easypaperless.models.documents.DocumentMetadata instance.

Raises:
async def list( self, *, search: str | None = None, search_mode: str = 'title_or_content', ids: Optional[List[int]] = None, tags: Optional[List[Union[str, int]]] = None, any_tags: Optional[List[Union[str, int]]] = None, exclude_tags: Optional[List[Union[str, int]]] = None, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, any_correspondent: Optional[List[Union[str, int]]] = None, exclude_correspondents: Optional[List[Union[str, int]]] = None, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type_name_contains: str | None = None, document_type_name_exact: str | None = None, any_document_type: Optional[List[Union[str, int]]] = None, exclude_document_types: Optional[List[Union[str, int]]] = None, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, any_storage_paths: Optional[List[Union[str, int]]] = None, exclude_storage_paths: Optional[List[Union[str, int]]] = None, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, exclude_owners: Optional[List[int]] = None, custom_fields: Optional[List[Union[str, int]]] = None, any_custom_fields: Optional[List[Union[str, int]]] = None, exclude_custom_fields: Optional[List[Union[str, int]]] = None, custom_field_query: Optional[List[Any]] = None, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, archive_serial_number_from: int | None = None, archive_serial_number_till: int | None = None, created_after: datetime.date | str | None = None, created_before: datetime.date | str | None = None, added_after: datetime.date | datetime.datetime | str | None = None, added_from: datetime.date | datetime.datetime | str | None = None, added_before: datetime.date | datetime.datetime | str | None = None, added_until: datetime.date | datetime.datetime | str | None = None, modified_after: datetime.date | datetime.datetime | str | None = None, modified_from: datetime.date | datetime.datetime | str | None = None, modified_before: datetime.date | datetime.datetime | str | None = None, modified_until: datetime.date | datetime.datetime | str | None = None, checksum: str | None = None, page_size: int = 25, page: int | None = None, ordering: str | None = None, descending: bool = False, max_results: int | None = None, on_page: Callable[[int, int | None], None] | None = None) -> List[easypaperless.Document]:
173    async def list(
174        self,
175        *,
176        search: str | None = None,
177        search_mode: str = "title_or_content",
178        ids: List[int] | None = None,
179        tags: List[int | str] | None = None,
180        any_tags: List[int | str] | None = None,
181        exclude_tags: List[int | str] | None = None,
182        correspondent: int | str | None | _Unset = UNSET,
183        any_correspondent: List[int | str] | None = None,
184        exclude_correspondents: List[int | str] | None = None,
185        document_type: int | str | None | _Unset = UNSET,
186        document_type_name_contains: str | None = None,
187        document_type_name_exact: str | None = None,
188        any_document_type: List[int | str] | None = None,
189        exclude_document_types: List[int | str] | None = None,
190        storage_path: int | str | None | _Unset = UNSET,
191        any_storage_paths: List[int | str] | None = None,
192        exclude_storage_paths: List[int | str] | None = None,
193        owner: int | None | _Unset = UNSET,
194        exclude_owners: List[int] | None = None,
195        custom_fields: List[int | str] | None = None,
196        any_custom_fields: List[int | str] | None = None,
197        exclude_custom_fields: List[int | str] | None = None,
198        custom_field_query: List[Any] | None = None,
199        archive_serial_number: int | None | _Unset = UNSET,
200        archive_serial_number_from: int | None = None,
201        archive_serial_number_till: int | None = None,
202        created_after: date | str | None = None,
203        created_before: date | str | None = None,
204        added_after: date | datetime | str | None = None,
205        added_from: date | datetime | str | None = None,
206        added_before: date | datetime | str | None = None,
207        added_until: date | datetime | str | None = None,
208        modified_after: date | datetime | str | None = None,
209        modified_from: date | datetime | str | None = None,
210        modified_before: date | datetime | str | None = None,
211        modified_until: date | datetime | str | None = None,
212        checksum: str | None = None,
213        page_size: int = 25,
214        page: int | None = None,
215        ordering: str | None = None,
216        descending: bool = False,
217        max_results: int | None = None,
218        on_page: Callable[[int, int | None], None] | None = None,
219    ) -> List[Document]:
220        """Return a filtered list of documents.
221
222        All tag, correspondent, document-type, storage-path, and custom-field
223        parameters accept either integer IDs or string names.
224
225        Args:
226            search: Search string.  Behaviour depends on ``search_mode``.
227            search_mode: How ``search`` is applied.  One of:
228                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
229                ``"original_filename"``.
230            ids: Return only documents whose ID is in this list.
231            tags: Documents must have **all** of these tags (AND semantics).
232            any_tags: Documents must have **at least one** of these tags.
233            exclude_tags: Documents must have **none** of these tags.
234            correspondent: Filter to documents assigned to this correspondent.
235                Pass ``None`` to return only documents with no correspondent set.
236            any_correspondent: Filter to documents assigned to any of these.
237            exclude_correspondents: Exclude documents assigned to any of these.
238            document_type: Filter to documents of exactly this type.
239                Pass ``None`` to return only documents with no document type set.
240            document_type_name_contains: Case-insensitive substring filter on document type name.
241            document_type_name_exact: Case-insensitive exact match on document type name.
242            any_document_type: Filter to documents whose type is any of these.
243            exclude_document_types: Exclude documents whose type is any of these.
244            storage_path: Filter to documents assigned to this storage path.
245                Pass ``None`` to return only documents with no storage path set.
246            any_storage_paths: Filter to documents assigned to any of these paths.
247            exclude_storage_paths: Exclude documents assigned to any of these paths.
248            owner: Filter to documents owned by this user ID.
249                Pass ``None`` to return only documents with no owner set.
250            exclude_owners: Exclude documents owned by any of these user IDs.
251            custom_fields: Documents must have **all** of these custom fields set.
252            any_custom_fields: Documents must have **at least one** of these fields.
253            exclude_custom_fields: Documents must have **none** of these fields.
254            custom_field_query: Filter documents by custom field values.
255            archive_serial_number: Filter by exact archive serial number.
256                Pass ``None`` to return only documents with no ASN set.
257            archive_serial_number_from: Filter by ASN >= this value.
258            archive_serial_number_till: Filter by ASN <= this value.
259            created_after: Only documents created after this date.
260            created_before: Only documents created before this date.
261            added_after: Only documents added after this date/time.
262            added_from: Only documents added on or after this date/time.
263            added_before: Only documents added before this date/time.
264            added_until: Only documents added on or before this date/time.
265            modified_after: Only documents modified after this date/time.
266            modified_from: Only documents modified on or after this date/time.
267            modified_before: Only documents modified before this date/time.
268            modified_until: Only documents modified on or before this date/time.
269            checksum: MD5 checksum of the original file (exact match).
270            page_size: Number of results per API page.  Default: ``25``.
271            page: Return only this specific page (1-based).
272            ordering: Field name to sort by.
273            descending: When ``True``, reverses the sort direction.
274            max_results: Stop after collecting this many documents.
275            on_page: Callback invoked after each page fetch.
276
277        Returns:
278            List of :class:`~easypaperless.models.documents.Document` objects.
279        """
280        resolver = self._core._resolver
281        params: dict[str, Any] = {"page_size": page_size}
282
283        if search is not None:
284            api_param = _SEARCH_MODE_MAP.get(search_mode, "search")
285            params[api_param] = search
286
287        if ids is not None:
288            params["id__in"] = ",".join(str(i) for i in ids)
289
290        if tags is not None:
291            resolved = await resolver.resolve_list("tags", tags)
292            params["tags__id__all"] = ",".join(str(t) for t in resolved)
293
294        if any_tags is not None:
295            resolved = await resolver.resolve_list("tags", any_tags)
296            params["tags__id__in"] = ",".join(str(t) for t in resolved)
297
298        if exclude_tags is not None:
299            resolved = await resolver.resolve_list("tags", exclude_tags)
300            params["tags__id__none"] = ",".join(str(t) for t in resolved)
301
302        if any_correspondent is not None:
303            resolved = await resolver.resolve_list("correspondents", any_correspondent)
304            params["correspondent__id__in"] = ",".join(str(c) for c in resolved)
305        elif not isinstance(correspondent, _Unset):
306            if correspondent is None:
307                params["correspondent__isnull"] = "true"
308            else:
309                resolved_id = await resolver.resolve("correspondents", correspondent)
310                params["correspondent__id__in"] = resolved_id
311
312        if exclude_correspondents is not None:
313            resolved = await resolver.resolve_list("correspondents", exclude_correspondents)
314            params["correspondent__id__none"] = ",".join(str(c) for c in resolved)
315
316        if document_type_name_contains is not None:
317            params["document_type__name__icontains"] = document_type_name_contains
318        if document_type_name_exact is not None:
319            params["document_type__name__iexact"] = document_type_name_exact
320
321        if any_document_type is not None:
322            resolved = await resolver.resolve_list("document_types", any_document_type)
323            params["document_type__id__in"] = ",".join(str(d) for d in resolved)
324        elif not isinstance(document_type, _Unset):
325            if document_type is None:
326                params["document_type__isnull"] = "true"
327            else:
328                resolved_id = await resolver.resolve("document_types", document_type)
329                params["document_type"] = resolved_id
330
331        if exclude_document_types is not None:
332            resolved = await resolver.resolve_list("document_types", exclude_document_types)
333            params["document_type__id__none"] = ",".join(str(d) for d in resolved)
334
335        if any_storage_paths is not None:
336            resolved = await resolver.resolve_list("storage_paths", any_storage_paths)
337            params["storage_path__id__in"] = ",".join(str(s) for s in resolved)
338        elif not isinstance(storage_path, _Unset):
339            if storage_path is None:
340                params["storage_path__isnull"] = "true"
341            else:
342                resolved_id = await resolver.resolve("storage_paths", storage_path)
343                params["storage_path__id__in"] = resolved_id
344
345        if exclude_storage_paths is not None:
346            resolved = await resolver.resolve_list("storage_paths", exclude_storage_paths)
347            params["storage_path__id__none"] = ",".join(str(s) for s in resolved)
348
349        if not isinstance(owner, _Unset):
350            if owner is None:
351                params["owner__isnull"] = "true"
352            else:
353                params["owner__id__in"] = owner
354
355        if exclude_owners is not None:
356            params["owner__id__none"] = ",".join(str(o) for o in exclude_owners)
357
358        if custom_fields is not None:
359            resolved = await resolver.resolve_list("custom_fields", custom_fields)
360            params["custom_fields__id__all"] = ",".join(str(f) for f in resolved)
361
362        if any_custom_fields is not None:
363            resolved = await resolver.resolve_list("custom_fields", any_custom_fields)
364            params["custom_fields__id__in"] = ",".join(str(f) for f in resolved)
365
366        if exclude_custom_fields is not None:
367            resolved = await resolver.resolve_list("custom_fields", exclude_custom_fields)
368            params["custom_fields__id__none"] = ",".join(str(f) for f in resolved)
369
370        if custom_field_query is not None:
371            params["custom_field_query"] = json.dumps(custom_field_query)
372
373        if not isinstance(archive_serial_number, _Unset):
374            if archive_serial_number is None:
375                params["archive_serial_number__isnull"] = "true"
376            else:
377                params["archive_serial_number"] = archive_serial_number
378
379        if archive_serial_number_from is not None:
380            params["archive_serial_number__gte"] = archive_serial_number_from
381
382        if archive_serial_number_till is not None:
383            params["archive_serial_number__lte"] = archive_serial_number_till
384
385        if created_after is not None:
386            params["created__date__gt"] = self._format_date_value(created_after)
387
388        if created_before is not None:
389            params["created__date__lt"] = self._format_date_value(created_before)
390
391        if added_after is not None:
392            key = "added__gt" if self._is_datetime(added_after) else "added__date__gt"
393            params[key] = self._format_date_value(added_after)
394
395        if added_from is not None:
396            key = "added__gte" if self._is_datetime(added_from) else "added__date__gte"
397            params[key] = self._format_date_value(added_from)
398
399        if added_before is not None:
400            key = "added__lt" if self._is_datetime(added_before) else "added__date__lt"
401            params[key] = self._format_date_value(added_before)
402
403        if added_until is not None:
404            key = "added__lte" if self._is_datetime(added_until) else "added__date__lte"
405            params[key] = self._format_date_value(added_until)
406
407        if modified_after is not None:
408            key = "modified__gt" if self._is_datetime(modified_after) else "modified__date__gt"
409            params[key] = self._format_date_value(modified_after)
410
411        if modified_from is not None:
412            key = "modified__gte" if self._is_datetime(modified_from) else "modified__date__gte"
413            params[key] = self._format_date_value(modified_from)
414
415        if modified_before is not None:
416            key = "modified__lt" if self._is_datetime(modified_before) else "modified__date__lt"
417            params[key] = self._format_date_value(modified_before)
418
419        if modified_until is not None:
420            key = "modified__lte" if self._is_datetime(modified_until) else "modified__date__lte"
421            params[key] = self._format_date_value(modified_until)
422
423        if checksum is not None:
424            params["checksum__iexact"] = checksum
425
426        if ordering is not None:
427            params["ordering"] = f"-{ordering}" if descending else ordering
428
429        if page is not None:
430            params["page"] = page
431            resp = await self._core._session.get("/documents/", params=params)
432            items = resp.json().get("results", [])
433            if max_results is not None:
434                items = items[:max_results]
435            return [Document.model_validate(item) for item in items]
436
437        items = await self._core._session.get_all_pages(
438            "/documents/", params, max_results=max_results, on_page=on_page
439        )
440        return [Document.model_validate(item) for item in items]

Return a filtered list of documents.

All tag, correspondent, document-type, storage-path, and custom-field parameters accept either integer IDs or string names.

Arguments:
  • search: Search string. Behaviour depends on search_mode.
  • search_mode: How search is applied. One of: "title_or_content" (default), "title", "query", "original_filename".
  • ids: Return only documents whose ID is in this list.
  • tags: Documents must have all of these tags (AND semantics).
  • any_tags: Documents must have at least one of these tags.
  • exclude_tags: Documents must have none of these tags.
  • correspondent: Filter to documents assigned to this correspondent. Pass None to return only documents with no correspondent set.
  • any_correspondent: Filter to documents assigned to any of these.
  • exclude_correspondents: Exclude documents assigned to any of these.
  • document_type: Filter to documents of exactly this type. Pass None to return only documents with no document type set.
  • document_type_name_contains: Case-insensitive substring filter on document type name.
  • document_type_name_exact: Case-insensitive exact match on document type name.
  • any_document_type: Filter to documents whose type is any of these.
  • exclude_document_types: Exclude documents whose type is any of these.
  • storage_path: Filter to documents assigned to this storage path. Pass None to return only documents with no storage path set.
  • any_storage_paths: Filter to documents assigned to any of these paths.
  • exclude_storage_paths: Exclude documents assigned to any of these paths.
  • owner: Filter to documents owned by this user ID. Pass None to return only documents with no owner set.
  • exclude_owners: Exclude documents owned by any of these user IDs.
  • custom_fields: Documents must have all of these custom fields set.
  • any_custom_fields: Documents must have at least one of these fields.
  • exclude_custom_fields: Documents must have none of these fields.
  • custom_field_query: Filter documents by custom field values.
  • archive_serial_number: Filter by exact archive serial number. Pass None to return only documents with no ASN set.
  • archive_serial_number_from: Filter by ASN >= this value.
  • archive_serial_number_till: Filter by ASN <= this value.
  • created_after: Only documents created after this date.
  • created_before: Only documents created before this date.
  • added_after: Only documents added after this date/time.
  • added_from: Only documents added on or after this date/time.
  • added_before: Only documents added before this date/time.
  • added_until: Only documents added on or before this date/time.
  • modified_after: Only documents modified after this date/time.
  • modified_from: Only documents modified on or after this date/time.
  • modified_before: Only documents modified before this date/time.
  • modified_until: Only documents modified on or before this date/time.
  • checksum: MD5 checksum of the original file (exact match).
  • page_size: Number of results per API page. Default: 25.
  • page: Return only this specific page (1-based).
  • ordering: Field name to sort by.
  • descending: When True, reverses the sort direction.
  • max_results: Stop after collecting this many documents.
  • on_page: Callback invoked after each page fetch.
Returns:

List of ~easypaperless.models.documents.Document objects.

async def update( self, id: int, *, title: str | None | easypaperless._internal.sentinel._Unset = UNSET, content: str | None | easypaperless._internal.sentinel._Unset = UNSET, created: datetime.date | str | None | easypaperless._internal.sentinel._Unset = UNSET, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, tags: Union[List[Union[str, int]], NoneType, easypaperless._internal.sentinel._Unset] = UNSET, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, custom_fields: Union[List[dict[str, Any]], NoneType, easypaperless._internal.sentinel._Unset] = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET, remove_inbox_tags: bool | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Document:
442    async def update(
443        self,
444        id: int,
445        *,
446        title: str | None | _Unset = UNSET,
447        content: str | None | _Unset = UNSET,
448        created: date | str | None | _Unset = UNSET,
449        correspondent: int | str | None | _Unset = UNSET,
450        document_type: int | str | None | _Unset = UNSET,
451        storage_path: int | str | None | _Unset = UNSET,
452        tags: List[int | str] | None | _Unset = UNSET,
453        archive_serial_number: int | None | _Unset = UNSET,
454        custom_fields: List[dict[str, Any]] | None | _Unset = UNSET,
455        owner: int | None | _Unset = UNSET,
456        set_permissions: SetPermissions | None | _Unset = UNSET,
457        remove_inbox_tags: bool | None | _Unset = UNSET,
458    ) -> Document:
459        """Partially update a document (PATCH semantics).
460
461        Args:
462            id: Numeric ID of the document to update.
463            title: New document title.
464            content: OCR text content of the document.
465            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
466                :class:`~datetime.date` object.
467            correspondent: Correspondent to assign, as an ID or name.
468                Pass ``None`` to clear the correspondent.
469            document_type: Document type to assign, as an ID or name.
470                Pass ``None`` to clear the document type.
471            storage_path: Storage path to assign, as an ID or name.
472                Pass ``None`` to clear the storage path.
473            tags: Full replacement list of tags (IDs or names).
474            archive_serial_number: Archive serial number to assign.
475                Pass ``None`` to clear the archive serial number.
476            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
477            owner: Numeric user ID to assign as document owner.
478                Pass ``None`` to clear the owner.
479            set_permissions: Explicit view/change permission sets.
480            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
481
482        Returns:
483            The updated :class:`~easypaperless.models.documents.Document`.
484        """
485        logger.debug("Updating document id=%d", id)
486        resolver = self._core._resolver
487        payload: dict[str, Any] = {}
488
489        if not isinstance(title, _Unset):
490            payload["title"] = title
491        if not isinstance(content, _Unset):
492            payload["content"] = content
493        if not isinstance(created, _Unset):
494            payload["created"] = self._format_date_value(created) if created is not None else None
495        if not isinstance(correspondent, _Unset):
496            payload["correspondent"] = (
497                None
498                if correspondent is None
499                else await resolver.resolve("correspondents", correspondent)
500            )
501        if not isinstance(document_type, _Unset):
502            payload["document_type"] = (
503                None
504                if document_type is None
505                else await resolver.resolve("document_types", document_type)
506            )
507        if not isinstance(storage_path, _Unset):
508            payload["storage_path"] = (
509                None
510                if storage_path is None
511                else await resolver.resolve("storage_paths", storage_path)
512            )
513        if not isinstance(tags, _Unset):
514            payload["tags"] = await resolver.resolve_list("tags", tags or [])
515        if not isinstance(archive_serial_number, _Unset):
516            payload["archive_serial_number"] = archive_serial_number
517        if not isinstance(custom_fields, _Unset):
518            payload["custom_fields"] = custom_fields
519        if not isinstance(owner, _Unset):
520            payload["owner"] = owner
521        if not isinstance(set_permissions, _Unset):
522            payload["set_permissions"] = (set_permissions or SetPermissions()).model_dump()
523        if not isinstance(remove_inbox_tags, _Unset):
524            payload["remove_inbox_tags"] = remove_inbox_tags
525
526        resp = await self._core._session.patch(f"/documents/{id}/", json=payload)
527        return Document.model_validate(resp.json())

Partially update a document (PATCH semantics).

Arguments:
  • id: Numeric ID of the document to update.
  • title: New document title.
  • content: OCR text content of the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear the correspondent.
  • document_type: Document type to assign, as an ID or name. Pass None to clear the document type.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear the storage path.
  • tags: Full replacement list of tags (IDs or names).
  • archive_serial_number: Archive serial number to assign. Pass None to clear the archive serial number.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner.
  • set_permissions: Explicit view/change permission sets.
  • remove_inbox_tags: When True, removes all inbox tags from the document.
Returns:

The updated ~easypaperless.models.documents.Document.

async def delete(self, id: int) -> None:
529    async def delete(self, id: int) -> None:
530        """Permanently delete a document.
531
532        Args:
533            id: Numeric ID of the document to delete.
534
535        Raises:
536            ~easypaperless.exceptions.NotFoundError: If no document exists
537                with that ID.
538        """
539        logger.debug("Deleting document id=%d", id)
540        await self._core._session.delete(f"/documents/{id}/")

Permanently delete a document.

Arguments:
  • id: Numeric ID of the document to delete.
Raises:
async def download(self, id: int, *, original: bool = False) -> bytes:
542    async def download(self, id: int, *, original: bool = False) -> bytes:
543        """Download the binary content of a document.
544
545        Args:
546            id: Numeric ID of the document to download.
547            original: If ``False`` *(default)*, returns the archived PDF.
548                If ``True``, returns the original uploaded file.
549
550        Returns:
551            Raw file bytes.
552        """
553        endpoint = "download" if original else "archive"
554        resp = await self._core._session.get_download(f"/documents/{id}/{endpoint}/")
555        content_type = resp.headers.get("content-type", "")
556        if "text/html" in content_type or resp.content[:9].lower().startswith(b"<!doctype"):
557            raise ServerError(
558                f"Download returned an HTML page (content-type: {content_type!r}). "
559                "The server redirected to a login page even after re-attaching auth.",
560                status_code=None,
561            )
562        return resp.content

Download the binary content of a document.

Arguments:
  • id: Numeric ID of the document to download.
  • original: If False (default), returns the archived PDF. If True, returns the original uploaded file.
Returns:

Raw file bytes.

async def upload( self, file: str | pathlib._local.Path, *, title: str | None = None, created: datetime.date | str | None = None, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, tags: Optional[List[Union[str, int]]] = None, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, custom_fields: Optional[List[dict[str, Any]]] = None, wait: bool = False, poll_interval: float | None = None, poll_timeout: float | None = None) -> str | easypaperless.Document:
564    async def upload(
565        self,
566        file: str | Path,
567        *,
568        title: str | None = None,
569        created: date | str | None = None,
570        correspondent: int | str | None | _Unset = UNSET,
571        document_type: int | str | None | _Unset = UNSET,
572        storage_path: int | str | None | _Unset = UNSET,
573        tags: List[int | str] | None = None,
574        archive_serial_number: int | None | _Unset = UNSET,
575        custom_fields: List[dict[str, Any]] | None = None,
576        wait: bool = False,
577        poll_interval: float | None = None,
578        poll_timeout: float | None = None,
579    ) -> str | Document:
580        """Upload a document to paperless-ngx.
581
582        Args:
583            file: Path to the file to upload.
584            title: Title to assign to the document.
585            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
586                :class:`~datetime.date` object.
587            correspondent: Correspondent to assign, as an ID or name.
588            document_type: Document type to assign, as an ID or name.
589            storage_path: Storage path to assign, as an ID or name.
590            tags: Tags to assign, as IDs or names.
591            archive_serial_number: Archive serial number to assign.
592            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
593            wait: If ``False`` *(default)*, returns immediately with the task ID.
594                If ``True``, polls until processing completes.
595            poll_interval: Override the client-level ``poll_interval`` (in seconds).
596            poll_timeout: Override the client-level ``poll_timeout`` (in seconds).
597
598        Returns:
599            The Celery task ID string when ``wait=False``, or the fully
600            processed :class:`~easypaperless.models.documents.Document`
601            when ``wait=True``.
602
603        Raises:
604            ~easypaperless.exceptions.UploadError: If processing fails.
605            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
606        """
607        resolver = self._core._resolver
608        file_path = Path(file)
609        file_bytes = file_path.read_bytes()
610        logger.info("Uploading %r (%d bytes)", file_path.name, len(file_bytes))
611
612        data: dict[str, Any] = {}
613        if title is not None:
614            data["title"] = title
615        if created is not None:
616            data["created"] = self._format_date_value(created)
617        if not isinstance(correspondent, _Unset) and correspondent is not None:
618            data["correspondent"] = await resolver.resolve("correspondents", correspondent)
619        if not isinstance(document_type, _Unset) and document_type is not None:
620            data["document_type"] = await resolver.resolve("document_types", document_type)
621        if not isinstance(storage_path, _Unset) and storage_path is not None:
622            data["storage_path"] = await resolver.resolve("storage_paths", storage_path)
623        if tags is not None:
624            resolved = await resolver.resolve_list("tags", tags)
625            data["tags"] = resolved
626        if not isinstance(archive_serial_number, _Unset) and archive_serial_number is not None:
627            data["archive_serial_number"] = archive_serial_number
628        if custom_fields is not None:
629            data["custom_fields"] = json.dumps(custom_fields)
630
631        files = {"document": (file_path.name, file_bytes)}
632        resp = await self._core._session.post("/documents/post_document/", data=data, files=files)
633        task_id: str = resp.text.strip('"')
634        logger.debug("Upload accepted, task_id=%r", task_id)
635
636        if not wait:
637            return task_id
638
639        interval = poll_interval if poll_interval is not None else self._core._poll_interval
640        timeout = poll_timeout if poll_timeout is not None else self._core._poll_timeout
641        return await self._poll_task(task_id, poll_interval=interval, poll_timeout=timeout)

Upload a document to paperless-ngx.

Arguments:
  • file: Path to the file to upload.
  • title: Title to assign to the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name.
  • document_type: Document type to assign, as an ID or name.
  • storage_path: Storage path to assign, as an ID or name.
  • tags: Tags to assign, as IDs or names.
  • archive_serial_number: Archive serial number to assign.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • wait: If False (default), returns immediately with the task ID. If True, polls until processing completes.
  • poll_interval: Override the client-level poll_interval (in seconds).
  • poll_timeout: Override the client-level poll_timeout (in seconds).
Returns:

The Celery task ID string when wait=False, or the fully processed ~easypaperless.models.documents.Document when wait=True.

Raises:
async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
696    async def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
697        """Add a tag to multiple documents in a single request.
698
699        Args:
700            document_ids: List of document IDs to tag.
701            tag: Tag to add, as an ID or name.
702        """
703        tag_id = await self._core._resolver.resolve("tags", tag)
704        await self._bulk_edit(document_ids, "add_tag", tag=tag_id)

Add a tag to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to tag.
  • tag: Tag to add, as an ID or name.
async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
706    async def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
707        """Remove a tag from multiple documents in a single request.
708
709        Args:
710            document_ids: List of document IDs to un-tag.
711            tag: Tag to remove, as an ID or name.
712        """
713        tag_id = await self._core._resolver.resolve("tags", tag)
714        await self._bulk_edit(document_ids, "remove_tag", tag=tag_id)

Remove a tag from multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to un-tag.
  • tag: Tag to remove, as an ID or name.
async def bulk_modify_tags( self, document_ids: List[int], *, add_tags: Optional[List[Union[str, int]]] = None, remove_tags: Optional[List[Union[str, int]]] = None) -> None:
716    async def bulk_modify_tags(
717        self,
718        document_ids: List[int],
719        *,
720        add_tags: List[int | str] | None = None,
721        remove_tags: List[int | str] | None = None,
722    ) -> None:
723        """Add and/or remove tags on multiple documents atomically.
724
725        Args:
726            document_ids: List of document IDs to modify.
727            add_tags: Tags to add, as IDs or names.
728            remove_tags: Tags to remove, as IDs or names.
729        """
730        resolver = self._core._resolver
731        add_ids = await resolver.resolve_list("tags", add_tags or [])
732        remove_ids = await resolver.resolve_list("tags", remove_tags or [])
733        await self._bulk_edit(document_ids, "modify_tags", add_tags=add_ids, remove_tags=remove_ids)

Add and/or remove tags on multiple documents atomically.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_tags: Tags to add, as IDs or names.
  • remove_tags: Tags to remove, as IDs or names.
async def bulk_delete(self, document_ids: List[int]) -> None:
735    async def bulk_delete(self, document_ids: List[int]) -> None:
736        """Permanently delete multiple documents in a single request.
737
738        Args:
739            document_ids: List of document IDs to delete.
740        """
741        await self._bulk_edit(document_ids, "delete")

Permanently delete multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to delete.
async def bulk_set_correspondent(self, document_ids: List[int], correspondent: int | str | None) -> None:
743    async def bulk_set_correspondent(
744        self, document_ids: List[int], correspondent: int | str | None
745    ) -> None:
746        """Assign a correspondent to multiple documents in a single request.
747
748        Args:
749            document_ids: List of document IDs to modify.
750            correspondent: Correspondent to assign, as an ID or name.
751                Pass ``None`` to clear.
752        """
753        cor_id: int | None = None
754        if correspondent is not None:
755            cor_id = await self._core._resolver.resolve("correspondents", correspondent)
756        await self._bulk_edit(document_ids, "set_correspondent", correspondent=cor_id)

Assign a correspondent to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear.
async def bulk_set_document_type(self, document_ids: List[int], document_type: int | str | None) -> None:
758    async def bulk_set_document_type(
759        self, document_ids: List[int], document_type: int | str | None
760    ) -> None:
761        """Assign a document type to multiple documents in a single request.
762
763        Args:
764            document_ids: List of document IDs to modify.
765            document_type: Document type to assign, as an ID or name.
766                Pass ``None`` to clear.
767        """
768        dt_id: int | None = None
769        if document_type is not None:
770            dt_id = await self._core._resolver.resolve("document_types", document_type)
771        await self._bulk_edit(document_ids, "set_document_type", document_type=dt_id)

Assign a document type to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • document_type: Document type to assign, as an ID or name. Pass None to clear.
async def bulk_set_storage_path(self, document_ids: List[int], storage_path: int | str | None) -> None:
773    async def bulk_set_storage_path(
774        self, document_ids: List[int], storage_path: int | str | None
775    ) -> None:
776        """Assign a storage path to multiple documents in a single request.
777
778        Args:
779            document_ids: List of document IDs to modify.
780            storage_path: Storage path to assign, as an ID or name.
781                Pass ``None`` to clear.
782        """
783        sp_id: int | None = None
784        if storage_path is not None:
785            sp_id = await self._core._resolver.resolve("storage_paths", storage_path)
786        await self._bulk_edit(document_ids, "set_storage_path", storage_path=sp_id)

Assign a storage path to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear.
async def bulk_modify_custom_fields( self, document_ids: List[int], *, add_fields: Optional[List[dict[str, Any]]] = None, remove_fields: Optional[List[int]] = None) -> None:
788    async def bulk_modify_custom_fields(
789        self,
790        document_ids: List[int],
791        *,
792        add_fields: List[dict[str, Any]] | None = None,
793        remove_fields: List[int] | None = None,
794    ) -> None:
795        """Add and/or remove custom field values on multiple documents.
796
797        Args:
798            document_ids: List of document IDs to modify.
799            add_fields: Custom-field value dicts to add.
800            remove_fields: Custom-field IDs whose values should be removed.
801        """
802        await self._bulk_edit(
803            document_ids,
804            "modify_custom_fields",
805            add_custom_fields=add_fields or [],
806            remove_custom_fields=remove_fields or [],
807        )

Add and/or remove custom field values on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_fields: Custom-field value dicts to add.
  • remove_fields: Custom-field IDs whose values should be removed.
async def bulk_set_permissions( self, document_ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
809    async def bulk_set_permissions(
810        self,
811        document_ids: List[int],
812        *,
813        set_permissions: SetPermissions | None = None,
814        owner: int | None = None,
815        merge: bool = False,
816    ) -> None:
817        """Set permissions and/or owner on multiple documents.
818
819        Args:
820            document_ids: List of document IDs to modify.
821            set_permissions: Explicit view/change permission sets.
822            owner: Numeric user ID to assign as document owner.
823            merge: When ``True``, new permissions are merged with existing ones.
824        """
825        params: dict[str, Any] = {"merge": merge}
826        if set_permissions is not None:
827            params["set_permissions"] = set_permissions.model_dump()
828        if owner is not None:
829            params["owner"] = owner
830        await self._bulk_edit(document_ids, "set_permissions", **params)

Set permissions and/or owner on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as document owner.
  • merge: When True, new permissions are merged with existing ones.
class NotesResource:
 42class NotesResource:
 43    """Accessor for document notes: ``client.documents.notes``."""
 44
 45    def __init__(self, core: _ClientCore) -> None:
 46        self._core = core
 47
 48    async def list(self, document_id: int) -> List[DocumentNote]:
 49        """Fetch all notes attached to a document.
 50
 51        Args:
 52            document_id: Numeric ID of the document whose notes to retrieve.
 53
 54        Returns:
 55            List of :class:`~easypaperless.models.documents.DocumentNote` objects,
 56            ordered by creation time.
 57
 58        Raises:
 59            ~easypaperless.exceptions.NotFoundError: If no document exists
 60                with that ID.
 61        """
 62        logger.debug("Fetching notes for document id=%d", document_id)
 63        resp = await self._core._session.get(f"/documents/{document_id}/notes/")
 64        return [DocumentNote.model_validate(item) for item in resp.json()]
 65
 66    async def create(self, document_id: int, *, note: str) -> DocumentNote:
 67        """Create a new note on a document.
 68
 69        Args:
 70            document_id: Numeric ID of the document to annotate.
 71            note: Text content of the note.
 72
 73        Returns:
 74            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
 75
 76        Raises:
 77            ~easypaperless.exceptions.NotFoundError: If no document exists
 78                with that ID.
 79        """
 80        logger.debug("Creating note for document id=%d", document_id)
 81        resp = await self._core._session.post(
 82            f"/documents/{document_id}/notes/",
 83            json={"note": note},
 84        )
 85        data = resp.json()
 86        if isinstance(data, list):
 87            return DocumentNote.model_validate(data[-1])
 88        return DocumentNote.model_validate(data)
 89
 90    async def delete(self, document_id: int, note_id: int) -> None:
 91        """Delete a note from a document.
 92
 93        Args:
 94            document_id: Numeric ID of the document that owns the note.
 95            note_id: Numeric ID of the note to delete.
 96
 97        Raises:
 98            ~easypaperless.exceptions.NotFoundError: If no document or note
 99                exists with the given IDs.
100        """
101        logger.debug("Deleting note id=%d from document id=%d", note_id, document_id)
102        await self._core._session.delete(f"/documents/{document_id}/notes/", params={"id": note_id})

Accessor for document notes: client.documents.notes.

NotesResource(core: easypaperless.client._ClientCore)
45    def __init__(self, core: _ClientCore) -> None:
46        self._core = core
async def list( self, document_id: int) -> List[easypaperless.DocumentNote]:
48    async def list(self, document_id: int) -> List[DocumentNote]:
49        """Fetch all notes attached to a document.
50
51        Args:
52            document_id: Numeric ID of the document whose notes to retrieve.
53
54        Returns:
55            List of :class:`~easypaperless.models.documents.DocumentNote` objects,
56            ordered by creation time.
57
58        Raises:
59            ~easypaperless.exceptions.NotFoundError: If no document exists
60                with that ID.
61        """
62        logger.debug("Fetching notes for document id=%d", document_id)
63        resp = await self._core._session.get(f"/documents/{document_id}/notes/")
64        return [DocumentNote.model_validate(item) for item in resp.json()]

Fetch all notes attached to a document.

Arguments:
  • document_id: Numeric ID of the document whose notes to retrieve.
Returns:

List of ~easypaperless.models.documents.DocumentNote objects, ordered by creation time.

Raises:
async def create( self, document_id: int, *, note: str) -> easypaperless.DocumentNote:
66    async def create(self, document_id: int, *, note: str) -> DocumentNote:
67        """Create a new note on a document.
68
69        Args:
70            document_id: Numeric ID of the document to annotate.
71            note: Text content of the note.
72
73        Returns:
74            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
75
76        Raises:
77            ~easypaperless.exceptions.NotFoundError: If no document exists
78                with that ID.
79        """
80        logger.debug("Creating note for document id=%d", document_id)
81        resp = await self._core._session.post(
82            f"/documents/{document_id}/notes/",
83            json={"note": note},
84        )
85        data = resp.json()
86        if isinstance(data, list):
87            return DocumentNote.model_validate(data[-1])
88        return DocumentNote.model_validate(data)

Create a new note on a document.

Arguments:
  • document_id: Numeric ID of the document to annotate.
  • note: Text content of the note.
Returns:

The newly created ~easypaperless.models.documents.DocumentNote.

Raises:
async def delete(self, document_id: int, note_id: int) -> None:
 90    async def delete(self, document_id: int, note_id: int) -> None:
 91        """Delete a note from a document.
 92
 93        Args:
 94            document_id: Numeric ID of the document that owns the note.
 95            note_id: Numeric ID of the note to delete.
 96
 97        Raises:
 98            ~easypaperless.exceptions.NotFoundError: If no document or note
 99                exists with the given IDs.
100        """
101        logger.debug("Deleting note id=%d from document id=%d", note_id, document_id)
102        await self._core._session.delete(f"/documents/{document_id}/notes/", params={"id": note_id})

Delete a note from a document.

Arguments:
  • document_id: Numeric ID of the document that owns the note.
  • note_id: Numeric ID of the note to delete.
Raises:
class StoragePathsResource:
 17class StoragePathsResource:
 18    """Accessor for storage paths: ``client.storage_paths``."""
 19
 20    def __init__(self, core: _ClientCore) -> None:
 21        self._core = core
 22
 23    async def list(
 24        self,
 25        *,
 26        ids: List[int] | None = None,
 27        name_contains: str | None = None,
 28        name_exact: str | None = None,
 29        path_contains: str | None = None,
 30        path_exact: str | None = None,
 31        page: int | None = None,
 32        page_size: int | None = None,
 33        ordering: str | None = None,
 34        descending: bool = False,
 35    ) -> List[StoragePath]:
 36        """Return storage paths defined in paperless-ngx.
 37
 38        Args:
 39            ids: Return only storage paths whose ID is in this list.
 40            name_contains: Case-insensitive substring filter on name.
 41            name_exact: Case-insensitive exact match on name.
 42            path_contains: Case-insensitive substring filter on path template.
 43            path_exact: Case-insensitive exact match on path template.
 44            page: Return only this specific page (1-based).
 45            page_size: Number of results per page.
 46            ordering: Field to sort by.
 47            descending: When ``True``, reverses the sort direction.
 48
 49        Returns:
 50            List of :class:`~easypaperless.models.storage_paths.StoragePath` objects.
 51        """
 52        params: dict[str, Any] = {}
 53        if ids is not None:
 54            params["id__in"] = ",".join(str(i) for i in ids)
 55        if name_contains is not None:
 56            params["name__icontains"] = name_contains
 57        if name_exact is not None:
 58            params["name__iexact"] = name_exact
 59        if path_contains is not None:
 60            params["path__icontains"] = path_contains
 61        if path_exact is not None:
 62            params["path__iexact"] = path_exact
 63        if page is not None:
 64            params["page"] = page
 65        if page_size is not None:
 66            params["page_size"] = page_size
 67        if ordering is not None:
 68            params["ordering"] = f"-{ordering}" if descending else ordering
 69        return cast(
 70            List[StoragePath],
 71            await self._core._list_resource("storage_paths", StoragePath, params or None),
 72        )
 73
 74    async def get(self, id: int) -> StoragePath:
 75        """Fetch a single storage path by its ID.
 76
 77        Args:
 78            id: Numeric storage-path ID.
 79
 80        Returns:
 81            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
 82
 83        Raises:
 84            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
 85        """
 86        return cast(StoragePath, await self._core._get_resource("storage_paths", id, StoragePath))
 87
 88    async def create(
 89        self,
 90        *,
 91        name: str,
 92        path: str | None = None,
 93        match: str | None | _Unset = UNSET,
 94        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 95        is_insensitive: bool = True,
 96        owner: int | None | _Unset = UNSET,
 97        set_permissions: SetPermissions | None = None,
 98    ) -> StoragePath:
 99        """Create a new storage path.
100
101        Args:
102            name: Storage-path name. Must be unique.
103            path: Template string for the archive file path.
104            match: Auto-matching pattern.
105            matching_algorithm: Controls how ``match`` is applied.
106            is_insensitive: When ``True``, ``match`` is case-insensitive.
107                Defaults to ``True``, matching the paperless-ngx API default.
108            owner: Numeric user ID to assign as owner.
109            set_permissions: Explicit view/change permission sets.
110
111        Returns:
112            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
113        """
114        return cast(
115            StoragePath,
116            await self._core._create_resource(
117                "storage_paths",
118                StoragePath,
119                owner=owner,
120                set_permissions=set_permissions,
121                name=name,
122                path=path,
123                match=match,
124                matching_algorithm=matching_algorithm,
125                is_insensitive=is_insensitive,
126            ),
127        )
128
129    async def update(
130        self,
131        id: int,
132        *,
133        name: str | None | _Unset = UNSET,
134        path: str | None | _Unset = UNSET,
135        match: str | None | _Unset = UNSET,
136        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
137        is_insensitive: bool | None | _Unset = UNSET,
138        owner: int | None | _Unset = UNSET,
139        set_permissions: SetPermissions | None | _Unset = UNSET,
140    ) -> StoragePath:
141        """Partially update a storage path (PATCH semantics).
142
143        Args:
144            id: Numeric ID of the storage path to update.
145            name: Storage-path name.
146            path: Template string for the archive file path.
147            match: Auto-matching pattern.
148            matching_algorithm: Controls how ``match`` is applied.
149            is_insensitive: When ``True``, ``match`` is case-insensitive.
150            owner: Numeric user ID to assign as owner.
151                Pass ``None`` to clear the owner.
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153            set_permissions: Explicit view/change permission sets.
154                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
155
156        Returns:
157            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
158        """
159        _set_perms: dict[str, Any] | _Unset = (
160            UNSET
161            if isinstance(set_permissions, _Unset)
162            else (set_permissions or SetPermissions()).model_dump()
163        )
164        return cast(
165            StoragePath,
166            await self._core._update_resource(
167                "storage_paths",
168                id,
169                StoragePath,
170                name=name,
171                path=path,
172                match=match,
173                matching_algorithm=matching_algorithm,
174                is_insensitive=is_insensitive,
175                owner=owner,
176                set_permissions=_set_perms,
177            ),
178        )
179
180    async def delete(self, id: int) -> None:
181        """Delete a storage path.
182
183        Args:
184            id: Numeric ID of the storage path to delete.
185
186        Raises:
187            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
188        """
189        await self._core._delete_resource("storage_paths", id)
190
191    async def bulk_delete(self, ids: List[int]) -> None:
192        """Permanently delete multiple storage paths in a single request.
193
194        Args:
195            ids: List of storage path IDs to delete.
196        """
197        await self._core._bulk_edit_objects("storage_paths", ids, "delete")
198
199    async def bulk_set_permissions(
200        self,
201        ids: List[int],
202        *,
203        set_permissions: SetPermissions | None = None,
204        owner: int | None = None,
205        merge: bool = False,
206    ) -> None:
207        """Set permissions and/or owner on multiple storage paths.
208
209        Args:
210            ids: List of storage path IDs to modify.
211            set_permissions: Explicit view/change permission sets.
212            owner: Numeric user ID to assign as owner.
213            merge: When ``True``, new permissions are merged with existing ones.
214        """
215        params: dict[str, Any] = {"merge": merge}
216        if set_permissions is not None:
217            params["permissions"] = set_permissions.model_dump()
218        if owner is not None:
219            params["owner"] = owner
220        await self._core._bulk_edit_objects("storage_paths", ids, "set_permissions", **params)

Accessor for storage paths: client.storage_paths.

StoragePathsResource(core: easypaperless.client._ClientCore)
20    def __init__(self, core: _ClientCore) -> None:
21        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, path_contains: str | None = None, path_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.StoragePath]:
23    async def list(
24        self,
25        *,
26        ids: List[int] | None = None,
27        name_contains: str | None = None,
28        name_exact: str | None = None,
29        path_contains: str | None = None,
30        path_exact: str | None = None,
31        page: int | None = None,
32        page_size: int | None = None,
33        ordering: str | None = None,
34        descending: bool = False,
35    ) -> List[StoragePath]:
36        """Return storage paths defined in paperless-ngx.
37
38        Args:
39            ids: Return only storage paths whose ID is in this list.
40            name_contains: Case-insensitive substring filter on name.
41            name_exact: Case-insensitive exact match on name.
42            path_contains: Case-insensitive substring filter on path template.
43            path_exact: Case-insensitive exact match on path template.
44            page: Return only this specific page (1-based).
45            page_size: Number of results per page.
46            ordering: Field to sort by.
47            descending: When ``True``, reverses the sort direction.
48
49        Returns:
50            List of :class:`~easypaperless.models.storage_paths.StoragePath` objects.
51        """
52        params: dict[str, Any] = {}
53        if ids is not None:
54            params["id__in"] = ",".join(str(i) for i in ids)
55        if name_contains is not None:
56            params["name__icontains"] = name_contains
57        if name_exact is not None:
58            params["name__iexact"] = name_exact
59        if path_contains is not None:
60            params["path__icontains"] = path_contains
61        if path_exact is not None:
62            params["path__iexact"] = path_exact
63        if page is not None:
64            params["page"] = page
65        if page_size is not None:
66            params["page_size"] = page_size
67        if ordering is not None:
68            params["ordering"] = f"-{ordering}" if descending else ordering
69        return cast(
70            List[StoragePath],
71            await self._core._list_resource("storage_paths", StoragePath, params or None),
72        )

Return storage paths defined in paperless-ngx.

Arguments:
  • ids: Return only storage paths whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • path_contains: Case-insensitive substring filter on path template.
  • path_exact: Case-insensitive exact match on path template.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.storage_paths.StoragePath objects.

async def get(self, id: int) -> easypaperless.StoragePath:
74    async def get(self, id: int) -> StoragePath:
75        """Fetch a single storage path by its ID.
76
77        Args:
78            id: Numeric storage-path ID.
79
80        Returns:
81            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
82
83        Raises:
84            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
85        """
86        return cast(StoragePath, await self._core._get_resource("storage_paths", id, StoragePath))

Fetch a single storage path by its ID.

Arguments:
  • id: Numeric storage-path ID.
Returns:

The ~easypaperless.models.storage_paths.StoragePath with the given ID.

Raises:
async def create( self, *, name: str, path: str | None = None, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.StoragePath:
 88    async def create(
 89        self,
 90        *,
 91        name: str,
 92        path: str | None = None,
 93        match: str | None | _Unset = UNSET,
 94        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 95        is_insensitive: bool = True,
 96        owner: int | None | _Unset = UNSET,
 97        set_permissions: SetPermissions | None = None,
 98    ) -> StoragePath:
 99        """Create a new storage path.
100
101        Args:
102            name: Storage-path name. Must be unique.
103            path: Template string for the archive file path.
104            match: Auto-matching pattern.
105            matching_algorithm: Controls how ``match`` is applied.
106            is_insensitive: When ``True``, ``match`` is case-insensitive.
107                Defaults to ``True``, matching the paperless-ngx API default.
108            owner: Numeric user ID to assign as owner.
109            set_permissions: Explicit view/change permission sets.
110
111        Returns:
112            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
113        """
114        return cast(
115            StoragePath,
116            await self._core._create_resource(
117                "storage_paths",
118                StoragePath,
119                owner=owner,
120                set_permissions=set_permissions,
121                name=name,
122                path=path,
123                match=match,
124                matching_algorithm=matching_algorithm,
125                is_insensitive=is_insensitive,
126            ),
127        )

Create a new storage path.

Arguments:
  • name: Storage-path name. Must be unique.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.storage_paths.StoragePath.

async def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, path: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.StoragePath:
129    async def update(
130        self,
131        id: int,
132        *,
133        name: str | None | _Unset = UNSET,
134        path: str | None | _Unset = UNSET,
135        match: str | None | _Unset = UNSET,
136        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
137        is_insensitive: bool | None | _Unset = UNSET,
138        owner: int | None | _Unset = UNSET,
139        set_permissions: SetPermissions | None | _Unset = UNSET,
140    ) -> StoragePath:
141        """Partially update a storage path (PATCH semantics).
142
143        Args:
144            id: Numeric ID of the storage path to update.
145            name: Storage-path name.
146            path: Template string for the archive file path.
147            match: Auto-matching pattern.
148            matching_algorithm: Controls how ``match`` is applied.
149            is_insensitive: When ``True``, ``match`` is case-insensitive.
150            owner: Numeric user ID to assign as owner.
151                Pass ``None`` to clear the owner.
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153            set_permissions: Explicit view/change permission sets.
154                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
155
156        Returns:
157            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
158        """
159        _set_perms: dict[str, Any] | _Unset = (
160            UNSET
161            if isinstance(set_permissions, _Unset)
162            else (set_permissions or SetPermissions()).model_dump()
163        )
164        return cast(
165            StoragePath,
166            await self._core._update_resource(
167                "storage_paths",
168                id,
169                StoragePath,
170                name=name,
171                path=path,
172                match=match,
173                matching_algorithm=matching_algorithm,
174                is_insensitive=is_insensitive,
175                owner=owner,
176                set_permissions=_set_perms,
177            ),
178        )

Partially update a storage path (PATCH semantics).

Arguments:
  • id: Numeric ID of the storage path to update.
  • name: Storage-path name.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.storage_paths.StoragePath.

async def delete(self, id: int) -> None:
180    async def delete(self, id: int) -> None:
181        """Delete a storage path.
182
183        Args:
184            id: Numeric ID of the storage path to delete.
185
186        Raises:
187            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
188        """
189        await self._core._delete_resource("storage_paths", id)

Delete a storage path.

Arguments:
  • id: Numeric ID of the storage path to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
191    async def bulk_delete(self, ids: List[int]) -> None:
192        """Permanently delete multiple storage paths in a single request.
193
194        Args:
195            ids: List of storage path IDs to delete.
196        """
197        await self._core._bulk_edit_objects("storage_paths", ids, "delete")

Permanently delete multiple storage paths in a single request.

Arguments:
  • ids: List of storage path IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
199    async def bulk_set_permissions(
200        self,
201        ids: List[int],
202        *,
203        set_permissions: SetPermissions | None = None,
204        owner: int | None = None,
205        merge: bool = False,
206    ) -> None:
207        """Set permissions and/or owner on multiple storage paths.
208
209        Args:
210            ids: List of storage path IDs to modify.
211            set_permissions: Explicit view/change permission sets.
212            owner: Numeric user ID to assign as owner.
213            merge: When ``True``, new permissions are merged with existing ones.
214        """
215        params: dict[str, Any] = {"merge": merge}
216        if set_permissions is not None:
217            params["permissions"] = set_permissions.model_dump()
218        if owner is not None:
219            params["owner"] = owner
220        await self._core._bulk_edit_objects("storage_paths", ids, "set_permissions", **params)

Set permissions and/or owner on multiple storage paths.

Arguments:
  • ids: List of storage path IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class TagsResource:
 17class TagsResource:
 18    """Accessor for tags: ``client.tags``."""
 19
 20    def __init__(self, core: _ClientCore) -> None:
 21        self._core = core
 22
 23    async def list(
 24        self,
 25        *,
 26        ids: List[int] | None = None,
 27        name_contains: str | None = None,
 28        name_exact: str | None = None,
 29        page: int | None = None,
 30        page_size: int | None = None,
 31        ordering: str | None = None,
 32        descending: bool = False,
 33    ) -> List[Tag]:
 34        """Return tags defined in paperless-ngx.
 35
 36        Args:
 37            ids: Return only tags whose ID is in this list.
 38            name_contains: Case-insensitive substring filter on tag name.
 39            name_exact: Case-insensitive exact match on tag name.
 40            page: Return only this specific page (1-based).
 41            page_size: Number of results per page.
 42            ordering: Field to sort by.
 43            descending: When ``True``, reverses the sort direction.
 44
 45        Returns:
 46            List of :class:`~easypaperless.models.tags.Tag` objects.
 47        """
 48        params: dict[str, Any] = {}
 49        if ids is not None:
 50            params["id__in"] = ",".join(str(i) for i in ids)
 51        if name_contains is not None:
 52            params["name__icontains"] = name_contains
 53        if name_exact is not None:
 54            params["name__iexact"] = name_exact
 55        if page is not None:
 56            params["page"] = page
 57        if page_size is not None:
 58            params["page_size"] = page_size
 59        if ordering is not None:
 60            params["ordering"] = f"-{ordering}" if descending else ordering
 61        return cast(
 62            List[Tag],
 63            await self._core._list_resource("tags", Tag, params or None),
 64        )
 65
 66    async def get(self, id: int) -> Tag:
 67        """Fetch a single tag by its ID.
 68
 69        Args:
 70            id: Numeric tag ID.
 71
 72        Returns:
 73            The :class:`~easypaperless.models.tags.Tag` with the given ID.
 74
 75        Raises:
 76            ~easypaperless.exceptions.NotFoundError: If no tag exists with
 77                that ID.
 78        """
 79        return cast(Tag, await self._core._get_resource("tags", id, Tag))
 80
 81    async def create(
 82        self,
 83        *,
 84        name: str,
 85        color: str | None | _Unset = UNSET,
 86        is_inbox_tag: bool | None | _Unset = UNSET,
 87        match: str | None | _Unset = UNSET,
 88        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 89        is_insensitive: bool = True,
 90        parent: int | None | _Unset = UNSET,
 91        owner: int | None | _Unset = UNSET,
 92        set_permissions: SetPermissions | None = None,
 93    ) -> Tag:
 94        """Create a new tag.
 95
 96        Args:
 97            name: Tag name. Must be unique.
 98            color: Background colour as a CSS hex string.
 99            is_inbox_tag: When ``True``, newly ingested documents get this tag.
100            match: Auto-matching pattern.
101            matching_algorithm: Controls how ``match`` is applied.
102            is_insensitive: When ``True``, ``match`` is case-insensitive.
103                Defaults to ``True``, matching the paperless-ngx API default.
104            parent: ID of parent tag for hierarchical trees.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107
108        Returns:
109            The newly created :class:`~easypaperless.models.tags.Tag`.
110        """
111        return cast(
112            Tag,
113            await self._core._create_resource(
114                "tags",
115                Tag,
116                owner=owner,
117                set_permissions=set_permissions,
118                name=name,
119                color=color,
120                is_inbox_tag=is_inbox_tag,
121                match=match,
122                matching_algorithm=matching_algorithm,
123                is_insensitive=is_insensitive,
124                parent=parent,
125            ),
126        )
127
128    async def update(
129        self,
130        id: int,
131        *,
132        name: str | None | _Unset = UNSET,
133        color: str | None | _Unset = UNSET,
134        is_inbox_tag: bool | None | _Unset = UNSET,
135        match: str | None | _Unset = UNSET,
136        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
137        is_insensitive: bool | None | _Unset = UNSET,
138        parent: int | None | _Unset = UNSET,
139        owner: int | None | _Unset = UNSET,
140        set_permissions: SetPermissions | None | _Unset = UNSET,
141    ) -> Tag:
142        """Partially update a tag (PATCH semantics).
143
144        Args:
145            id: Numeric ID of the tag to update.
146            name: Tag name.
147            color: Background colour as a CSS hex string.
148            is_inbox_tag: When ``True``, newly ingested documents get this tag.
149            match: Auto-matching pattern.
150            matching_algorithm: Controls how ``match`` is applied.
151            is_insensitive: When ``True``, ``match`` is case-insensitive.
152            parent: ID of parent tag.
153                Pass ``None`` to clear (make root tag).
154                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
155            owner: Numeric user ID to assign as owner.
156                Pass ``None`` to clear the owner.
157                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
158            set_permissions: Explicit view/change permission sets.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160
161        Returns:
162            The updated :class:`~easypaperless.models.tags.Tag`.
163        """
164        _set_perms: dict[str, Any] | _Unset = (
165            UNSET
166            if isinstance(set_permissions, _Unset)
167            else (set_permissions or SetPermissions()).model_dump()
168        )
169        return cast(
170            Tag,
171            await self._core._update_resource(
172                "tags",
173                id,
174                Tag,
175                name=name,
176                color=color,
177                is_inbox_tag=is_inbox_tag,
178                match=match,
179                matching_algorithm=matching_algorithm,
180                is_insensitive=is_insensitive,
181                parent=parent,
182                owner=owner,
183                set_permissions=_set_perms,
184            ),
185        )
186
187    async def delete(self, id: int) -> None:
188        """Delete a tag.
189
190        Args:
191            id: Numeric ID of the tag to delete.
192
193        Raises:
194            ~easypaperless.exceptions.NotFoundError: If no tag exists with
195                that ID.
196        """
197        await self._core._delete_resource("tags", id)
198
199    async def bulk_delete(self, ids: List[int]) -> None:
200        """Permanently delete multiple tags in a single request.
201
202        Args:
203            ids: List of tag IDs to delete.
204        """
205        await self._core._bulk_edit_objects("tags", ids, "delete")
206
207    async def bulk_set_permissions(
208        self,
209        ids: List[int],
210        *,
211        set_permissions: SetPermissions | None = None,
212        owner: int | None = None,
213        merge: bool = False,
214    ) -> None:
215        """Set permissions and/or owner on multiple tags.
216
217        Args:
218            ids: List of tag IDs to modify.
219            set_permissions: Explicit view/change permission sets.
220            owner: Numeric user ID to assign as owner.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        params: dict[str, Any] = {"merge": merge}
224        if set_permissions is not None:
225            params["permissions"] = set_permissions.model_dump()
226        if owner is not None:
227            params["owner"] = owner
228        await self._core._bulk_edit_objects("tags", ids, "set_permissions", **params)

Accessor for tags: client.tags.

TagsResource(core: easypaperless.client._ClientCore)
20    def __init__(self, core: _ClientCore) -> None:
21        self._core = core
async def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.Tag]:
23    async def list(
24        self,
25        *,
26        ids: List[int] | None = None,
27        name_contains: str | None = None,
28        name_exact: str | None = None,
29        page: int | None = None,
30        page_size: int | None = None,
31        ordering: str | None = None,
32        descending: bool = False,
33    ) -> List[Tag]:
34        """Return tags defined in paperless-ngx.
35
36        Args:
37            ids: Return only tags whose ID is in this list.
38            name_contains: Case-insensitive substring filter on tag name.
39            name_exact: Case-insensitive exact match on tag name.
40            page: Return only this specific page (1-based).
41            page_size: Number of results per page.
42            ordering: Field to sort by.
43            descending: When ``True``, reverses the sort direction.
44
45        Returns:
46            List of :class:`~easypaperless.models.tags.Tag` objects.
47        """
48        params: dict[str, Any] = {}
49        if ids is not None:
50            params["id__in"] = ",".join(str(i) for i in ids)
51        if name_contains is not None:
52            params["name__icontains"] = name_contains
53        if name_exact is not None:
54            params["name__iexact"] = name_exact
55        if page is not None:
56            params["page"] = page
57        if page_size is not None:
58            params["page_size"] = page_size
59        if ordering is not None:
60            params["ordering"] = f"-{ordering}" if descending else ordering
61        return cast(
62            List[Tag],
63            await self._core._list_resource("tags", Tag, params or None),
64        )

Return tags defined in paperless-ngx.

Arguments:
  • ids: Return only tags whose ID is in this list.
  • name_contains: Case-insensitive substring filter on tag name.
  • name_exact: Case-insensitive exact match on tag name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.tags.Tag objects.

async def get(self, id: int) -> easypaperless.Tag:
66    async def get(self, id: int) -> Tag:
67        """Fetch a single tag by its ID.
68
69        Args:
70            id: Numeric tag ID.
71
72        Returns:
73            The :class:`~easypaperless.models.tags.Tag` with the given ID.
74
75        Raises:
76            ~easypaperless.exceptions.NotFoundError: If no tag exists with
77                that ID.
78        """
79        return cast(Tag, await self._core._get_resource("tags", id, Tag))

Fetch a single tag by its ID.

Arguments:
  • id: Numeric tag ID.
Returns:

The ~easypaperless.models.tags.Tag with the given ID.

Raises:
async def create( self, *, name: str, color: str | None | easypaperless._internal.sentinel._Unset = UNSET, is_inbox_tag: bool | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, parent: int | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.Tag:
 81    async def create(
 82        self,
 83        *,
 84        name: str,
 85        color: str | None | _Unset = UNSET,
 86        is_inbox_tag: bool | None | _Unset = UNSET,
 87        match: str | None | _Unset = UNSET,
 88        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 89        is_insensitive: bool = True,
 90        parent: int | None | _Unset = UNSET,
 91        owner: int | None | _Unset = UNSET,
 92        set_permissions: SetPermissions | None = None,
 93    ) -> Tag:
 94        """Create a new tag.
 95
 96        Args:
 97            name: Tag name. Must be unique.
 98            color: Background colour as a CSS hex string.
 99            is_inbox_tag: When ``True``, newly ingested documents get this tag.
100            match: Auto-matching pattern.
101            matching_algorithm: Controls how ``match`` is applied.
102            is_insensitive: When ``True``, ``match`` is case-insensitive.
103                Defaults to ``True``, matching the paperless-ngx API default.
104            parent: ID of parent tag for hierarchical trees.
105            owner: Numeric user ID to assign as owner.
106            set_permissions: Explicit view/change permission sets.
107
108        Returns:
109            The newly created :class:`~easypaperless.models.tags.Tag`.
110        """
111        return cast(
112            Tag,
113            await self._core._create_resource(
114                "tags",
115                Tag,
116                owner=owner,
117                set_permissions=set_permissions,
118                name=name,
119                color=color,
120                is_inbox_tag=is_inbox_tag,
121                match=match,
122                matching_algorithm=matching_algorithm,
123                is_insensitive=is_insensitive,
124                parent=parent,
125            ),
126        )

Create a new tag.

Arguments:
  • name: Tag name. Must be unique.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • parent: ID of parent tag for hierarchical trees.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.tags.Tag.

async def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, color: str | None | easypaperless._internal.sentinel._Unset = UNSET, is_inbox_tag: bool | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, parent: int | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Tag:
128    async def update(
129        self,
130        id: int,
131        *,
132        name: str | None | _Unset = UNSET,
133        color: str | None | _Unset = UNSET,
134        is_inbox_tag: bool | None | _Unset = UNSET,
135        match: str | None | _Unset = UNSET,
136        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
137        is_insensitive: bool | None | _Unset = UNSET,
138        parent: int | None | _Unset = UNSET,
139        owner: int | None | _Unset = UNSET,
140        set_permissions: SetPermissions | None | _Unset = UNSET,
141    ) -> Tag:
142        """Partially update a tag (PATCH semantics).
143
144        Args:
145            id: Numeric ID of the tag to update.
146            name: Tag name.
147            color: Background colour as a CSS hex string.
148            is_inbox_tag: When ``True``, newly ingested documents get this tag.
149            match: Auto-matching pattern.
150            matching_algorithm: Controls how ``match`` is applied.
151            is_insensitive: When ``True``, ``match`` is case-insensitive.
152            parent: ID of parent tag.
153                Pass ``None`` to clear (make root tag).
154                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
155            owner: Numeric user ID to assign as owner.
156                Pass ``None`` to clear the owner.
157                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
158            set_permissions: Explicit view/change permission sets.
159                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
160
161        Returns:
162            The updated :class:`~easypaperless.models.tags.Tag`.
163        """
164        _set_perms: dict[str, Any] | _Unset = (
165            UNSET
166            if isinstance(set_permissions, _Unset)
167            else (set_permissions or SetPermissions()).model_dump()
168        )
169        return cast(
170            Tag,
171            await self._core._update_resource(
172                "tags",
173                id,
174                Tag,
175                name=name,
176                color=color,
177                is_inbox_tag=is_inbox_tag,
178                match=match,
179                matching_algorithm=matching_algorithm,
180                is_insensitive=is_insensitive,
181                parent=parent,
182                owner=owner,
183                set_permissions=_set_perms,
184            ),
185        )

Partially update a tag (PATCH semantics).

Arguments:
  • id: Numeric ID of the tag to update.
  • name: Tag name.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • parent: ID of parent tag. Pass None to clear (make root tag). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.tags.Tag.

async def delete(self, id: int) -> None:
187    async def delete(self, id: int) -> None:
188        """Delete a tag.
189
190        Args:
191            id: Numeric ID of the tag to delete.
192
193        Raises:
194            ~easypaperless.exceptions.NotFoundError: If no tag exists with
195                that ID.
196        """
197        await self._core._delete_resource("tags", id)

Delete a tag.

Arguments:
  • id: Numeric ID of the tag to delete.
Raises:
async def bulk_delete(self, ids: List[int]) -> None:
199    async def bulk_delete(self, ids: List[int]) -> None:
200        """Permanently delete multiple tags in a single request.
201
202        Args:
203            ids: List of tag IDs to delete.
204        """
205        await self._core._bulk_edit_objects("tags", ids, "delete")

Permanently delete multiple tags in a single request.

Arguments:
  • ids: List of tag IDs to delete.
async def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
207    async def bulk_set_permissions(
208        self,
209        ids: List[int],
210        *,
211        set_permissions: SetPermissions | None = None,
212        owner: int | None = None,
213        merge: bool = False,
214    ) -> None:
215        """Set permissions and/or owner on multiple tags.
216
217        Args:
218            ids: List of tag IDs to modify.
219            set_permissions: Explicit view/change permission sets.
220            owner: Numeric user ID to assign as owner.
221            merge: When ``True``, new permissions are merged with existing ones.
222        """
223        params: dict[str, Any] = {"merge": merge}
224        if set_permissions is not None:
225            params["permissions"] = set_permissions.model_dump()
226        if owner is not None:
227            params["owner"] = owner
228        await self._core._bulk_edit_objects("tags", ids, "set_permissions", **params)

Set permissions and/or owner on multiple tags.

Arguments:
  • ids: List of tag IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class SyncCorrespondentsResource:
 17class SyncCorrespondentsResource:
 18    """Sync accessor for correspondents: ``client.correspondents``."""
 19
 20    def __init__(self, async_correspondents: CorrespondentsResource, run: Any) -> None:
 21        self._async_correspondents = async_correspondents
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        ids: List[int] | None = None,
 28        name_contains: str | None = None,
 29        name_exact: str | None = None,
 30        page: int | None = None,
 31        page_size: int | None = None,
 32        ordering: str | None = None,
 33        descending: bool = False,
 34    ) -> List[Correspondent]:
 35        """Return correspondents defined in paperless-ngx.
 36
 37        Args:
 38            ids: Return only correspondents whose ID is in this list.
 39            name_contains: Case-insensitive substring filter on name.
 40            name_exact: Case-insensitive exact match on name.
 41            page: Return only this specific page (1-based).
 42            page_size: Number of results per page.
 43            ordering: Field to sort by.
 44            descending: When ``True``, reverses the sort direction.
 45
 46        Returns:
 47            List of :class:`~easypaperless.models.correspondents.Correspondent` objects.
 48        """
 49        return cast(
 50            List[Correspondent],
 51            self._run(
 52                self._async_correspondents.list(
 53                    ids=ids,
 54                    name_contains=name_contains,
 55                    name_exact=name_exact,
 56                    page=page,
 57                    page_size=page_size,
 58                    ordering=ordering,
 59                    descending=descending,
 60                )
 61            ),
 62        )
 63
 64    def get(self, id: int) -> Correspondent:
 65        """Fetch a single correspondent by its ID.
 66
 67        Args:
 68            id: Numeric correspondent ID.
 69
 70        Returns:
 71            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
 72
 73        Raises:
 74            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
 75        """
 76        return cast(Correspondent, self._run(self._async_correspondents.get(id)))
 77
 78    def create(
 79        self,
 80        *,
 81        name: str,
 82        match: str | None | _Unset = UNSET,
 83        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 84        is_insensitive: bool = True,
 85        owner: int | None | _Unset = UNSET,
 86        set_permissions: SetPermissions | None = None,
 87    ) -> Correspondent:
 88        """Create a new correspondent.
 89
 90        Args:
 91            name: Correspondent name. Must be unique.
 92            match: Auto-matching pattern.
 93            matching_algorithm: Controls how ``match`` is applied.
 94            is_insensitive: When ``True``, ``match`` is case-insensitive.
 95                Defaults to ``True``, matching the paperless-ngx API default.
 96            owner: Numeric user ID to assign as owner.
 97            set_permissions: Explicit view/change permission sets.
 98
 99        Returns:
100            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
101        """
102        return cast(
103            Correspondent,
104            self._run(
105                self._async_correspondents.create(
106                    name=name,
107                    match=match,
108                    matching_algorithm=matching_algorithm,
109                    is_insensitive=is_insensitive,
110                    owner=owner,
111                    set_permissions=set_permissions,
112                )
113            ),
114        )
115
116    def update(
117        self,
118        id: int,
119        *,
120        name: str | None | _Unset = UNSET,
121        match: str | None | _Unset = UNSET,
122        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
123        is_insensitive: bool | None | _Unset = UNSET,
124        owner: int | None | _Unset = UNSET,
125        set_permissions: SetPermissions | None | _Unset = UNSET,
126    ) -> Correspondent:
127        """Partially update a correspondent (PATCH semantics).
128
129        Args:
130            id: Numeric ID of the correspondent to update.
131            name: Correspondent name.
132            match: Auto-matching pattern.
133            matching_algorithm: Controls how ``match`` is applied.
134            is_insensitive: When ``True``, ``match`` is case-insensitive.
135            owner: Numeric user ID to assign as owner.
136                Pass ``None`` to clear the owner.
137                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
138            set_permissions: Explicit view/change permission sets.
139                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
140
141        Returns:
142            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
143        """
144        return cast(
145            Correspondent,
146            self._run(
147                self._async_correspondents.update(
148                    id,
149                    name=name,
150                    match=match,
151                    matching_algorithm=matching_algorithm,
152                    is_insensitive=is_insensitive,
153                    owner=owner,
154                    set_permissions=set_permissions,
155                )
156            ),
157        )
158
159    def delete(self, id: int) -> None:
160        """Delete a correspondent.
161
162        Args:
163            id: Numeric ID of the correspondent to delete.
164
165        Raises:
166            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
167        """
168        self._run(self._async_correspondents.delete(id))
169
170    def bulk_delete(self, ids: List[int]) -> None:
171        """Permanently delete multiple correspondents in a single request.
172
173        Args:
174            ids: List of correspondent IDs to delete.
175        """
176        self._run(self._async_correspondents.bulk_delete(ids))
177
178    def bulk_set_permissions(
179        self,
180        ids: List[int],
181        *,
182        set_permissions: SetPermissions | None = None,
183        owner: int | None = None,
184        merge: bool = False,
185    ) -> None:
186        """Set permissions and/or owner on multiple correspondents.
187
188        Args:
189            ids: List of correspondent IDs to modify.
190            set_permissions: Explicit view/change permission sets.
191            owner: Numeric user ID to assign as owner.
192            merge: When ``True``, new permissions are merged with existing ones.
193        """
194        self._run(
195            self._async_correspondents.bulk_set_permissions(
196                ids, set_permissions=set_permissions, owner=owner, merge=merge
197            )
198        )

Sync accessor for correspondents: client.correspondents.

SyncCorrespondentsResource( async_correspondents: CorrespondentsResource, run: Any)
20    def __init__(self, async_correspondents: CorrespondentsResource, run: Any) -> None:
21        self._async_correspondents = async_correspondents
22        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.Correspondent]:
24    def list(
25        self,
26        *,
27        ids: List[int] | None = None,
28        name_contains: str | None = None,
29        name_exact: str | None = None,
30        page: int | None = None,
31        page_size: int | None = None,
32        ordering: str | None = None,
33        descending: bool = False,
34    ) -> List[Correspondent]:
35        """Return correspondents defined in paperless-ngx.
36
37        Args:
38            ids: Return only correspondents whose ID is in this list.
39            name_contains: Case-insensitive substring filter on name.
40            name_exact: Case-insensitive exact match on name.
41            page: Return only this specific page (1-based).
42            page_size: Number of results per page.
43            ordering: Field to sort by.
44            descending: When ``True``, reverses the sort direction.
45
46        Returns:
47            List of :class:`~easypaperless.models.correspondents.Correspondent` objects.
48        """
49        return cast(
50            List[Correspondent],
51            self._run(
52                self._async_correspondents.list(
53                    ids=ids,
54                    name_contains=name_contains,
55                    name_exact=name_exact,
56                    page=page,
57                    page_size=page_size,
58                    ordering=ordering,
59                    descending=descending,
60                )
61            ),
62        )

Return correspondents defined in paperless-ngx.

Arguments:
  • ids: Return only correspondents whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.correspondents.Correspondent objects.

def get(self, id: int) -> easypaperless.Correspondent:
64    def get(self, id: int) -> Correspondent:
65        """Fetch a single correspondent by its ID.
66
67        Args:
68            id: Numeric correspondent ID.
69
70        Returns:
71            The :class:`~easypaperless.models.correspondents.Correspondent` with the given ID.
72
73        Raises:
74            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
75        """
76        return cast(Correspondent, self._run(self._async_correspondents.get(id)))

Fetch a single correspondent by its ID.

Arguments:
  • id: Numeric correspondent ID.
Returns:

The ~easypaperless.models.correspondents.Correspondent with the given ID.

Raises:
def create( self, *, name: str, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.Correspondent:
 78    def create(
 79        self,
 80        *,
 81        name: str,
 82        match: str | None | _Unset = UNSET,
 83        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 84        is_insensitive: bool = True,
 85        owner: int | None | _Unset = UNSET,
 86        set_permissions: SetPermissions | None = None,
 87    ) -> Correspondent:
 88        """Create a new correspondent.
 89
 90        Args:
 91            name: Correspondent name. Must be unique.
 92            match: Auto-matching pattern.
 93            matching_algorithm: Controls how ``match`` is applied.
 94            is_insensitive: When ``True``, ``match`` is case-insensitive.
 95                Defaults to ``True``, matching the paperless-ngx API default.
 96            owner: Numeric user ID to assign as owner.
 97            set_permissions: Explicit view/change permission sets.
 98
 99        Returns:
100            The newly created :class:`~easypaperless.models.correspondents.Correspondent`.
101        """
102        return cast(
103            Correspondent,
104            self._run(
105                self._async_correspondents.create(
106                    name=name,
107                    match=match,
108                    matching_algorithm=matching_algorithm,
109                    is_insensitive=is_insensitive,
110                    owner=owner,
111                    set_permissions=set_permissions,
112                )
113            ),
114        )

Create a new correspondent.

Arguments:
  • name: Correspondent name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.correspondents.Correspondent.

def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Correspondent:
116    def update(
117        self,
118        id: int,
119        *,
120        name: str | None | _Unset = UNSET,
121        match: str | None | _Unset = UNSET,
122        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
123        is_insensitive: bool | None | _Unset = UNSET,
124        owner: int | None | _Unset = UNSET,
125        set_permissions: SetPermissions | None | _Unset = UNSET,
126    ) -> Correspondent:
127        """Partially update a correspondent (PATCH semantics).
128
129        Args:
130            id: Numeric ID of the correspondent to update.
131            name: Correspondent name.
132            match: Auto-matching pattern.
133            matching_algorithm: Controls how ``match`` is applied.
134            is_insensitive: When ``True``, ``match`` is case-insensitive.
135            owner: Numeric user ID to assign as owner.
136                Pass ``None`` to clear the owner.
137                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
138            set_permissions: Explicit view/change permission sets.
139                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
140
141        Returns:
142            The updated :class:`~easypaperless.models.correspondents.Correspondent`.
143        """
144        return cast(
145            Correspondent,
146            self._run(
147                self._async_correspondents.update(
148                    id,
149                    name=name,
150                    match=match,
151                    matching_algorithm=matching_algorithm,
152                    is_insensitive=is_insensitive,
153                    owner=owner,
154                    set_permissions=set_permissions,
155                )
156            ),
157        )

Partially update a correspondent (PATCH semantics).

Arguments:
  • id: Numeric ID of the correspondent to update.
  • name: Correspondent name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.correspondents.Correspondent.

def delete(self, id: int) -> None:
159    def delete(self, id: int) -> None:
160        """Delete a correspondent.
161
162        Args:
163            id: Numeric ID of the correspondent to delete.
164
165        Raises:
166            ~easypaperless.exceptions.NotFoundError: If no correspondent exists with that ID.
167        """
168        self._run(self._async_correspondents.delete(id))

Delete a correspondent.

Arguments:
  • id: Numeric ID of the correspondent to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
170    def bulk_delete(self, ids: List[int]) -> None:
171        """Permanently delete multiple correspondents in a single request.
172
173        Args:
174            ids: List of correspondent IDs to delete.
175        """
176        self._run(self._async_correspondents.bulk_delete(ids))

Permanently delete multiple correspondents in a single request.

Arguments:
  • ids: List of correspondent IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
178    def bulk_set_permissions(
179        self,
180        ids: List[int],
181        *,
182        set_permissions: SetPermissions | None = None,
183        owner: int | None = None,
184        merge: bool = False,
185    ) -> None:
186        """Set permissions and/or owner on multiple correspondents.
187
188        Args:
189            ids: List of correspondent IDs to modify.
190            set_permissions: Explicit view/change permission sets.
191            owner: Numeric user ID to assign as owner.
192            merge: When ``True``, new permissions are merged with existing ones.
193        """
194        self._run(
195            self._async_correspondents.bulk_set_permissions(
196                ids, set_permissions=set_permissions, owner=owner, merge=merge
197            )
198        )

Set permissions and/or owner on multiple correspondents.

Arguments:
  • ids: List of correspondent IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class SyncCustomFieldsResource:
 16class SyncCustomFieldsResource:
 17    """Sync accessor for custom fields: ``client.custom_fields``."""
 18
 19    def __init__(self, async_custom_fields: CustomFieldsResource, run: Any) -> None:
 20        self._async_custom_fields = async_custom_fields
 21        self._run = run
 22
 23    def list(
 24        self,
 25        *,
 26        name_contains: str | None = None,
 27        name_exact: str | None = None,
 28        page: int | None = None,
 29        page_size: int | None = None,
 30        ordering: str | None = None,
 31        descending: bool = False,
 32    ) -> List[CustomField]:
 33        """Return all custom fields defined in paperless-ngx.
 34
 35        Args:
 36            name_contains: Case-insensitive substring filter on name.
 37            name_exact: Case-insensitive exact match on name.
 38            page: Return only this specific page (1-based).
 39            page_size: Number of results per page.
 40            ordering: Field to sort by.
 41            descending: When ``True``, reverses the sort direction.
 42
 43        Returns:
 44            List of :class:`~easypaperless.models.custom_fields.CustomField` objects.
 45        """
 46        return cast(
 47            List[CustomField],
 48            self._run(
 49                self._async_custom_fields.list(
 50                    name_contains=name_contains,
 51                    name_exact=name_exact,
 52                    page=page,
 53                    page_size=page_size,
 54                    ordering=ordering,
 55                    descending=descending,
 56                )
 57            ),
 58        )
 59
 60    def get(self, id: int) -> CustomField:
 61        """Fetch a single custom field by its ID.
 62
 63        Args:
 64            id: Numeric custom-field ID.
 65
 66        Returns:
 67            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
 68
 69        Raises:
 70            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
 71        """
 72        return cast(CustomField, self._run(self._async_custom_fields.get(id)))
 73
 74    def create(
 75        self,
 76        *,
 77        name: str,
 78        data_type: str,
 79        extra_data: Any | None = None,
 80        owner: int | None | _Unset = UNSET,
 81        set_permissions: SetPermissions | None = None,
 82    ) -> CustomField:
 83        """Create a new custom field.
 84
 85        Args:
 86            name: Field name shown in the UI. Must be unique.
 87            data_type: Value type. One of ``"string"``, ``"boolean"``,
 88                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 89                ``"url"``, ``"documentlink"``, ``"select"``.
 90            extra_data: Additional configuration for the field type.
 91            owner: Numeric user ID to assign as owner.
 92            set_permissions: Explicit view/change permission sets.
 93
 94        Returns:
 95            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
 96        """
 97        return cast(
 98            CustomField,
 99            self._run(
100                self._async_custom_fields.create(
101                    name=name,
102                    data_type=data_type,
103                    extra_data=extra_data,
104                    owner=owner,
105                    set_permissions=set_permissions,
106                )
107            ),
108        )
109
110    def update(
111        self,
112        id: int,
113        *,
114        name: str | None | _Unset = UNSET,
115        data_type: str | None | _Unset = UNSET,
116        extra_data: Any | None | _Unset = UNSET,
117    ) -> CustomField:
118        """Partially update a custom field (PATCH semantics).
119
120        Args:
121            id: Numeric ID of the custom field to update.
122            name: Field name shown in the UI.
123            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
124                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
125            extra_data: Additional configuration for the field type.
126
127        Returns:
128            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
129        """
130        return cast(
131            CustomField,
132            self._run(
133                self._async_custom_fields.update(
134                    id,
135                    name=name,
136                    data_type=data_type,
137                    extra_data=extra_data,
138                )
139            ),
140        )
141
142    def delete(self, id: int) -> None:
143        """Delete a custom field.
144
145        Args:
146            id: Numeric ID of the custom field to delete.
147
148        Raises:
149            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
150        """
151        self._run(self._async_custom_fields.delete(id))

Sync accessor for custom fields: client.custom_fields.

SyncCustomFieldsResource( async_custom_fields: CustomFieldsResource, run: Any)
19    def __init__(self, async_custom_fields: CustomFieldsResource, run: Any) -> None:
20        self._async_custom_fields = async_custom_fields
21        self._run = run
def list( self, *, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.CustomField]:
23    def list(
24        self,
25        *,
26        name_contains: str | None = None,
27        name_exact: str | None = None,
28        page: int | None = None,
29        page_size: int | None = None,
30        ordering: str | None = None,
31        descending: bool = False,
32    ) -> List[CustomField]:
33        """Return all custom fields defined in paperless-ngx.
34
35        Args:
36            name_contains: Case-insensitive substring filter on name.
37            name_exact: Case-insensitive exact match on name.
38            page: Return only this specific page (1-based).
39            page_size: Number of results per page.
40            ordering: Field to sort by.
41            descending: When ``True``, reverses the sort direction.
42
43        Returns:
44            List of :class:`~easypaperless.models.custom_fields.CustomField` objects.
45        """
46        return cast(
47            List[CustomField],
48            self._run(
49                self._async_custom_fields.list(
50                    name_contains=name_contains,
51                    name_exact=name_exact,
52                    page=page,
53                    page_size=page_size,
54                    ordering=ordering,
55                    descending=descending,
56                )
57            ),
58        )

Return all custom fields defined in paperless-ngx.

Arguments:
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.custom_fields.CustomField objects.

def get(self, id: int) -> easypaperless.CustomField:
60    def get(self, id: int) -> CustomField:
61        """Fetch a single custom field by its ID.
62
63        Args:
64            id: Numeric custom-field ID.
65
66        Returns:
67            The :class:`~easypaperless.models.custom_fields.CustomField` with the given ID.
68
69        Raises:
70            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
71        """
72        return cast(CustomField, self._run(self._async_custom_fields.get(id)))

Fetch a single custom field by its ID.

Arguments:
  • id: Numeric custom-field ID.
Returns:

The ~easypaperless.models.custom_fields.CustomField with the given ID.

Raises:
def create( self, *, name: str, data_type: str, extra_data: typing.Any | None = None, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.CustomField:
 74    def create(
 75        self,
 76        *,
 77        name: str,
 78        data_type: str,
 79        extra_data: Any | None = None,
 80        owner: int | None | _Unset = UNSET,
 81        set_permissions: SetPermissions | None = None,
 82    ) -> CustomField:
 83        """Create a new custom field.
 84
 85        Args:
 86            name: Field name shown in the UI. Must be unique.
 87            data_type: Value type. One of ``"string"``, ``"boolean"``,
 88                ``"integer"``, ``"float"``, ``"monetary"``, ``"date"``,
 89                ``"url"``, ``"documentlink"``, ``"select"``.
 90            extra_data: Additional configuration for the field type.
 91            owner: Numeric user ID to assign as owner.
 92            set_permissions: Explicit view/change permission sets.
 93
 94        Returns:
 95            The newly created :class:`~easypaperless.models.custom_fields.CustomField`.
 96        """
 97        return cast(
 98            CustomField,
 99            self._run(
100                self._async_custom_fields.create(
101                    name=name,
102                    data_type=data_type,
103                    extra_data=extra_data,
104                    owner=owner,
105                    set_permissions=set_permissions,
106                )
107            ),
108        )

Create a new custom field.

Arguments:
  • name: Field name shown in the UI. Must be unique.
  • data_type: Value type. One of "string", "boolean", "integer", "float", "monetary", "date", "url", "documentlink", "select".
  • extra_data: Additional configuration for the field type.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.custom_fields.CustomField.

def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, data_type: str | None | easypaperless._internal.sentinel._Unset = UNSET, extra_data: typing.Any | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.CustomField:
110    def update(
111        self,
112        id: int,
113        *,
114        name: str | None | _Unset = UNSET,
115        data_type: str | None | _Unset = UNSET,
116        extra_data: Any | None | _Unset = UNSET,
117    ) -> CustomField:
118        """Partially update a custom field (PATCH semantics).
119
120        Args:
121            id: Numeric ID of the custom field to update.
122            name: Field name shown in the UI.
123            data_type: Value type (e.g. ``"string"``, ``"boolean"``, ``"integer"``).
124                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
125            extra_data: Additional configuration for the field type.
126
127        Returns:
128            The updated :class:`~easypaperless.models.custom_fields.CustomField`.
129        """
130        return cast(
131            CustomField,
132            self._run(
133                self._async_custom_fields.update(
134                    id,
135                    name=name,
136                    data_type=data_type,
137                    extra_data=extra_data,
138                )
139            ),
140        )

Partially update a custom field (PATCH semantics).

Arguments:
  • id: Numeric ID of the custom field to update.
  • name: Field name shown in the UI.
  • data_type: Value type (e.g. "string", "boolean", "integer"). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • extra_data: Additional configuration for the field type.
Returns:

The updated ~easypaperless.models.custom_fields.CustomField.

def delete(self, id: int) -> None:
142    def delete(self, id: int) -> None:
143        """Delete a custom field.
144
145        Args:
146            id: Numeric ID of the custom field to delete.
147
148        Raises:
149            ~easypaperless.exceptions.NotFoundError: If no custom field exists with that ID.
150        """
151        self._run(self._async_custom_fields.delete(id))

Delete a custom field.

Arguments:
  • id: Numeric ID of the custom field to delete.
Raises:
class SyncDocumentTypesResource:
 17class SyncDocumentTypesResource:
 18    """Sync accessor for document types: ``client.document_types``."""
 19
 20    def __init__(self, async_document_types: DocumentTypesResource, run: Any) -> None:
 21        self._async_document_types = async_document_types
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        ids: List[int] | None = None,
 28        name_contains: str | None = None,
 29        name_exact: str | None = None,
 30        page: int | None = None,
 31        page_size: int | None = None,
 32        ordering: str | None = None,
 33        descending: bool = False,
 34    ) -> List[DocumentType]:
 35        """Return document types defined in paperless-ngx.
 36
 37        Args:
 38            ids: Return only document types whose ID is in this list.
 39            name_contains: Case-insensitive substring filter on name.
 40            name_exact: Case-insensitive exact match on name.
 41            page: Return only this specific page (1-based).
 42            page_size: Number of results per page.
 43            ordering: Field to sort by.
 44            descending: When ``True``, reverses the sort direction.
 45
 46        Returns:
 47            List of :class:`~easypaperless.models.document_types.DocumentType` objects.
 48        """
 49        return cast(
 50            List[DocumentType],
 51            self._run(
 52                self._async_document_types.list(
 53                    ids=ids,
 54                    name_contains=name_contains,
 55                    name_exact=name_exact,
 56                    page=page,
 57                    page_size=page_size,
 58                    ordering=ordering,
 59                    descending=descending,
 60                )
 61            ),
 62        )
 63
 64    def get(self, id: int) -> DocumentType:
 65        """Fetch a single document type by its ID.
 66
 67        Args:
 68            id: Numeric document-type ID.
 69
 70        Returns:
 71            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
 72
 73        Raises:
 74            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
 75        """
 76        return cast(DocumentType, self._run(self._async_document_types.get(id)))
 77
 78    def create(
 79        self,
 80        *,
 81        name: str,
 82        match: str | None | _Unset = UNSET,
 83        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 84        is_insensitive: bool = True,
 85        owner: int | None | _Unset = UNSET,
 86        set_permissions: SetPermissions | None = None,
 87    ) -> DocumentType:
 88        """Create a new document type.
 89
 90        Args:
 91            name: Document-type name. Must be unique.
 92            match: Auto-matching pattern.
 93            matching_algorithm: Controls how ``match`` is applied.
 94            is_insensitive: When ``True``, ``match`` is case-insensitive.
 95                Defaults to ``True``, matching the paperless-ngx API default.
 96            owner: Numeric user ID to assign as owner.
 97            set_permissions: Explicit view/change permission sets.
 98
 99        Returns:
100            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
101        """
102        return cast(
103            DocumentType,
104            self._run(
105                self._async_document_types.create(
106                    name=name,
107                    match=match,
108                    matching_algorithm=matching_algorithm,
109                    is_insensitive=is_insensitive,
110                    owner=owner,
111                    set_permissions=set_permissions,
112                )
113            ),
114        )
115
116    def update(
117        self,
118        id: int,
119        *,
120        name: str | None | _Unset = UNSET,
121        match: str | None | _Unset = UNSET,
122        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
123        is_insensitive: bool | None | _Unset = UNSET,
124        owner: int | None | _Unset = UNSET,
125        set_permissions: SetPermissions | None | _Unset = UNSET,
126    ) -> DocumentType:
127        """Partially update a document type (PATCH semantics).
128
129        Args:
130            id: Numeric ID of the document type to update.
131            name: Document-type name.
132            match: Auto-matching pattern.
133            matching_algorithm: Controls how ``match`` is applied.
134            is_insensitive: When ``True``, ``match`` is case-insensitive.
135            owner: Numeric user ID to assign as owner.
136                Pass ``None`` to clear the owner.
137                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
138            set_permissions: Explicit view/change permission sets.
139                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
140
141        Returns:
142            The updated :class:`~easypaperless.models.document_types.DocumentType`.
143        """
144        return cast(
145            DocumentType,
146            self._run(
147                self._async_document_types.update(
148                    id,
149                    name=name,
150                    match=match,
151                    matching_algorithm=matching_algorithm,
152                    is_insensitive=is_insensitive,
153                    owner=owner,
154                    set_permissions=set_permissions,
155                )
156            ),
157        )
158
159    def delete(self, id: int) -> None:
160        """Delete a document type.
161
162        Args:
163            id: Numeric ID of the document type to delete.
164
165        Raises:
166            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
167        """
168        self._run(self._async_document_types.delete(id))
169
170    def bulk_delete(self, ids: List[int]) -> None:
171        """Permanently delete multiple document types in a single request.
172
173        Args:
174            ids: List of document type IDs to delete.
175        """
176        self._run(self._async_document_types.bulk_delete(ids))
177
178    def bulk_set_permissions(
179        self,
180        ids: List[int],
181        *,
182        set_permissions: SetPermissions | None = None,
183        owner: int | None = None,
184        merge: bool = False,
185    ) -> None:
186        """Set permissions and/or owner on multiple document types.
187
188        Args:
189            ids: List of document type IDs to modify.
190            set_permissions: Explicit view/change permission sets.
191            owner: Numeric user ID to assign as owner.
192            merge: When ``True``, new permissions are merged with existing ones.
193        """
194        self._run(
195            self._async_document_types.bulk_set_permissions(
196                ids, set_permissions=set_permissions, owner=owner, merge=merge
197            )
198        )

Sync accessor for document types: client.document_types.

SyncDocumentTypesResource( async_document_types: DocumentTypesResource, run: Any)
20    def __init__(self, async_document_types: DocumentTypesResource, run: Any) -> None:
21        self._async_document_types = async_document_types
22        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.DocumentType]:
24    def list(
25        self,
26        *,
27        ids: List[int] | None = None,
28        name_contains: str | None = None,
29        name_exact: str | None = None,
30        page: int | None = None,
31        page_size: int | None = None,
32        ordering: str | None = None,
33        descending: bool = False,
34    ) -> List[DocumentType]:
35        """Return document types defined in paperless-ngx.
36
37        Args:
38            ids: Return only document types whose ID is in this list.
39            name_contains: Case-insensitive substring filter on name.
40            name_exact: Case-insensitive exact match on name.
41            page: Return only this specific page (1-based).
42            page_size: Number of results per page.
43            ordering: Field to sort by.
44            descending: When ``True``, reverses the sort direction.
45
46        Returns:
47            List of :class:`~easypaperless.models.document_types.DocumentType` objects.
48        """
49        return cast(
50            List[DocumentType],
51            self._run(
52                self._async_document_types.list(
53                    ids=ids,
54                    name_contains=name_contains,
55                    name_exact=name_exact,
56                    page=page,
57                    page_size=page_size,
58                    ordering=ordering,
59                    descending=descending,
60                )
61            ),
62        )

Return document types defined in paperless-ngx.

Arguments:
  • ids: Return only document types whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.document_types.DocumentType objects.

def get(self, id: int) -> easypaperless.DocumentType:
64    def get(self, id: int) -> DocumentType:
65        """Fetch a single document type by its ID.
66
67        Args:
68            id: Numeric document-type ID.
69
70        Returns:
71            The :class:`~easypaperless.models.document_types.DocumentType` with the given ID.
72
73        Raises:
74            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
75        """
76        return cast(DocumentType, self._run(self._async_document_types.get(id)))

Fetch a single document type by its ID.

Arguments:
  • id: Numeric document-type ID.
Returns:

The ~easypaperless.models.document_types.DocumentType with the given ID.

Raises:
def create( self, *, name: str, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.DocumentType:
 78    def create(
 79        self,
 80        *,
 81        name: str,
 82        match: str | None | _Unset = UNSET,
 83        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 84        is_insensitive: bool = True,
 85        owner: int | None | _Unset = UNSET,
 86        set_permissions: SetPermissions | None = None,
 87    ) -> DocumentType:
 88        """Create a new document type.
 89
 90        Args:
 91            name: Document-type name. Must be unique.
 92            match: Auto-matching pattern.
 93            matching_algorithm: Controls how ``match`` is applied.
 94            is_insensitive: When ``True``, ``match`` is case-insensitive.
 95                Defaults to ``True``, matching the paperless-ngx API default.
 96            owner: Numeric user ID to assign as owner.
 97            set_permissions: Explicit view/change permission sets.
 98
 99        Returns:
100            The newly created :class:`~easypaperless.models.document_types.DocumentType`.
101        """
102        return cast(
103            DocumentType,
104            self._run(
105                self._async_document_types.create(
106                    name=name,
107                    match=match,
108                    matching_algorithm=matching_algorithm,
109                    is_insensitive=is_insensitive,
110                    owner=owner,
111                    set_permissions=set_permissions,
112                )
113            ),
114        )

Create a new document type.

Arguments:
  • name: Document-type name. Must be unique.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.document_types.DocumentType.

def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.DocumentType:
116    def update(
117        self,
118        id: int,
119        *,
120        name: str | None | _Unset = UNSET,
121        match: str | None | _Unset = UNSET,
122        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
123        is_insensitive: bool | None | _Unset = UNSET,
124        owner: int | None | _Unset = UNSET,
125        set_permissions: SetPermissions | None | _Unset = UNSET,
126    ) -> DocumentType:
127        """Partially update a document type (PATCH semantics).
128
129        Args:
130            id: Numeric ID of the document type to update.
131            name: Document-type name.
132            match: Auto-matching pattern.
133            matching_algorithm: Controls how ``match`` is applied.
134            is_insensitive: When ``True``, ``match`` is case-insensitive.
135            owner: Numeric user ID to assign as owner.
136                Pass ``None`` to clear the owner.
137                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
138            set_permissions: Explicit view/change permission sets.
139                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
140
141        Returns:
142            The updated :class:`~easypaperless.models.document_types.DocumentType`.
143        """
144        return cast(
145            DocumentType,
146            self._run(
147                self._async_document_types.update(
148                    id,
149                    name=name,
150                    match=match,
151                    matching_algorithm=matching_algorithm,
152                    is_insensitive=is_insensitive,
153                    owner=owner,
154                    set_permissions=set_permissions,
155                )
156            ),
157        )

Partially update a document type (PATCH semantics).

Arguments:
  • id: Numeric ID of the document type to update.
  • name: Document-type name.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.document_types.DocumentType.

def delete(self, id: int) -> None:
159    def delete(self, id: int) -> None:
160        """Delete a document type.
161
162        Args:
163            id: Numeric ID of the document type to delete.
164
165        Raises:
166            ~easypaperless.exceptions.NotFoundError: If no document type exists with that ID.
167        """
168        self._run(self._async_document_types.delete(id))

Delete a document type.

Arguments:
  • id: Numeric ID of the document type to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
170    def bulk_delete(self, ids: List[int]) -> None:
171        """Permanently delete multiple document types in a single request.
172
173        Args:
174            ids: List of document type IDs to delete.
175        """
176        self._run(self._async_document_types.bulk_delete(ids))

Permanently delete multiple document types in a single request.

Arguments:
  • ids: List of document type IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
178    def bulk_set_permissions(
179        self,
180        ids: List[int],
181        *,
182        set_permissions: SetPermissions | None = None,
183        owner: int | None = None,
184        merge: bool = False,
185    ) -> None:
186        """Set permissions and/or owner on multiple document types.
187
188        Args:
189            ids: List of document type IDs to modify.
190            set_permissions: Explicit view/change permission sets.
191            owner: Numeric user ID to assign as owner.
192            merge: When ``True``, new permissions are merged with existing ones.
193        """
194        self._run(
195            self._async_document_types.bulk_set_permissions(
196                ids, set_permissions=set_permissions, owner=owner, merge=merge
197            )
198        )

Set permissions and/or owner on multiple document types.

Arguments:
  • ids: List of document type IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class SyncDocumentsResource:
 72class SyncDocumentsResource:
 73    """Sync accessor for documents: ``client.documents``."""
 74
 75    def __init__(self, async_documents: DocumentsResource, run: Any) -> None:
 76        self._async_documents = async_documents
 77        self._run = run
 78        self.notes = SyncNotesResource(async_documents.notes, run)
 79
 80    def get(self, id: int, *, include_metadata: bool = False) -> Document:
 81        """Fetch a single document by its ID.
 82
 83        Args:
 84            id: Numeric paperless-ngx document ID.
 85            include_metadata: When ``True``, the extended file-level metadata
 86                is fetched concurrently and attached to the document.
 87                Default: ``False``.
 88
 89        Returns:
 90            The :class:`~easypaperless.models.documents.Document` with the
 91            given ID.
 92
 93        Raises:
 94            ~easypaperless.exceptions.NotFoundError: If no document exists
 95                with that ID.
 96        """
 97        return cast(
 98            Document, self._run(self._async_documents.get(id, include_metadata=include_metadata))
 99        )
100
101    def get_metadata(self, id: int) -> DocumentMetadata:
102        """Fetch the extended file-level metadata for a document.
103
104        Args:
105            id: Numeric paperless-ngx document ID.
106
107        Returns:
108            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
109
110        Raises:
111            ~easypaperless.exceptions.NotFoundError: If no document exists
112                with that ID.
113        """
114        return cast(DocumentMetadata, self._run(self._async_documents.get_metadata(id)))
115
116    def list(
117        self,
118        *,
119        search: str | None = None,
120        search_mode: str = "title_or_content",
121        ids: List[int] | None = None,
122        tags: List[int | str] | None = None,
123        any_tags: List[int | str] | None = None,
124        exclude_tags: List[int | str] | None = None,
125        correspondent: int | str | None | _Unset = UNSET,
126        any_correspondent: List[int | str] | None = None,
127        exclude_correspondents: List[int | str] | None = None,
128        document_type: int | str | None | _Unset = UNSET,
129        document_type_name_contains: str | None = None,
130        document_type_name_exact: str | None = None,
131        any_document_type: List[int | str] | None = None,
132        exclude_document_types: List[int | str] | None = None,
133        storage_path: int | str | None | _Unset = UNSET,
134        any_storage_paths: List[int | str] | None = None,
135        exclude_storage_paths: List[int | str] | None = None,
136        owner: int | None | _Unset = UNSET,
137        exclude_owners: List[int] | None = None,
138        custom_fields: List[int | str] | None = None,
139        any_custom_fields: List[int | str] | None = None,
140        exclude_custom_fields: List[int | str] | None = None,
141        custom_field_query: List[Any] | None = None,
142        archive_serial_number: int | None | _Unset = UNSET,
143        archive_serial_number_from: int | None = None,
144        archive_serial_number_till: int | None = None,
145        created_after: date | str | None = None,
146        created_before: date | str | None = None,
147        added_after: date | datetime | str | None = None,
148        added_from: date | datetime | str | None = None,
149        added_before: date | datetime | str | None = None,
150        added_until: date | datetime | str | None = None,
151        modified_after: date | datetime | str | None = None,
152        modified_from: date | datetime | str | None = None,
153        modified_before: date | datetime | str | None = None,
154        modified_until: date | datetime | str | None = None,
155        checksum: str | None = None,
156        page_size: int = 25,
157        page: int | None = None,
158        ordering: str | None = None,
159        descending: bool = False,
160        max_results: int | None = None,
161        on_page: Callable[[int, int | None], None] | None = None,
162    ) -> List[Document]:
163        """Return a filtered list of documents.
164
165        All tag, correspondent, document-type, storage-path, and custom-field
166        parameters accept either integer IDs or string names.
167
168        Args:
169            search: Search string.  Behaviour depends on ``search_mode``.
170            search_mode: How ``search`` is applied.  One of:
171                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
172                ``"original_filename"``.
173            ids: Return only documents whose ID is in this list.
174            tags: Documents must have **all** of these tags (AND semantics).
175            any_tags: Documents must have **at least one** of these tags.
176            exclude_tags: Documents must have **none** of these tags.
177            correspondent: Filter to documents assigned to this correspondent.
178                Pass ``None`` to return only documents with no correspondent set.
179            any_correspondent: Filter to documents assigned to any of these.
180            exclude_correspondents: Exclude documents assigned to any of these.
181            document_type: Filter to documents of exactly this type.
182                Pass ``None`` to return only documents with no document type set.
183            document_type_name_contains: Case-insensitive substring filter on document type name.
184            document_type_name_exact: Case-insensitive exact match on document type name.
185            any_document_type: Filter to documents whose type is any of these.
186            exclude_document_types: Exclude documents whose type is any of these.
187            storage_path: Filter to documents assigned to this storage path.
188                Pass ``None`` to return only documents with no storage path set.
189            any_storage_paths: Filter to documents assigned to any of these paths.
190            exclude_storage_paths: Exclude documents assigned to any of these paths.
191            owner: Filter to documents owned by this user ID.
192                Pass ``None`` to return only documents with no owner set.
193            exclude_owners: Exclude documents owned by any of these user IDs.
194            custom_fields: Documents must have **all** of these custom fields set.
195            any_custom_fields: Documents must have **at least one** of these fields.
196            exclude_custom_fields: Documents must have **none** of these fields.
197            custom_field_query: Filter documents by custom field values.
198            archive_serial_number: Filter by exact archive serial number.
199                Pass ``None`` to return only documents with no ASN set.
200            archive_serial_number_from: Filter by ASN >= this value.
201            archive_serial_number_till: Filter by ASN <= this value.
202            created_after: Only documents created after this date.
203            created_before: Only documents created before this date.
204            added_after: Only documents added after this date/time.
205            added_from: Only documents added on or after this date/time.
206            added_before: Only documents added before this date/time.
207            added_until: Only documents added on or before this date/time.
208            modified_after: Only documents modified after this date/time.
209            modified_from: Only documents modified on or after this date/time.
210            modified_before: Only documents modified before this date/time.
211            modified_until: Only documents modified on or before this date/time.
212            checksum: MD5 checksum of the original file (exact match).
213            page_size: Number of results per API page.  Default: ``25``.
214            page: Return only this specific page (1-based).
215            ordering: Field name to sort by.
216            descending: When ``True``, reverses the sort direction.
217            max_results: Stop after collecting this many documents.
218            on_page: Callback invoked after each page fetch.
219
220        Returns:
221            List of :class:`~easypaperless.models.documents.Document` objects.
222        """
223        return cast(
224            List[Document],
225            self._run(
226                self._async_documents.list(
227                    search=search,
228                    search_mode=search_mode,
229                    ids=ids,
230                    tags=tags,
231                    any_tags=any_tags,
232                    exclude_tags=exclude_tags,
233                    correspondent=correspondent,
234                    any_correspondent=any_correspondent,
235                    exclude_correspondents=exclude_correspondents,
236                    document_type=document_type,
237                    document_type_name_contains=document_type_name_contains,
238                    document_type_name_exact=document_type_name_exact,
239                    any_document_type=any_document_type,
240                    exclude_document_types=exclude_document_types,
241                    storage_path=storage_path,
242                    any_storage_paths=any_storage_paths,
243                    exclude_storage_paths=exclude_storage_paths,
244                    owner=owner,
245                    exclude_owners=exclude_owners,
246                    custom_fields=custom_fields,
247                    any_custom_fields=any_custom_fields,
248                    exclude_custom_fields=exclude_custom_fields,
249                    custom_field_query=custom_field_query,
250                    archive_serial_number=archive_serial_number,
251                    archive_serial_number_from=archive_serial_number_from,
252                    archive_serial_number_till=archive_serial_number_till,
253                    created_after=created_after,
254                    created_before=created_before,
255                    added_after=added_after,
256                    added_from=added_from,
257                    added_before=added_before,
258                    added_until=added_until,
259                    modified_after=modified_after,
260                    modified_from=modified_from,
261                    modified_before=modified_before,
262                    modified_until=modified_until,
263                    checksum=checksum,
264                    page_size=page_size,
265                    page=page,
266                    ordering=ordering,
267                    descending=descending,
268                    max_results=max_results,
269                    on_page=on_page,
270                )
271            ),
272        )
273
274    def update(
275        self,
276        id: int,
277        *,
278        title: str | None | _Unset = UNSET,
279        content: str | None | _Unset = UNSET,
280        created: date | str | None | _Unset = UNSET,
281        correspondent: int | str | None | _Unset = UNSET,
282        document_type: int | str | None | _Unset = UNSET,
283        storage_path: int | str | None | _Unset = UNSET,
284        tags: List[int | str] | None | _Unset = UNSET,
285        archive_serial_number: int | None | _Unset = UNSET,
286        custom_fields: List[dict[str, Any]] | None | _Unset = UNSET,
287        owner: int | None | _Unset = UNSET,
288        set_permissions: SetPermissions | None | _Unset = UNSET,
289        remove_inbox_tags: bool | None | _Unset = UNSET,
290    ) -> Document:
291        """Partially update a document (PATCH semantics).
292
293        Args:
294            id: Numeric ID of the document to update.
295            title: New document title.
296            content: OCR text content of the document.
297            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
298                :class:`~datetime.date` object.
299            correspondent: Correspondent to assign, as an ID or name.
300                Pass ``None`` to clear the correspondent.
301            document_type: Document type to assign, as an ID or name.
302                Pass ``None`` to clear the document type.
303            storage_path: Storage path to assign, as an ID or name.
304                Pass ``None`` to clear the storage path.
305            tags: Full replacement list of tags (IDs or names).
306            archive_serial_number: Archive serial number to assign.
307                Pass ``None`` to clear the archive serial number.
308            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
309            owner: Numeric user ID to assign as document owner.
310                Pass ``None`` to clear the owner.
311            set_permissions: Explicit view/change permission sets.
312            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
313
314        Returns:
315            The updated :class:`~easypaperless.models.documents.Document`.
316        """
317        return cast(
318            Document,
319            self._run(
320                self._async_documents.update(
321                    id,
322                    title=title,
323                    content=content,
324                    created=created,
325                    correspondent=correspondent,
326                    document_type=document_type,
327                    storage_path=storage_path,
328                    tags=tags,
329                    archive_serial_number=archive_serial_number,
330                    custom_fields=custom_fields,
331                    owner=owner,
332                    set_permissions=set_permissions,
333                    remove_inbox_tags=remove_inbox_tags,
334                )
335            ),
336        )
337
338    def delete(self, id: int) -> None:
339        """Permanently delete a document.
340
341        Args:
342            id: Numeric ID of the document to delete.
343
344        Raises:
345            ~easypaperless.exceptions.NotFoundError: If no document exists
346                with that ID.
347        """
348        self._run(self._async_documents.delete(id))
349
350    def download(self, id: int, *, original: bool = False) -> bytes:
351        """Download the binary content of a document.
352
353        Args:
354            id: Numeric ID of the document to download.
355            original: If ``False`` *(default)*, returns the archived PDF.
356                If ``True``, returns the original uploaded file.
357
358        Returns:
359            Raw file bytes.
360        """
361        return cast(bytes, self._run(self._async_documents.download(id, original=original)))
362
363    def upload(
364        self,
365        file: str | Path,
366        *,
367        title: str | None = None,
368        created: date | str | None = None,
369        correspondent: int | str | None | _Unset = UNSET,
370        document_type: int | str | None | _Unset = UNSET,
371        storage_path: int | str | None | _Unset = UNSET,
372        tags: List[int | str] | None = None,
373        archive_serial_number: int | None | _Unset = UNSET,
374        custom_fields: List[dict[str, Any]] | None = None,
375        wait: bool = False,
376        poll_interval: float | None = None,
377        poll_timeout: float | None = None,
378    ) -> str | Document:
379        """Upload a document to paperless-ngx.
380
381        Args:
382            file: Path to the file to upload.
383            title: Title to assign to the document.
384            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
385                :class:`~datetime.date` object.
386            correspondent: Correspondent to assign, as an ID or name.
387            document_type: Document type to assign, as an ID or name.
388            storage_path: Storage path to assign, as an ID or name.
389            tags: Tags to assign, as IDs or names.
390            archive_serial_number: Archive serial number to assign.
391            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
392            wait: If ``False`` *(default)*, returns immediately with the task ID.
393                If ``True``, polls until processing completes.
394            poll_interval: Override the client-level ``poll_interval`` (in seconds).
395            poll_timeout: Override the client-level ``poll_timeout`` (in seconds).
396
397        Returns:
398            The Celery task ID string when ``wait=False``, or the fully
399            processed :class:`~easypaperless.models.documents.Document`
400            when ``wait=True``.
401
402        Raises:
403            ~easypaperless.exceptions.UploadError: If processing fails.
404            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
405        """
406        return cast(
407            str | Document,
408            self._run(
409                self._async_documents.upload(
410                    file,
411                    title=title,
412                    created=created,
413                    correspondent=correspondent,
414                    document_type=document_type,
415                    storage_path=storage_path,
416                    tags=tags,
417                    archive_serial_number=archive_serial_number,
418                    custom_fields=custom_fields,
419                    wait=wait,
420                    poll_interval=poll_interval,
421                    poll_timeout=poll_timeout,
422                )
423            ),
424        )
425
426    def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
427        """Add a tag to multiple documents in a single request.
428
429        Args:
430            document_ids: List of document IDs to tag.
431            tag: Tag to add, as an ID or name.
432        """
433        self._run(self._async_documents.bulk_add_tag(document_ids, tag))
434
435    def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
436        """Remove a tag from multiple documents in a single request.
437
438        Args:
439            document_ids: List of document IDs to un-tag.
440            tag: Tag to remove, as an ID or name.
441        """
442        self._run(self._async_documents.bulk_remove_tag(document_ids, tag))
443
444    def bulk_modify_tags(
445        self,
446        document_ids: List[int],
447        *,
448        add_tags: List[int | str] | None = None,
449        remove_tags: List[int | str] | None = None,
450    ) -> None:
451        """Add and/or remove tags on multiple documents atomically.
452
453        Args:
454            document_ids: List of document IDs to modify.
455            add_tags: Tags to add, as IDs or names.
456            remove_tags: Tags to remove, as IDs or names.
457        """
458        self._run(
459            self._async_documents.bulk_modify_tags(
460                document_ids, add_tags=add_tags, remove_tags=remove_tags
461            )
462        )
463
464    def bulk_delete(self, document_ids: List[int]) -> None:
465        """Permanently delete multiple documents in a single request.
466
467        Args:
468            document_ids: List of document IDs to delete.
469        """
470        self._run(self._async_documents.bulk_delete(document_ids))
471
472    def bulk_set_correspondent(
473        self, document_ids: List[int], correspondent: int | str | None
474    ) -> None:
475        """Assign a correspondent to multiple documents in a single request.
476
477        Args:
478            document_ids: List of document IDs to modify.
479            correspondent: Correspondent to assign, as an ID or name.
480                Pass ``None`` to clear.
481        """
482        self._run(self._async_documents.bulk_set_correspondent(document_ids, correspondent))
483
484    def bulk_set_document_type(
485        self, document_ids: List[int], document_type: int | str | None
486    ) -> None:
487        """Assign a document type to multiple documents in a single request.
488
489        Args:
490            document_ids: List of document IDs to modify.
491            document_type: Document type to assign, as an ID or name.
492                Pass ``None`` to clear.
493        """
494        self._run(self._async_documents.bulk_set_document_type(document_ids, document_type))
495
496    def bulk_set_storage_path(
497        self, document_ids: List[int], storage_path: int | str | None
498    ) -> None:
499        """Assign a storage path to multiple documents in a single request.
500
501        Args:
502            document_ids: List of document IDs to modify.
503            storage_path: Storage path to assign, as an ID or name.
504                Pass ``None`` to clear.
505        """
506        self._run(self._async_documents.bulk_set_storage_path(document_ids, storage_path))
507
508    def bulk_modify_custom_fields(
509        self,
510        document_ids: List[int],
511        *,
512        add_fields: List[dict[str, Any]] | None = None,
513        remove_fields: List[int] | None = None,
514    ) -> None:
515        """Add and/or remove custom field values on multiple documents.
516
517        Args:
518            document_ids: List of document IDs to modify.
519            add_fields: Custom-field value dicts to add.
520            remove_fields: Custom-field IDs whose values should be removed.
521        """
522        self._run(
523            self._async_documents.bulk_modify_custom_fields(
524                document_ids, add_fields=add_fields, remove_fields=remove_fields
525            )
526        )
527
528    def bulk_set_permissions(
529        self,
530        document_ids: List[int],
531        *,
532        set_permissions: SetPermissions | None = None,
533        owner: int | None = None,
534        merge: bool = False,
535    ) -> None:
536        """Set permissions and/or owner on multiple documents.
537
538        Args:
539            document_ids: List of document IDs to modify.
540            set_permissions: Explicit view/change permission sets.
541            owner: Numeric user ID to assign as document owner.
542            merge: When ``True``, new permissions are merged with existing ones.
543        """
544        self._run(
545            self._async_documents.bulk_set_permissions(
546                document_ids,
547                set_permissions=set_permissions,
548                owner=owner,
549                merge=merge,
550            )
551        )

Sync accessor for documents: client.documents.

SyncDocumentsResource( async_documents: DocumentsResource, run: Any)
75    def __init__(self, async_documents: DocumentsResource, run: Any) -> None:
76        self._async_documents = async_documents
77        self._run = run
78        self.notes = SyncNotesResource(async_documents.notes, run)
notes
def get( self, id: int, *, include_metadata: bool = False) -> easypaperless.Document:
80    def get(self, id: int, *, include_metadata: bool = False) -> Document:
81        """Fetch a single document by its ID.
82
83        Args:
84            id: Numeric paperless-ngx document ID.
85            include_metadata: When ``True``, the extended file-level metadata
86                is fetched concurrently and attached to the document.
87                Default: ``False``.
88
89        Returns:
90            The :class:`~easypaperless.models.documents.Document` with the
91            given ID.
92
93        Raises:
94            ~easypaperless.exceptions.NotFoundError: If no document exists
95                with that ID.
96        """
97        return cast(
98            Document, self._run(self._async_documents.get(id, include_metadata=include_metadata))
99        )

Fetch a single document by its ID.

Arguments:
  • id: Numeric paperless-ngx document ID.
  • include_metadata: When True, the extended file-level metadata is fetched concurrently and attached to the document. Default: False.
Returns:

The ~easypaperless.models.documents.Document with the given ID.

Raises:
def get_metadata(self, id: int) -> easypaperless.DocumentMetadata:
101    def get_metadata(self, id: int) -> DocumentMetadata:
102        """Fetch the extended file-level metadata for a document.
103
104        Args:
105            id: Numeric paperless-ngx document ID.
106
107        Returns:
108            A :class:`~easypaperless.models.documents.DocumentMetadata` instance.
109
110        Raises:
111            ~easypaperless.exceptions.NotFoundError: If no document exists
112                with that ID.
113        """
114        return cast(DocumentMetadata, self._run(self._async_documents.get_metadata(id)))

Fetch the extended file-level metadata for a document.

Arguments:
  • id: Numeric paperless-ngx document ID.
Returns:

A ~easypaperless.models.documents.DocumentMetadata instance.

Raises:
def list( self, *, search: str | None = None, search_mode: str = 'title_or_content', ids: Optional[List[int]] = None, tags: Optional[List[Union[str, int]]] = None, any_tags: Optional[List[Union[str, int]]] = None, exclude_tags: Optional[List[Union[str, int]]] = None, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, any_correspondent: Optional[List[Union[str, int]]] = None, exclude_correspondents: Optional[List[Union[str, int]]] = None, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type_name_contains: str | None = None, document_type_name_exact: str | None = None, any_document_type: Optional[List[Union[str, int]]] = None, exclude_document_types: Optional[List[Union[str, int]]] = None, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, any_storage_paths: Optional[List[Union[str, int]]] = None, exclude_storage_paths: Optional[List[Union[str, int]]] = None, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, exclude_owners: Optional[List[int]] = None, custom_fields: Optional[List[Union[str, int]]] = None, any_custom_fields: Optional[List[Union[str, int]]] = None, exclude_custom_fields: Optional[List[Union[str, int]]] = None, custom_field_query: Optional[List[Any]] = None, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, archive_serial_number_from: int | None = None, archive_serial_number_till: int | None = None, created_after: datetime.date | str | None = None, created_before: datetime.date | str | None = None, added_after: datetime.date | datetime.datetime | str | None = None, added_from: datetime.date | datetime.datetime | str | None = None, added_before: datetime.date | datetime.datetime | str | None = None, added_until: datetime.date | datetime.datetime | str | None = None, modified_after: datetime.date | datetime.datetime | str | None = None, modified_from: datetime.date | datetime.datetime | str | None = None, modified_before: datetime.date | datetime.datetime | str | None = None, modified_until: datetime.date | datetime.datetime | str | None = None, checksum: str | None = None, page_size: int = 25, page: int | None = None, ordering: str | None = None, descending: bool = False, max_results: int | None = None, on_page: Callable[[int, int | None], None] | None = None) -> List[easypaperless.Document]:
116    def list(
117        self,
118        *,
119        search: str | None = None,
120        search_mode: str = "title_or_content",
121        ids: List[int] | None = None,
122        tags: List[int | str] | None = None,
123        any_tags: List[int | str] | None = None,
124        exclude_tags: List[int | str] | None = None,
125        correspondent: int | str | None | _Unset = UNSET,
126        any_correspondent: List[int | str] | None = None,
127        exclude_correspondents: List[int | str] | None = None,
128        document_type: int | str | None | _Unset = UNSET,
129        document_type_name_contains: str | None = None,
130        document_type_name_exact: str | None = None,
131        any_document_type: List[int | str] | None = None,
132        exclude_document_types: List[int | str] | None = None,
133        storage_path: int | str | None | _Unset = UNSET,
134        any_storage_paths: List[int | str] | None = None,
135        exclude_storage_paths: List[int | str] | None = None,
136        owner: int | None | _Unset = UNSET,
137        exclude_owners: List[int] | None = None,
138        custom_fields: List[int | str] | None = None,
139        any_custom_fields: List[int | str] | None = None,
140        exclude_custom_fields: List[int | str] | None = None,
141        custom_field_query: List[Any] | None = None,
142        archive_serial_number: int | None | _Unset = UNSET,
143        archive_serial_number_from: int | None = None,
144        archive_serial_number_till: int | None = None,
145        created_after: date | str | None = None,
146        created_before: date | str | None = None,
147        added_after: date | datetime | str | None = None,
148        added_from: date | datetime | str | None = None,
149        added_before: date | datetime | str | None = None,
150        added_until: date | datetime | str | None = None,
151        modified_after: date | datetime | str | None = None,
152        modified_from: date | datetime | str | None = None,
153        modified_before: date | datetime | str | None = None,
154        modified_until: date | datetime | str | None = None,
155        checksum: str | None = None,
156        page_size: int = 25,
157        page: int | None = None,
158        ordering: str | None = None,
159        descending: bool = False,
160        max_results: int | None = None,
161        on_page: Callable[[int, int | None], None] | None = None,
162    ) -> List[Document]:
163        """Return a filtered list of documents.
164
165        All tag, correspondent, document-type, storage-path, and custom-field
166        parameters accept either integer IDs or string names.
167
168        Args:
169            search: Search string.  Behaviour depends on ``search_mode``.
170            search_mode: How ``search`` is applied.  One of:
171                ``"title_or_content"`` *(default)*, ``"title"``, ``"query"``,
172                ``"original_filename"``.
173            ids: Return only documents whose ID is in this list.
174            tags: Documents must have **all** of these tags (AND semantics).
175            any_tags: Documents must have **at least one** of these tags.
176            exclude_tags: Documents must have **none** of these tags.
177            correspondent: Filter to documents assigned to this correspondent.
178                Pass ``None`` to return only documents with no correspondent set.
179            any_correspondent: Filter to documents assigned to any of these.
180            exclude_correspondents: Exclude documents assigned to any of these.
181            document_type: Filter to documents of exactly this type.
182                Pass ``None`` to return only documents with no document type set.
183            document_type_name_contains: Case-insensitive substring filter on document type name.
184            document_type_name_exact: Case-insensitive exact match on document type name.
185            any_document_type: Filter to documents whose type is any of these.
186            exclude_document_types: Exclude documents whose type is any of these.
187            storage_path: Filter to documents assigned to this storage path.
188                Pass ``None`` to return only documents with no storage path set.
189            any_storage_paths: Filter to documents assigned to any of these paths.
190            exclude_storage_paths: Exclude documents assigned to any of these paths.
191            owner: Filter to documents owned by this user ID.
192                Pass ``None`` to return only documents with no owner set.
193            exclude_owners: Exclude documents owned by any of these user IDs.
194            custom_fields: Documents must have **all** of these custom fields set.
195            any_custom_fields: Documents must have **at least one** of these fields.
196            exclude_custom_fields: Documents must have **none** of these fields.
197            custom_field_query: Filter documents by custom field values.
198            archive_serial_number: Filter by exact archive serial number.
199                Pass ``None`` to return only documents with no ASN set.
200            archive_serial_number_from: Filter by ASN >= this value.
201            archive_serial_number_till: Filter by ASN <= this value.
202            created_after: Only documents created after this date.
203            created_before: Only documents created before this date.
204            added_after: Only documents added after this date/time.
205            added_from: Only documents added on or after this date/time.
206            added_before: Only documents added before this date/time.
207            added_until: Only documents added on or before this date/time.
208            modified_after: Only documents modified after this date/time.
209            modified_from: Only documents modified on or after this date/time.
210            modified_before: Only documents modified before this date/time.
211            modified_until: Only documents modified on or before this date/time.
212            checksum: MD5 checksum of the original file (exact match).
213            page_size: Number of results per API page.  Default: ``25``.
214            page: Return only this specific page (1-based).
215            ordering: Field name to sort by.
216            descending: When ``True``, reverses the sort direction.
217            max_results: Stop after collecting this many documents.
218            on_page: Callback invoked after each page fetch.
219
220        Returns:
221            List of :class:`~easypaperless.models.documents.Document` objects.
222        """
223        return cast(
224            List[Document],
225            self._run(
226                self._async_documents.list(
227                    search=search,
228                    search_mode=search_mode,
229                    ids=ids,
230                    tags=tags,
231                    any_tags=any_tags,
232                    exclude_tags=exclude_tags,
233                    correspondent=correspondent,
234                    any_correspondent=any_correspondent,
235                    exclude_correspondents=exclude_correspondents,
236                    document_type=document_type,
237                    document_type_name_contains=document_type_name_contains,
238                    document_type_name_exact=document_type_name_exact,
239                    any_document_type=any_document_type,
240                    exclude_document_types=exclude_document_types,
241                    storage_path=storage_path,
242                    any_storage_paths=any_storage_paths,
243                    exclude_storage_paths=exclude_storage_paths,
244                    owner=owner,
245                    exclude_owners=exclude_owners,
246                    custom_fields=custom_fields,
247                    any_custom_fields=any_custom_fields,
248                    exclude_custom_fields=exclude_custom_fields,
249                    custom_field_query=custom_field_query,
250                    archive_serial_number=archive_serial_number,
251                    archive_serial_number_from=archive_serial_number_from,
252                    archive_serial_number_till=archive_serial_number_till,
253                    created_after=created_after,
254                    created_before=created_before,
255                    added_after=added_after,
256                    added_from=added_from,
257                    added_before=added_before,
258                    added_until=added_until,
259                    modified_after=modified_after,
260                    modified_from=modified_from,
261                    modified_before=modified_before,
262                    modified_until=modified_until,
263                    checksum=checksum,
264                    page_size=page_size,
265                    page=page,
266                    ordering=ordering,
267                    descending=descending,
268                    max_results=max_results,
269                    on_page=on_page,
270                )
271            ),
272        )

Return a filtered list of documents.

All tag, correspondent, document-type, storage-path, and custom-field parameters accept either integer IDs or string names.

Arguments:
  • search: Search string. Behaviour depends on search_mode.
  • search_mode: How search is applied. One of: "title_or_content" (default), "title", "query", "original_filename".
  • ids: Return only documents whose ID is in this list.
  • tags: Documents must have all of these tags (AND semantics).
  • any_tags: Documents must have at least one of these tags.
  • exclude_tags: Documents must have none of these tags.
  • correspondent: Filter to documents assigned to this correspondent. Pass None to return only documents with no correspondent set.
  • any_correspondent: Filter to documents assigned to any of these.
  • exclude_correspondents: Exclude documents assigned to any of these.
  • document_type: Filter to documents of exactly this type. Pass None to return only documents with no document type set.
  • document_type_name_contains: Case-insensitive substring filter on document type name.
  • document_type_name_exact: Case-insensitive exact match on document type name.
  • any_document_type: Filter to documents whose type is any of these.
  • exclude_document_types: Exclude documents whose type is any of these.
  • storage_path: Filter to documents assigned to this storage path. Pass None to return only documents with no storage path set.
  • any_storage_paths: Filter to documents assigned to any of these paths.
  • exclude_storage_paths: Exclude documents assigned to any of these paths.
  • owner: Filter to documents owned by this user ID. Pass None to return only documents with no owner set.
  • exclude_owners: Exclude documents owned by any of these user IDs.
  • custom_fields: Documents must have all of these custom fields set.
  • any_custom_fields: Documents must have at least one of these fields.
  • exclude_custom_fields: Documents must have none of these fields.
  • custom_field_query: Filter documents by custom field values.
  • archive_serial_number: Filter by exact archive serial number. Pass None to return only documents with no ASN set.
  • archive_serial_number_from: Filter by ASN >= this value.
  • archive_serial_number_till: Filter by ASN <= this value.
  • created_after: Only documents created after this date.
  • created_before: Only documents created before this date.
  • added_after: Only documents added after this date/time.
  • added_from: Only documents added on or after this date/time.
  • added_before: Only documents added before this date/time.
  • added_until: Only documents added on or before this date/time.
  • modified_after: Only documents modified after this date/time.
  • modified_from: Only documents modified on or after this date/time.
  • modified_before: Only documents modified before this date/time.
  • modified_until: Only documents modified on or before this date/time.
  • checksum: MD5 checksum of the original file (exact match).
  • page_size: Number of results per API page. Default: 25.
  • page: Return only this specific page (1-based).
  • ordering: Field name to sort by.
  • descending: When True, reverses the sort direction.
  • max_results: Stop after collecting this many documents.
  • on_page: Callback invoked after each page fetch.
Returns:

List of ~easypaperless.models.documents.Document objects.

def update( self, id: int, *, title: str | None | easypaperless._internal.sentinel._Unset = UNSET, content: str | None | easypaperless._internal.sentinel._Unset = UNSET, created: datetime.date | str | None | easypaperless._internal.sentinel._Unset = UNSET, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, tags: Union[List[Union[str, int]], NoneType, easypaperless._internal.sentinel._Unset] = UNSET, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, custom_fields: Union[List[dict[str, Any]], NoneType, easypaperless._internal.sentinel._Unset] = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET, remove_inbox_tags: bool | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Document:
274    def update(
275        self,
276        id: int,
277        *,
278        title: str | None | _Unset = UNSET,
279        content: str | None | _Unset = UNSET,
280        created: date | str | None | _Unset = UNSET,
281        correspondent: int | str | None | _Unset = UNSET,
282        document_type: int | str | None | _Unset = UNSET,
283        storage_path: int | str | None | _Unset = UNSET,
284        tags: List[int | str] | None | _Unset = UNSET,
285        archive_serial_number: int | None | _Unset = UNSET,
286        custom_fields: List[dict[str, Any]] | None | _Unset = UNSET,
287        owner: int | None | _Unset = UNSET,
288        set_permissions: SetPermissions | None | _Unset = UNSET,
289        remove_inbox_tags: bool | None | _Unset = UNSET,
290    ) -> Document:
291        """Partially update a document (PATCH semantics).
292
293        Args:
294            id: Numeric ID of the document to update.
295            title: New document title.
296            content: OCR text content of the document.
297            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
298                :class:`~datetime.date` object.
299            correspondent: Correspondent to assign, as an ID or name.
300                Pass ``None`` to clear the correspondent.
301            document_type: Document type to assign, as an ID or name.
302                Pass ``None`` to clear the document type.
303            storage_path: Storage path to assign, as an ID or name.
304                Pass ``None`` to clear the storage path.
305            tags: Full replacement list of tags (IDs or names).
306            archive_serial_number: Archive serial number to assign.
307                Pass ``None`` to clear the archive serial number.
308            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
309            owner: Numeric user ID to assign as document owner.
310                Pass ``None`` to clear the owner.
311            set_permissions: Explicit view/change permission sets.
312            remove_inbox_tags: When ``True``, removes all inbox tags from the document.
313
314        Returns:
315            The updated :class:`~easypaperless.models.documents.Document`.
316        """
317        return cast(
318            Document,
319            self._run(
320                self._async_documents.update(
321                    id,
322                    title=title,
323                    content=content,
324                    created=created,
325                    correspondent=correspondent,
326                    document_type=document_type,
327                    storage_path=storage_path,
328                    tags=tags,
329                    archive_serial_number=archive_serial_number,
330                    custom_fields=custom_fields,
331                    owner=owner,
332                    set_permissions=set_permissions,
333                    remove_inbox_tags=remove_inbox_tags,
334                )
335            ),
336        )

Partially update a document (PATCH semantics).

Arguments:
  • id: Numeric ID of the document to update.
  • title: New document title.
  • content: OCR text content of the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear the correspondent.
  • document_type: Document type to assign, as an ID or name. Pass None to clear the document type.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear the storage path.
  • tags: Full replacement list of tags (IDs or names).
  • archive_serial_number: Archive serial number to assign. Pass None to clear the archive serial number.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • owner: Numeric user ID to assign as document owner. Pass None to clear the owner.
  • set_permissions: Explicit view/change permission sets.
  • remove_inbox_tags: When True, removes all inbox tags from the document.
Returns:

The updated ~easypaperless.models.documents.Document.

def delete(self, id: int) -> None:
338    def delete(self, id: int) -> None:
339        """Permanently delete a document.
340
341        Args:
342            id: Numeric ID of the document to delete.
343
344        Raises:
345            ~easypaperless.exceptions.NotFoundError: If no document exists
346                with that ID.
347        """
348        self._run(self._async_documents.delete(id))

Permanently delete a document.

Arguments:
  • id: Numeric ID of the document to delete.
Raises:
def download(self, id: int, *, original: bool = False) -> bytes:
350    def download(self, id: int, *, original: bool = False) -> bytes:
351        """Download the binary content of a document.
352
353        Args:
354            id: Numeric ID of the document to download.
355            original: If ``False`` *(default)*, returns the archived PDF.
356                If ``True``, returns the original uploaded file.
357
358        Returns:
359            Raw file bytes.
360        """
361        return cast(bytes, self._run(self._async_documents.download(id, original=original)))

Download the binary content of a document.

Arguments:
  • id: Numeric ID of the document to download.
  • original: If False (default), returns the archived PDF. If True, returns the original uploaded file.
Returns:

Raw file bytes.

def upload( self, file: str | pathlib._local.Path, *, title: str | None = None, created: datetime.date | str | None = None, correspondent: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, document_type: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, storage_path: int | str | None | easypaperless._internal.sentinel._Unset = UNSET, tags: Optional[List[Union[str, int]]] = None, archive_serial_number: int | None | easypaperless._internal.sentinel._Unset = UNSET, custom_fields: Optional[List[dict[str, Any]]] = None, wait: bool = False, poll_interval: float | None = None, poll_timeout: float | None = None) -> str | easypaperless.Document:
363    def upload(
364        self,
365        file: str | Path,
366        *,
367        title: str | None = None,
368        created: date | str | None = None,
369        correspondent: int | str | None | _Unset = UNSET,
370        document_type: int | str | None | _Unset = UNSET,
371        storage_path: int | str | None | _Unset = UNSET,
372        tags: List[int | str] | None = None,
373        archive_serial_number: int | None | _Unset = UNSET,
374        custom_fields: List[dict[str, Any]] | None = None,
375        wait: bool = False,
376        poll_interval: float | None = None,
377        poll_timeout: float | None = None,
378    ) -> str | Document:
379        """Upload a document to paperless-ngx.
380
381        Args:
382            file: Path to the file to upload.
383            title: Title to assign to the document.
384            created: Creation date as an ISO-8601 string (``"YYYY-MM-DD"``) or a
385                :class:`~datetime.date` object.
386            correspondent: Correspondent to assign, as an ID or name.
387            document_type: Document type to assign, as an ID or name.
388            storage_path: Storage path to assign, as an ID or name.
389            tags: Tags to assign, as IDs or names.
390            archive_serial_number: Archive serial number to assign.
391            custom_fields: List of ``{"field": <field_id>, "value": ...}`` dicts.
392            wait: If ``False`` *(default)*, returns immediately with the task ID.
393                If ``True``, polls until processing completes.
394            poll_interval: Override the client-level ``poll_interval`` (in seconds).
395            poll_timeout: Override the client-level ``poll_timeout`` (in seconds).
396
397        Returns:
398            The Celery task ID string when ``wait=False``, or the fully
399            processed :class:`~easypaperless.models.documents.Document`
400            when ``wait=True``.
401
402        Raises:
403            ~easypaperless.exceptions.UploadError: If processing fails.
404            ~easypaperless.exceptions.TaskTimeoutError: If timeout is exceeded.
405        """
406        return cast(
407            str | Document,
408            self._run(
409                self._async_documents.upload(
410                    file,
411                    title=title,
412                    created=created,
413                    correspondent=correspondent,
414                    document_type=document_type,
415                    storage_path=storage_path,
416                    tags=tags,
417                    archive_serial_number=archive_serial_number,
418                    custom_fields=custom_fields,
419                    wait=wait,
420                    poll_interval=poll_interval,
421                    poll_timeout=poll_timeout,
422                )
423            ),
424        )

Upload a document to paperless-ngx.

Arguments:
  • file: Path to the file to upload.
  • title: Title to assign to the document.
  • created: Creation date as an ISO-8601 string ("YYYY-MM-DD") or a ~datetime.date object.
  • correspondent: Correspondent to assign, as an ID or name.
  • document_type: Document type to assign, as an ID or name.
  • storage_path: Storage path to assign, as an ID or name.
  • tags: Tags to assign, as IDs or names.
  • archive_serial_number: Archive serial number to assign.
  • custom_fields: List of {"field": <field_id>, "value": ...} dicts.
  • wait: If False (default), returns immediately with the task ID. If True, polls until processing completes.
  • poll_interval: Override the client-level poll_interval (in seconds).
  • poll_timeout: Override the client-level poll_timeout (in seconds).
Returns:

The Celery task ID string when wait=False, or the fully processed ~easypaperless.models.documents.Document when wait=True.

Raises:
def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
426    def bulk_add_tag(self, document_ids: List[int], tag: int | str) -> None:
427        """Add a tag to multiple documents in a single request.
428
429        Args:
430            document_ids: List of document IDs to tag.
431            tag: Tag to add, as an ID or name.
432        """
433        self._run(self._async_documents.bulk_add_tag(document_ids, tag))

Add a tag to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to tag.
  • tag: Tag to add, as an ID or name.
def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
435    def bulk_remove_tag(self, document_ids: List[int], tag: int | str) -> None:
436        """Remove a tag from multiple documents in a single request.
437
438        Args:
439            document_ids: List of document IDs to un-tag.
440            tag: Tag to remove, as an ID or name.
441        """
442        self._run(self._async_documents.bulk_remove_tag(document_ids, tag))

Remove a tag from multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to un-tag.
  • tag: Tag to remove, as an ID or name.
def bulk_modify_tags( self, document_ids: List[int], *, add_tags: Optional[List[Union[str, int]]] = None, remove_tags: Optional[List[Union[str, int]]] = None) -> None:
444    def bulk_modify_tags(
445        self,
446        document_ids: List[int],
447        *,
448        add_tags: List[int | str] | None = None,
449        remove_tags: List[int | str] | None = None,
450    ) -> None:
451        """Add and/or remove tags on multiple documents atomically.
452
453        Args:
454            document_ids: List of document IDs to modify.
455            add_tags: Tags to add, as IDs or names.
456            remove_tags: Tags to remove, as IDs or names.
457        """
458        self._run(
459            self._async_documents.bulk_modify_tags(
460                document_ids, add_tags=add_tags, remove_tags=remove_tags
461            )
462        )

Add and/or remove tags on multiple documents atomically.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_tags: Tags to add, as IDs or names.
  • remove_tags: Tags to remove, as IDs or names.
def bulk_delete(self, document_ids: List[int]) -> None:
464    def bulk_delete(self, document_ids: List[int]) -> None:
465        """Permanently delete multiple documents in a single request.
466
467        Args:
468            document_ids: List of document IDs to delete.
469        """
470        self._run(self._async_documents.bulk_delete(document_ids))

Permanently delete multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to delete.
def bulk_set_correspondent(self, document_ids: List[int], correspondent: int | str | None) -> None:
472    def bulk_set_correspondent(
473        self, document_ids: List[int], correspondent: int | str | None
474    ) -> None:
475        """Assign a correspondent to multiple documents in a single request.
476
477        Args:
478            document_ids: List of document IDs to modify.
479            correspondent: Correspondent to assign, as an ID or name.
480                Pass ``None`` to clear.
481        """
482        self._run(self._async_documents.bulk_set_correspondent(document_ids, correspondent))

Assign a correspondent to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • correspondent: Correspondent to assign, as an ID or name. Pass None to clear.
def bulk_set_document_type(self, document_ids: List[int], document_type: int | str | None) -> None:
484    def bulk_set_document_type(
485        self, document_ids: List[int], document_type: int | str | None
486    ) -> None:
487        """Assign a document type to multiple documents in a single request.
488
489        Args:
490            document_ids: List of document IDs to modify.
491            document_type: Document type to assign, as an ID or name.
492                Pass ``None`` to clear.
493        """
494        self._run(self._async_documents.bulk_set_document_type(document_ids, document_type))

Assign a document type to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • document_type: Document type to assign, as an ID or name. Pass None to clear.
def bulk_set_storage_path(self, document_ids: List[int], storage_path: int | str | None) -> None:
496    def bulk_set_storage_path(
497        self, document_ids: List[int], storage_path: int | str | None
498    ) -> None:
499        """Assign a storage path to multiple documents in a single request.
500
501        Args:
502            document_ids: List of document IDs to modify.
503            storage_path: Storage path to assign, as an ID or name.
504                Pass ``None`` to clear.
505        """
506        self._run(self._async_documents.bulk_set_storage_path(document_ids, storage_path))

Assign a storage path to multiple documents in a single request.

Arguments:
  • document_ids: List of document IDs to modify.
  • storage_path: Storage path to assign, as an ID or name. Pass None to clear.
def bulk_modify_custom_fields( self, document_ids: List[int], *, add_fields: Optional[List[dict[str, Any]]] = None, remove_fields: Optional[List[int]] = None) -> None:
508    def bulk_modify_custom_fields(
509        self,
510        document_ids: List[int],
511        *,
512        add_fields: List[dict[str, Any]] | None = None,
513        remove_fields: List[int] | None = None,
514    ) -> None:
515        """Add and/or remove custom field values on multiple documents.
516
517        Args:
518            document_ids: List of document IDs to modify.
519            add_fields: Custom-field value dicts to add.
520            remove_fields: Custom-field IDs whose values should be removed.
521        """
522        self._run(
523            self._async_documents.bulk_modify_custom_fields(
524                document_ids, add_fields=add_fields, remove_fields=remove_fields
525            )
526        )

Add and/or remove custom field values on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • add_fields: Custom-field value dicts to add.
  • remove_fields: Custom-field IDs whose values should be removed.
def bulk_set_permissions( self, document_ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
528    def bulk_set_permissions(
529        self,
530        document_ids: List[int],
531        *,
532        set_permissions: SetPermissions | None = None,
533        owner: int | None = None,
534        merge: bool = False,
535    ) -> None:
536        """Set permissions and/or owner on multiple documents.
537
538        Args:
539            document_ids: List of document IDs to modify.
540            set_permissions: Explicit view/change permission sets.
541            owner: Numeric user ID to assign as document owner.
542            merge: When ``True``, new permissions are merged with existing ones.
543        """
544        self._run(
545            self._async_documents.bulk_set_permissions(
546                document_ids,
547                set_permissions=set_permissions,
548                owner=owner,
549                merge=merge,
550            )
551        )

Set permissions and/or owner on multiple documents.

Arguments:
  • document_ids: List of document IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as document owner.
  • merge: When True, new permissions are merged with existing ones.
class SyncNotesResource:
19class SyncNotesResource:
20    """Sync accessor for document notes: ``client.documents.notes``."""
21
22    def __init__(self, async_notes: NotesResource, run: Any) -> None:
23        self._async_notes = async_notes
24        self._run = run
25
26    def list(self, document_id: int) -> List[DocumentNote]:
27        """Fetch all notes attached to a document.
28
29        Args:
30            document_id: Numeric ID of the document whose notes to retrieve.
31
32        Returns:
33            List of :class:`~easypaperless.models.documents.DocumentNote` objects,
34            ordered by creation time.
35
36        Raises:
37            ~easypaperless.exceptions.NotFoundError: If no document exists
38                with that ID.
39        """
40        return cast(List[DocumentNote], self._run(self._async_notes.list(document_id)))
41
42    def create(self, document_id: int, *, note: str) -> DocumentNote:
43        """Create a new note on a document.
44
45        Args:
46            document_id: Numeric ID of the document to annotate.
47            note: Text content of the note.
48
49        Returns:
50            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
51
52        Raises:
53            ~easypaperless.exceptions.NotFoundError: If no document exists
54                with that ID.
55        """
56        return cast(DocumentNote, self._run(self._async_notes.create(document_id, note=note)))
57
58    def delete(self, document_id: int, note_id: int) -> None:
59        """Delete a note from a document.
60
61        Args:
62            document_id: Numeric ID of the document that owns the note.
63            note_id: Numeric ID of the note to delete.
64
65        Raises:
66            ~easypaperless.exceptions.NotFoundError: If no document or note
67                exists with the given IDs.
68        """
69        self._run(self._async_notes.delete(document_id, note_id))

Sync accessor for document notes: client.documents.notes.

SyncNotesResource( async_notes: NotesResource, run: Any)
22    def __init__(self, async_notes: NotesResource, run: Any) -> None:
23        self._async_notes = async_notes
24        self._run = run
def list( self, document_id: int) -> List[easypaperless.DocumentNote]:
26    def list(self, document_id: int) -> List[DocumentNote]:
27        """Fetch all notes attached to a document.
28
29        Args:
30            document_id: Numeric ID of the document whose notes to retrieve.
31
32        Returns:
33            List of :class:`~easypaperless.models.documents.DocumentNote` objects,
34            ordered by creation time.
35
36        Raises:
37            ~easypaperless.exceptions.NotFoundError: If no document exists
38                with that ID.
39        """
40        return cast(List[DocumentNote], self._run(self._async_notes.list(document_id)))

Fetch all notes attached to a document.

Arguments:
  • document_id: Numeric ID of the document whose notes to retrieve.
Returns:

List of ~easypaperless.models.documents.DocumentNote objects, ordered by creation time.

Raises:
def create( self, document_id: int, *, note: str) -> easypaperless.DocumentNote:
42    def create(self, document_id: int, *, note: str) -> DocumentNote:
43        """Create a new note on a document.
44
45        Args:
46            document_id: Numeric ID of the document to annotate.
47            note: Text content of the note.
48
49        Returns:
50            The newly created :class:`~easypaperless.models.documents.DocumentNote`.
51
52        Raises:
53            ~easypaperless.exceptions.NotFoundError: If no document exists
54                with that ID.
55        """
56        return cast(DocumentNote, self._run(self._async_notes.create(document_id, note=note)))

Create a new note on a document.

Arguments:
  • document_id: Numeric ID of the document to annotate.
  • note: Text content of the note.
Returns:

The newly created ~easypaperless.models.documents.DocumentNote.

Raises:
def delete(self, document_id: int, note_id: int) -> None:
58    def delete(self, document_id: int, note_id: int) -> None:
59        """Delete a note from a document.
60
61        Args:
62            document_id: Numeric ID of the document that owns the note.
63            note_id: Numeric ID of the note to delete.
64
65        Raises:
66            ~easypaperless.exceptions.NotFoundError: If no document or note
67                exists with the given IDs.
68        """
69        self._run(self._async_notes.delete(document_id, note_id))

Delete a note from a document.

Arguments:
  • document_id: Numeric ID of the document that owns the note.
  • note_id: Numeric ID of the note to delete.
Raises:
class SyncStoragePathsResource:
 17class SyncStoragePathsResource:
 18    """Sync accessor for storage paths: ``client.storage_paths``."""
 19
 20    def __init__(self, async_storage_paths: StoragePathsResource, run: Any) -> None:
 21        self._async_storage_paths = async_storage_paths
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        ids: List[int] | None = None,
 28        name_contains: str | None = None,
 29        name_exact: str | None = None,
 30        path_contains: str | None = None,
 31        path_exact: str | None = None,
 32        page: int | None = None,
 33        page_size: int | None = None,
 34        ordering: str | None = None,
 35        descending: bool = False,
 36    ) -> List[StoragePath]:
 37        """Return storage paths defined in paperless-ngx.
 38
 39        Args:
 40            ids: Return only storage paths whose ID is in this list.
 41            name_contains: Case-insensitive substring filter on name.
 42            name_exact: Case-insensitive exact match on name.
 43            path_contains: Case-insensitive substring filter on path template.
 44            path_exact: Case-insensitive exact match on path template.
 45            page: Return only this specific page (1-based).
 46            page_size: Number of results per page.
 47            ordering: Field to sort by.
 48            descending: When ``True``, reverses the sort direction.
 49
 50        Returns:
 51            List of :class:`~easypaperless.models.storage_paths.StoragePath` objects.
 52        """
 53        return cast(
 54            List[StoragePath],
 55            self._run(
 56                self._async_storage_paths.list(
 57                    ids=ids,
 58                    name_contains=name_contains,
 59                    name_exact=name_exact,
 60                    path_contains=path_contains,
 61                    path_exact=path_exact,
 62                    page=page,
 63                    page_size=page_size,
 64                    ordering=ordering,
 65                    descending=descending,
 66                )
 67            ),
 68        )
 69
 70    def get(self, id: int) -> StoragePath:
 71        """Fetch a single storage path by its ID.
 72
 73        Args:
 74            id: Numeric storage-path ID.
 75
 76        Returns:
 77            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
 78
 79        Raises:
 80            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
 81        """
 82        return cast(StoragePath, self._run(self._async_storage_paths.get(id)))
 83
 84    def create(
 85        self,
 86        *,
 87        name: str,
 88        path: str | None = None,
 89        match: str | None | _Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | _Unset = UNSET,
 93        set_permissions: SetPermissions | None = None,
 94    ) -> StoragePath:
 95        """Create a new storage path.
 96
 97        Args:
 98            name: Storage-path name. Must be unique.
 99            path: Template string for the archive file path.
100            match: Auto-matching pattern.
101            matching_algorithm: Controls how ``match`` is applied.
102            is_insensitive: When ``True``, ``match`` is case-insensitive.
103                Defaults to ``True``, matching the paperless-ngx API default.
104            owner: Numeric user ID to assign as owner.
105            set_permissions: Explicit view/change permission sets.
106
107        Returns:
108            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
109        """
110        return cast(
111            StoragePath,
112            self._run(
113                self._async_storage_paths.create(
114                    name=name,
115                    path=path,
116                    match=match,
117                    matching_algorithm=matching_algorithm,
118                    is_insensitive=is_insensitive,
119                    owner=owner,
120                    set_permissions=set_permissions,
121                )
122            ),
123        )
124
125    def update(
126        self,
127        id: int,
128        *,
129        name: str | None | _Unset = UNSET,
130        path: str | None | _Unset = UNSET,
131        match: str | None | _Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
133        is_insensitive: bool | None | _Unset = UNSET,
134        owner: int | None | _Unset = UNSET,
135        set_permissions: SetPermissions | None | _Unset = UNSET,
136    ) -> StoragePath:
137        """Partially update a storage path (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the storage path to update.
141            name: Storage-path name.
142            path: Template string for the archive file path.
143            match: Auto-matching pattern.
144            matching_algorithm: Controls how ``match`` is applied.
145            is_insensitive: When ``True``, ``match`` is case-insensitive.
146            owner: Numeric user ID to assign as owner.
147                Pass ``None`` to clear the owner.
148                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
149            set_permissions: Explicit view/change permission sets.
150                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
151
152        Returns:
153            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
154        """
155        return cast(
156            StoragePath,
157            self._run(
158                self._async_storage_paths.update(
159                    id,
160                    name=name,
161                    path=path,
162                    match=match,
163                    matching_algorithm=matching_algorithm,
164                    is_insensitive=is_insensitive,
165                    owner=owner,
166                    set_permissions=set_permissions,
167                )
168            ),
169        )
170
171    def delete(self, id: int) -> None:
172        """Delete a storage path.
173
174        Args:
175            id: Numeric ID of the storage path to delete.
176
177        Raises:
178            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
179        """
180        self._run(self._async_storage_paths.delete(id))
181
182    def bulk_delete(self, ids: List[int]) -> None:
183        """Permanently delete multiple storage paths in a single request.
184
185        Args:
186            ids: List of storage path IDs to delete.
187        """
188        self._run(self._async_storage_paths.bulk_delete(ids))
189
190    def bulk_set_permissions(
191        self,
192        ids: List[int],
193        *,
194        set_permissions: SetPermissions | None = None,
195        owner: int | None = None,
196        merge: bool = False,
197    ) -> None:
198        """Set permissions and/or owner on multiple storage paths.
199
200        Args:
201            ids: List of storage path IDs to modify.
202            set_permissions: Explicit view/change permission sets.
203            owner: Numeric user ID to assign as owner.
204            merge: When ``True``, new permissions are merged with existing ones.
205        """
206        self._run(
207            self._async_storage_paths.bulk_set_permissions(
208                ids, set_permissions=set_permissions, owner=owner, merge=merge
209            )
210        )

Sync accessor for storage paths: client.storage_paths.

SyncStoragePathsResource( async_storage_paths: StoragePathsResource, run: Any)
20    def __init__(self, async_storage_paths: StoragePathsResource, run: Any) -> None:
21        self._async_storage_paths = async_storage_paths
22        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, path_contains: str | None = None, path_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.StoragePath]:
24    def list(
25        self,
26        *,
27        ids: List[int] | None = None,
28        name_contains: str | None = None,
29        name_exact: str | None = None,
30        path_contains: str | None = None,
31        path_exact: str | None = None,
32        page: int | None = None,
33        page_size: int | None = None,
34        ordering: str | None = None,
35        descending: bool = False,
36    ) -> List[StoragePath]:
37        """Return storage paths defined in paperless-ngx.
38
39        Args:
40            ids: Return only storage paths whose ID is in this list.
41            name_contains: Case-insensitive substring filter on name.
42            name_exact: Case-insensitive exact match on name.
43            path_contains: Case-insensitive substring filter on path template.
44            path_exact: Case-insensitive exact match on path template.
45            page: Return only this specific page (1-based).
46            page_size: Number of results per page.
47            ordering: Field to sort by.
48            descending: When ``True``, reverses the sort direction.
49
50        Returns:
51            List of :class:`~easypaperless.models.storage_paths.StoragePath` objects.
52        """
53        return cast(
54            List[StoragePath],
55            self._run(
56                self._async_storage_paths.list(
57                    ids=ids,
58                    name_contains=name_contains,
59                    name_exact=name_exact,
60                    path_contains=path_contains,
61                    path_exact=path_exact,
62                    page=page,
63                    page_size=page_size,
64                    ordering=ordering,
65                    descending=descending,
66                )
67            ),
68        )

Return storage paths defined in paperless-ngx.

Arguments:
  • ids: Return only storage paths whose ID is in this list.
  • name_contains: Case-insensitive substring filter on name.
  • name_exact: Case-insensitive exact match on name.
  • path_contains: Case-insensitive substring filter on path template.
  • path_exact: Case-insensitive exact match on path template.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.storage_paths.StoragePath objects.

def get(self, id: int) -> easypaperless.StoragePath:
70    def get(self, id: int) -> StoragePath:
71        """Fetch a single storage path by its ID.
72
73        Args:
74            id: Numeric storage-path ID.
75
76        Returns:
77            The :class:`~easypaperless.models.storage_paths.StoragePath` with the given ID.
78
79        Raises:
80            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
81        """
82        return cast(StoragePath, self._run(self._async_storage_paths.get(id)))

Fetch a single storage path by its ID.

Arguments:
  • id: Numeric storage-path ID.
Returns:

The ~easypaperless.models.storage_paths.StoragePath with the given ID.

Raises:
def create( self, *, name: str, path: str | None = None, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.StoragePath:
 84    def create(
 85        self,
 86        *,
 87        name: str,
 88        path: str | None = None,
 89        match: str | None | _Unset = UNSET,
 90        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 91        is_insensitive: bool = True,
 92        owner: int | None | _Unset = UNSET,
 93        set_permissions: SetPermissions | None = None,
 94    ) -> StoragePath:
 95        """Create a new storage path.
 96
 97        Args:
 98            name: Storage-path name. Must be unique.
 99            path: Template string for the archive file path.
100            match: Auto-matching pattern.
101            matching_algorithm: Controls how ``match`` is applied.
102            is_insensitive: When ``True``, ``match`` is case-insensitive.
103                Defaults to ``True``, matching the paperless-ngx API default.
104            owner: Numeric user ID to assign as owner.
105            set_permissions: Explicit view/change permission sets.
106
107        Returns:
108            The newly created :class:`~easypaperless.models.storage_paths.StoragePath`.
109        """
110        return cast(
111            StoragePath,
112            self._run(
113                self._async_storage_paths.create(
114                    name=name,
115                    path=path,
116                    match=match,
117                    matching_algorithm=matching_algorithm,
118                    is_insensitive=is_insensitive,
119                    owner=owner,
120                    set_permissions=set_permissions,
121                )
122            ),
123        )

Create a new storage path.

Arguments:
  • name: Storage-path name. Must be unique.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.storage_paths.StoragePath.

def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, path: str | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.StoragePath:
125    def update(
126        self,
127        id: int,
128        *,
129        name: str | None | _Unset = UNSET,
130        path: str | None | _Unset = UNSET,
131        match: str | None | _Unset = UNSET,
132        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
133        is_insensitive: bool | None | _Unset = UNSET,
134        owner: int | None | _Unset = UNSET,
135        set_permissions: SetPermissions | None | _Unset = UNSET,
136    ) -> StoragePath:
137        """Partially update a storage path (PATCH semantics).
138
139        Args:
140            id: Numeric ID of the storage path to update.
141            name: Storage-path name.
142            path: Template string for the archive file path.
143            match: Auto-matching pattern.
144            matching_algorithm: Controls how ``match`` is applied.
145            is_insensitive: When ``True``, ``match`` is case-insensitive.
146            owner: Numeric user ID to assign as owner.
147                Pass ``None`` to clear the owner.
148                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
149            set_permissions: Explicit view/change permission sets.
150                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
151
152        Returns:
153            The updated :class:`~easypaperless.models.storage_paths.StoragePath`.
154        """
155        return cast(
156            StoragePath,
157            self._run(
158                self._async_storage_paths.update(
159                    id,
160                    name=name,
161                    path=path,
162                    match=match,
163                    matching_algorithm=matching_algorithm,
164                    is_insensitive=is_insensitive,
165                    owner=owner,
166                    set_permissions=set_permissions,
167                )
168            ),
169        )

Partially update a storage path (PATCH semantics).

Arguments:
  • id: Numeric ID of the storage path to update.
  • name: Storage-path name.
  • path: Template string for the archive file path.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.storage_paths.StoragePath.

def delete(self, id: int) -> None:
171    def delete(self, id: int) -> None:
172        """Delete a storage path.
173
174        Args:
175            id: Numeric ID of the storage path to delete.
176
177        Raises:
178            ~easypaperless.exceptions.NotFoundError: If no storage path exists with that ID.
179        """
180        self._run(self._async_storage_paths.delete(id))

Delete a storage path.

Arguments:
  • id: Numeric ID of the storage path to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
182    def bulk_delete(self, ids: List[int]) -> None:
183        """Permanently delete multiple storage paths in a single request.
184
185        Args:
186            ids: List of storage path IDs to delete.
187        """
188        self._run(self._async_storage_paths.bulk_delete(ids))

Permanently delete multiple storage paths in a single request.

Arguments:
  • ids: List of storage path IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
190    def bulk_set_permissions(
191        self,
192        ids: List[int],
193        *,
194        set_permissions: SetPermissions | None = None,
195        owner: int | None = None,
196        merge: bool = False,
197    ) -> None:
198        """Set permissions and/or owner on multiple storage paths.
199
200        Args:
201            ids: List of storage path IDs to modify.
202            set_permissions: Explicit view/change permission sets.
203            owner: Numeric user ID to assign as owner.
204            merge: When ``True``, new permissions are merged with existing ones.
205        """
206        self._run(
207            self._async_storage_paths.bulk_set_permissions(
208                ids, set_permissions=set_permissions, owner=owner, merge=merge
209            )
210        )

Set permissions and/or owner on multiple storage paths.

Arguments:
  • ids: List of storage path IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.
class SyncTagsResource:
 17class SyncTagsResource:
 18    """Sync accessor for tags: ``client.tags``."""
 19
 20    def __init__(self, async_tags: TagsResource, run: Any) -> None:
 21        self._async_tags = async_tags
 22        self._run = run
 23
 24    def list(
 25        self,
 26        *,
 27        ids: List[int] | None = None,
 28        name_contains: str | None = None,
 29        name_exact: str | None = None,
 30        page: int | None = None,
 31        page_size: int | None = None,
 32        ordering: str | None = None,
 33        descending: bool = False,
 34    ) -> List[Tag]:
 35        """Return tags defined in paperless-ngx.
 36
 37        Args:
 38            ids: Return only tags whose ID is in this list.
 39            name_contains: Case-insensitive substring filter on tag name.
 40            name_exact: Case-insensitive exact match on tag name.
 41            page: Return only this specific page (1-based).
 42            page_size: Number of results per page.
 43            ordering: Field to sort by.
 44            descending: When ``True``, reverses the sort direction.
 45
 46        Returns:
 47            List of :class:`~easypaperless.models.tags.Tag` objects.
 48        """
 49        return cast(
 50            List[Tag],
 51            self._run(
 52                self._async_tags.list(
 53                    ids=ids,
 54                    name_contains=name_contains,
 55                    name_exact=name_exact,
 56                    page=page,
 57                    page_size=page_size,
 58                    ordering=ordering,
 59                    descending=descending,
 60                )
 61            ),
 62        )
 63
 64    def get(self, id: int) -> Tag:
 65        """Fetch a single tag by its ID.
 66
 67        Args:
 68            id: Numeric tag ID.
 69
 70        Returns:
 71            The :class:`~easypaperless.models.tags.Tag` with the given ID.
 72
 73        Raises:
 74            ~easypaperless.exceptions.NotFoundError: If no tag exists with
 75                that ID.
 76        """
 77        return cast(Tag, self._run(self._async_tags.get(id)))
 78
 79    def create(
 80        self,
 81        *,
 82        name: str,
 83        color: str | None = None,
 84        is_inbox_tag: bool | None = None,
 85        match: str | None | _Unset = UNSET,
 86        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 87        is_insensitive: bool = True,
 88        parent: int | None | _Unset = UNSET,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> Tag:
 92        """Create a new tag.
 93
 94        Args:
 95            name: Tag name. Must be unique.
 96            color: Background colour as a CSS hex string.
 97            is_inbox_tag: When ``True``, newly ingested documents get this tag.
 98            match: Auto-matching pattern.
 99            matching_algorithm: Controls how ``match`` is applied.
100            is_insensitive: When ``True``, ``match`` is case-insensitive.
101                Defaults to ``True``, matching the paperless-ngx API default.
102            parent: ID of parent tag for hierarchical trees.
103            owner: Numeric user ID to assign as owner.
104            set_permissions: Explicit view/change permission sets.
105
106        Returns:
107            The newly created :class:`~easypaperless.models.tags.Tag`.
108        """
109        return cast(
110            Tag,
111            self._run(
112                self._async_tags.create(
113                    name=name,
114                    color=color,
115                    is_inbox_tag=is_inbox_tag,
116                    match=match,
117                    matching_algorithm=matching_algorithm,
118                    is_insensitive=is_insensitive,
119                    parent=parent,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )
125
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | None | _Unset = UNSET,
131        color: str | None | _Unset = UNSET,
132        is_inbox_tag: bool | None | _Unset = UNSET,
133        match: str | None | _Unset = UNSET,
134        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
135        is_insensitive: bool | None | _Unset = UNSET,
136        parent: int | None | _Unset = UNSET,
137        owner: int | None | _Unset = UNSET,
138        set_permissions: SetPermissions | None | _Unset = UNSET,
139    ) -> Tag:
140        """Partially update a tag (PATCH semantics).
141
142        Args:
143            id: Numeric ID of the tag to update.
144            name: Tag name.
145            color: Background colour as a CSS hex string.
146            is_inbox_tag: When ``True``, newly ingested documents get this tag.
147            match: Auto-matching pattern.
148            matching_algorithm: Controls how ``match`` is applied.
149            is_insensitive: When ``True``, ``match`` is case-insensitive.
150            parent: ID of parent tag.
151                Pass ``None`` to clear (make root tag).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153            owner: Numeric user ID to assign as owner.
154                Pass ``None`` to clear the owner.
155                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
156            set_permissions: Explicit view/change permission sets.
157                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
158
159        Returns:
160            The updated :class:`~easypaperless.models.tags.Tag`.
161        """
162        return cast(
163            Tag,
164            self._run(
165                self._async_tags.update(
166                    id,
167                    name=name,
168                    color=color,
169                    is_inbox_tag=is_inbox_tag,
170                    match=match,
171                    matching_algorithm=matching_algorithm,
172                    is_insensitive=is_insensitive,
173                    parent=parent,
174                    owner=owner,
175                    set_permissions=set_permissions,
176                )
177            ),
178        )
179
180    def delete(self, id: int) -> None:
181        """Delete a tag.
182
183        Args:
184            id: Numeric ID of the tag to delete.
185
186        Raises:
187            ~easypaperless.exceptions.NotFoundError: If no tag exists with
188                that ID.
189        """
190        self._run(self._async_tags.delete(id))
191
192    def bulk_delete(self, ids: List[int]) -> None:
193        """Permanently delete multiple tags in a single request.
194
195        Args:
196            ids: List of tag IDs to delete.
197        """
198        self._run(self._async_tags.bulk_delete(ids))
199
200    def bulk_set_permissions(
201        self,
202        ids: List[int],
203        *,
204        set_permissions: SetPermissions | None = None,
205        owner: int | None = None,
206        merge: bool = False,
207    ) -> None:
208        """Set permissions and/or owner on multiple tags.
209
210        Args:
211            ids: List of tag IDs to modify.
212            set_permissions: Explicit view/change permission sets.
213            owner: Numeric user ID to assign as owner.
214            merge: When ``True``, new permissions are merged with existing ones.
215        """
216        self._run(
217            self._async_tags.bulk_set_permissions(
218                ids, set_permissions=set_permissions, owner=owner, merge=merge
219            )
220        )

Sync accessor for tags: client.tags.

SyncTagsResource( async_tags: TagsResource, run: Any)
20    def __init__(self, async_tags: TagsResource, run: Any) -> None:
21        self._async_tags = async_tags
22        self._run = run
def list( self, *, ids: Optional[List[int]] = None, name_contains: str | None = None, name_exact: str | None = None, page: int | None = None, page_size: int | None = None, ordering: str | None = None, descending: bool = False) -> List[easypaperless.Tag]:
24    def list(
25        self,
26        *,
27        ids: List[int] | None = None,
28        name_contains: str | None = None,
29        name_exact: str | None = None,
30        page: int | None = None,
31        page_size: int | None = None,
32        ordering: str | None = None,
33        descending: bool = False,
34    ) -> List[Tag]:
35        """Return tags defined in paperless-ngx.
36
37        Args:
38            ids: Return only tags whose ID is in this list.
39            name_contains: Case-insensitive substring filter on tag name.
40            name_exact: Case-insensitive exact match on tag name.
41            page: Return only this specific page (1-based).
42            page_size: Number of results per page.
43            ordering: Field to sort by.
44            descending: When ``True``, reverses the sort direction.
45
46        Returns:
47            List of :class:`~easypaperless.models.tags.Tag` objects.
48        """
49        return cast(
50            List[Tag],
51            self._run(
52                self._async_tags.list(
53                    ids=ids,
54                    name_contains=name_contains,
55                    name_exact=name_exact,
56                    page=page,
57                    page_size=page_size,
58                    ordering=ordering,
59                    descending=descending,
60                )
61            ),
62        )

Return tags defined in paperless-ngx.

Arguments:
  • ids: Return only tags whose ID is in this list.
  • name_contains: Case-insensitive substring filter on tag name.
  • name_exact: Case-insensitive exact match on tag name.
  • page: Return only this specific page (1-based).
  • page_size: Number of results per page.
  • ordering: Field to sort by.
  • descending: When True, reverses the sort direction.
Returns:

List of ~easypaperless.models.tags.Tag objects.

def get(self, id: int) -> easypaperless.Tag:
64    def get(self, id: int) -> Tag:
65        """Fetch a single tag by its ID.
66
67        Args:
68            id: Numeric tag ID.
69
70        Returns:
71            The :class:`~easypaperless.models.tags.Tag` with the given ID.
72
73        Raises:
74            ~easypaperless.exceptions.NotFoundError: If no tag exists with
75                that ID.
76        """
77        return cast(Tag, self._run(self._async_tags.get(id)))

Fetch a single tag by its ID.

Arguments:
  • id: Numeric tag ID.
Returns:

The ~easypaperless.models.tags.Tag with the given ID.

Raises:
def create( self, *, name: str, color: str | None = None, is_inbox_tag: bool | None = None, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool = True, parent: int | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None = None) -> easypaperless.Tag:
 79    def create(
 80        self,
 81        *,
 82        name: str,
 83        color: str | None = None,
 84        is_inbox_tag: bool | None = None,
 85        match: str | None | _Unset = UNSET,
 86        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
 87        is_insensitive: bool = True,
 88        parent: int | None | _Unset = UNSET,
 89        owner: int | None | _Unset = UNSET,
 90        set_permissions: SetPermissions | None = None,
 91    ) -> Tag:
 92        """Create a new tag.
 93
 94        Args:
 95            name: Tag name. Must be unique.
 96            color: Background colour as a CSS hex string.
 97            is_inbox_tag: When ``True``, newly ingested documents get this tag.
 98            match: Auto-matching pattern.
 99            matching_algorithm: Controls how ``match`` is applied.
100            is_insensitive: When ``True``, ``match`` is case-insensitive.
101                Defaults to ``True``, matching the paperless-ngx API default.
102            parent: ID of parent tag for hierarchical trees.
103            owner: Numeric user ID to assign as owner.
104            set_permissions: Explicit view/change permission sets.
105
106        Returns:
107            The newly created :class:`~easypaperless.models.tags.Tag`.
108        """
109        return cast(
110            Tag,
111            self._run(
112                self._async_tags.create(
113                    name=name,
114                    color=color,
115                    is_inbox_tag=is_inbox_tag,
116                    match=match,
117                    matching_algorithm=matching_algorithm,
118                    is_insensitive=is_insensitive,
119                    parent=parent,
120                    owner=owner,
121                    set_permissions=set_permissions,
122                )
123            ),
124        )

Create a new tag.

Arguments:
  • name: Tag name. Must be unique.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive. Defaults to True, matching the paperless-ngx API default.
  • parent: ID of parent tag for hierarchical trees.
  • owner: Numeric user ID to assign as owner.
  • set_permissions: Explicit view/change permission sets.
Returns:

The newly created ~easypaperless.models.tags.Tag.

def update( self, id: int, *, name: str | None | easypaperless._internal.sentinel._Unset = UNSET, color: str | None | easypaperless._internal.sentinel._Unset = UNSET, is_inbox_tag: bool | None | easypaperless._internal.sentinel._Unset = UNSET, match: str | None | easypaperless._internal.sentinel._Unset = UNSET, matching_algorithm: easypaperless.MatchingAlgorithm | None | easypaperless._internal.sentinel._Unset = UNSET, is_insensitive: bool | None | easypaperless._internal.sentinel._Unset = UNSET, parent: int | None | easypaperless._internal.sentinel._Unset = UNSET, owner: int | None | easypaperless._internal.sentinel._Unset = UNSET, set_permissions: easypaperless.SetPermissions | None | easypaperless._internal.sentinel._Unset = UNSET) -> easypaperless.Tag:
126    def update(
127        self,
128        id: int,
129        *,
130        name: str | None | _Unset = UNSET,
131        color: str | None | _Unset = UNSET,
132        is_inbox_tag: bool | None | _Unset = UNSET,
133        match: str | None | _Unset = UNSET,
134        matching_algorithm: MatchingAlgorithm | None | _Unset = UNSET,
135        is_insensitive: bool | None | _Unset = UNSET,
136        parent: int | None | _Unset = UNSET,
137        owner: int | None | _Unset = UNSET,
138        set_permissions: SetPermissions | None | _Unset = UNSET,
139    ) -> Tag:
140        """Partially update a tag (PATCH semantics).
141
142        Args:
143            id: Numeric ID of the tag to update.
144            name: Tag name.
145            color: Background colour as a CSS hex string.
146            is_inbox_tag: When ``True``, newly ingested documents get this tag.
147            match: Auto-matching pattern.
148            matching_algorithm: Controls how ``match`` is applied.
149            is_insensitive: When ``True``, ``match`` is case-insensitive.
150            parent: ID of parent tag.
151                Pass ``None`` to clear (make root tag).
152                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
153            owner: Numeric user ID to assign as owner.
154                Pass ``None`` to clear the owner.
155                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
156            set_permissions: Explicit view/change permission sets.
157                Omit (or pass :data:`~easypaperless.UNSET`) to leave unchanged.
158
159        Returns:
160            The updated :class:`~easypaperless.models.tags.Tag`.
161        """
162        return cast(
163            Tag,
164            self._run(
165                self._async_tags.update(
166                    id,
167                    name=name,
168                    color=color,
169                    is_inbox_tag=is_inbox_tag,
170                    match=match,
171                    matching_algorithm=matching_algorithm,
172                    is_insensitive=is_insensitive,
173                    parent=parent,
174                    owner=owner,
175                    set_permissions=set_permissions,
176                )
177            ),
178        )

Partially update a tag (PATCH semantics).

Arguments:
  • id: Numeric ID of the tag to update.
  • name: Tag name.
  • color: Background colour as a CSS hex string.
  • is_inbox_tag: When True, newly ingested documents get this tag.
  • match: Auto-matching pattern.
  • matching_algorithm: Controls how match is applied.
  • is_insensitive: When True, match is case-insensitive.
  • parent: ID of parent tag. Pass None to clear (make root tag). Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • owner: Numeric user ID to assign as owner. Pass None to clear the owner. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
  • set_permissions: Explicit view/change permission sets. Omit (or pass ~easypaperless.UNSET) to leave unchanged.
Returns:

The updated ~easypaperless.models.tags.Tag.

def delete(self, id: int) -> None:
180    def delete(self, id: int) -> None:
181        """Delete a tag.
182
183        Args:
184            id: Numeric ID of the tag to delete.
185
186        Raises:
187            ~easypaperless.exceptions.NotFoundError: If no tag exists with
188                that ID.
189        """
190        self._run(self._async_tags.delete(id))

Delete a tag.

Arguments:
  • id: Numeric ID of the tag to delete.
Raises:
def bulk_delete(self, ids: List[int]) -> None:
192    def bulk_delete(self, ids: List[int]) -> None:
193        """Permanently delete multiple tags in a single request.
194
195        Args:
196            ids: List of tag IDs to delete.
197        """
198        self._run(self._async_tags.bulk_delete(ids))

Permanently delete multiple tags in a single request.

Arguments:
  • ids: List of tag IDs to delete.
def bulk_set_permissions( self, ids: List[int], *, set_permissions: easypaperless.SetPermissions | None = None, owner: int | None = None, merge: bool = False) -> None:
200    def bulk_set_permissions(
201        self,
202        ids: List[int],
203        *,
204        set_permissions: SetPermissions | None = None,
205        owner: int | None = None,
206        merge: bool = False,
207    ) -> None:
208        """Set permissions and/or owner on multiple tags.
209
210        Args:
211            ids: List of tag IDs to modify.
212            set_permissions: Explicit view/change permission sets.
213            owner: Numeric user ID to assign as owner.
214            merge: When ``True``, new permissions are merged with existing ones.
215        """
216        self._run(
217            self._async_tags.bulk_set_permissions(
218                ids, set_permissions=set_permissions, owner=owner, merge=merge
219            )
220        )

Set permissions and/or owner on multiple tags.

Arguments:
  • ids: List of tag IDs to modify.
  • set_permissions: Explicit view/change permission sets.
  • owner: Numeric user ID to assign as owner.
  • merge: When True, new permissions are merged with existing ones.