easypaperless

easypaperless — Python API wrapper for paperless-ngx.

 1"""easypaperless — Python API wrapper for paperless-ngx."""
 2
 3import importlib.metadata
 4import logging
 5
 6__version__: str = importlib.metadata.version("easypaperless")
 7
 8from easypaperless import resources as resources  # noqa: F401
 9from easypaperless._internal.sentinel import UNSET, Unset
10from easypaperless.client import PaperlessClient
11from easypaperless.exceptions import (
12    AuthError,
13    NotFoundError,
14    PaperlessError,
15    RetryExhaustedError,
16    ServerError,
17    TaskTimeoutError,
18    UploadError,
19    ValidationError,
20)
21from easypaperless.models import (
22    AuditLogActor,
23    AuditLogEntry,
24    Correspondent,
25    CustomField,
26    CustomFieldValue,
27    Document,
28    DocumentMetadata,
29    DocumentNote,
30    DocumentType,
31    FieldDataType,
32    FileMetadataEntry,
33    MatchingAlgorithm,
34    PagedResult,
35    PaperlessPermission,
36    PermissionSet,
37    SearchHit,
38    SetPermissions,
39    StoragePath,
40    Tag,
41    Task,
42    TaskStatus,
43    User,
44)
45from easypaperless.sync import SyncPaperlessClient
46
47logging.getLogger("easypaperless").addHandler(logging.NullHandler())
48
49__all__ = [
50    "__version__",
51    # Clients
52    "PaperlessClient",
53    "SyncPaperlessClient",
54    # Sentinel
55    "UNSET",
56    "Unset",
57    # Models
58    "MatchingAlgorithm",
59    "PagedResult",
60    "AuditLogActor",
61    "AuditLogEntry",
62    "Correspondent",
63    "CustomField",
64    "CustomFieldValue",
65    "Document",
66    "DocumentMetadata",
67    "DocumentNote",
68    "DocumentType",
69    "FieldDataType",
70    "FileMetadataEntry",
71    "PermissionSet",
72    "SearchHit",
73    "SetPermissions",
74    "StoragePath",
75    "Tag",
76    "Task",
77    "TaskStatus",
78    "User",
79    "PaperlessPermission",
80    # Exceptions
81    "PaperlessError",
82    "AuthError",
83    "NotFoundError",
84    "ValidationError",
85    "ServerError",
86    "UploadError",
87    "TaskTimeoutError",
88    "RetryExhaustedError",
89]
__version__: str = '0.2.1'
class PaperlessClient(easypaperless.client._ClientCore):
170class PaperlessClient(_ClientCore):
171    """Async client for the paperless-ngx API.
172
173    Resources are accessible as attributes:
174
175    * ``client.correspondents`` — correspondent CRUD + bulk ops -
176      see `easypaperless.resources.CorrespondentsResource`
177    * ``client.custom_fields`` — custom field CRUD -
178      see `easypaperless.resources.CustomFieldsResource`
179    * ``client.document_types`` — document type CRUD + bulk ops -
180      see `easypaperless.resources.DocumentTypesResource`
181    * ``client.documents`` — document CRUD, bulk ops, upload, download, history -
182      see `easypaperless.resources.DocumentsResource`
183    * ``client.documents.notes`` — document notes -
184      see `easypaperless.resources.NotesResource`
185    * ``client.storage_paths`` — storage path CRUD + bulk ops -
186      see `easypaperless.resources.StoragePathsResource`
187    * ``client.tags`` — tag CRUD + bulk ops -
188      see `easypaperless.resources.TagsResource`
189    * ``client.users`` — user CRUD -
190      see `easypaperless.resources.UsersResource`
191    * ``client.trash`` — list, restore, and permanently delete trashed documents -
192      see `easypaperless.resources.TrashResource`
193
194    Use as an async context manager to ensure the underlying HTTP connection
195    pool is closed when you are done:
196
197    Example:
198        async with PaperlessClient(url="http://localhost:8000", api_token="abc") as client:
199            docs = await client.documents.list(max_results=10)
200    """
201
202    def __init__(
203        self,
204        url: str,
205        api_token: str,
206        *,
207        timeout: float = 30.0,
208        poll_interval: float = 2.0,
209        poll_timeout: float = 60.0,
210        retry_attempts: int = 0,
211        retry_backoff: float = 1.0,
212        retry_on: tuple[type[Exception], ...] | None = None,
213        tenacity_retrying: Any = None,
214    ) -> None:
215        """Create an async paperless-ngx client.
216
217        Args:
218            url: Base URL of the paperless-ngx instance
219                (e.g. ``"http://localhost:8000"``).
220            api_token: API token.  Generate one in paperless-ngx under
221                *Settings → API → Generate Token*.
222            timeout: Default request timeout in seconds.  Default: ``30.0``.
223            poll_interval: Seconds between status checks when ``wait=True``
224                is passed to :meth:`documents.upload`.  Default: ``2.0``.
225            poll_timeout: Maximum seconds to wait for a document to finish
226                processing before raising
227                :exc:`~easypaperless.exceptions.TaskTimeoutError`.
228                Default: ``60.0``.
229            retry_attempts: Maximum number of retry attempts after the first
230                failure.  ``0`` (the default) disables retrying entirely,
231                preserving backward-compatible behaviour.
232            retry_backoff: Initial sleep in seconds between retry attempts;
233                doubles on each subsequent attempt.  Default: ``1.0``.
234            retry_on: Tuple of exception types that trigger a retry.  Defaults
235                to ``(ServerError, httpx.TimeoutException, httpx.ConnectError)``.
236                ``NotFoundError`` is intentionally excluded from the default set
237                so that genuine 404 responses are never silently retried.
238                Note: ``httpx.TimeoutException`` and ``httpx.ConnectError`` are
239                intercepted inside the HTTP layer and re-raised as ``ServerError``
240                before the retry loop runs, so including them in a custom
241                ``retry_on`` tuple has no effect unless ``ServerError`` is also
242                present.
243            tenacity_retrying: An optional pre-configured
244                ``tenacity.AsyncRetrying`` instance.  When supplied, the
245                ``retry_attempts``, ``retry_backoff``, and ``retry_on``
246                parameters are ignored and tenacity drives the retry loop
247                instead.  Must be ``AsyncRetrying`` — the sync
248                ``tenacity.Retrying`` is not compatible with the async HTTP
249                layer used internally.
250        """
251        super().__init__(
252            url,
253            api_token,
254            timeout=timeout,
255            poll_interval=poll_interval,
256            poll_timeout=poll_timeout,
257            retry_attempts=retry_attempts,
258            retry_backoff=retry_backoff,
259            retry_on=retry_on,
260            tenacity_retrying=tenacity_retrying,
261        )
262
263    async def __aenter__(self) -> PaperlessClient:
264        return self
265
266    async def __aexit__(self, *args: Any) -> None:
267        await self.close()

Async client for the paperless-ngx API.

Resources are accessible as attributes:

  • client.correspondents — correspondent CRUD + bulk ops - see easypaperless.resources.CorrespondentsResource
  • client.custom_fields — custom field CRUD - see easypaperless.resources.CustomFieldsResource
  • client.document_types — document type CRUD + bulk ops - see easypaperless.resources.DocumentTypesResource
  • client.documents — document CRUD, bulk ops, upload, download, history - see easypaperless.resources.DocumentsResource
  • client.documents.notes — document notes - see easypaperless.resources.NotesResource
  • client.storage_paths — storage path CRUD + bulk ops - see easypaperless.resources.StoragePathsResource
  • client.tags — tag CRUD + bulk ops - see easypaperless.resources.TagsResource
  • client.users — user CRUD - see easypaperless.resources.UsersResource
  • client.trash — list, restore, and permanently delete trashed documents - see easypaperless.resources.TrashResource

Use as an async context manager to ensure the underlying HTTP connection pool is closed when you are done:

Example:

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

PaperlessClient( url: str, api_token: str, *, timeout: float = 30.0, poll_interval: float = 2.0, poll_timeout: float = 60.0, retry_attempts: int = 0, retry_backoff: float = 1.0, retry_on: tuple[type[Exception], ...] | None = None, tenacity_retrying: Any = None)
202    def __init__(
203        self,
204        url: str,
205        api_token: str,
206        *,
207        timeout: float = 30.0,
208        poll_interval: float = 2.0,
209        poll_timeout: float = 60.0,
210        retry_attempts: int = 0,
211        retry_backoff: float = 1.0,
212        retry_on: tuple[type[Exception], ...] | None = None,
213        tenacity_retrying: Any = None,
214    ) -> None:
215        """Create an async paperless-ngx client.
216
217        Args:
218            url: Base URL of the paperless-ngx instance
219                (e.g. ``"http://localhost:8000"``).
220            api_token: API token.  Generate one in paperless-ngx under
221                *Settings → API → Generate Token*.
222            timeout: Default request timeout in seconds.  Default: ``30.0``.
223            poll_interval: Seconds between status checks when ``wait=True``
224                is passed to :meth:`documents.upload`.  Default: ``2.0``.
225            poll_timeout: Maximum seconds to wait for a document to finish
226                processing before raising
227                :exc:`~easypaperless.exceptions.TaskTimeoutError`.
228                Default: ``60.0``.
229            retry_attempts: Maximum number of retry attempts after the first
230                failure.  ``0`` (the default) disables retrying entirely,
231                preserving backward-compatible behaviour.
232            retry_backoff: Initial sleep in seconds between retry attempts;
233                doubles on each subsequent attempt.  Default: ``1.0``.
234            retry_on: Tuple of exception types that trigger a retry.  Defaults
235                to ``(ServerError, httpx.TimeoutException, httpx.ConnectError)``.
236                ``NotFoundError`` is intentionally excluded from the default set
237                so that genuine 404 responses are never silently retried.
238                Note: ``httpx.TimeoutException`` and ``httpx.ConnectError`` are
239                intercepted inside the HTTP layer and re-raised as ``ServerError``
240                before the retry loop runs, so including them in a custom
241                ``retry_on`` tuple has no effect unless ``ServerError`` is also
242                present.
243            tenacity_retrying: An optional pre-configured
244                ``tenacity.AsyncRetrying`` instance.  When supplied, the
245                ``retry_attempts``, ``retry_backoff``, and ``retry_on``
246                parameters are ignored and tenacity drives the retry loop
247                instead.  Must be ``AsyncRetrying`` — the sync
248                ``tenacity.Retrying`` is not compatible with the async HTTP
249                layer used internally.
250        """
251        super().__init__(
252            url,
253            api_token,
254            timeout=timeout,
255            poll_interval=poll_interval,
256            poll_timeout=poll_timeout,
257            retry_attempts=retry_attempts,
258            retry_backoff=retry_backoff,
259            retry_on=retry_on,
260            tenacity_retrying=tenacity_retrying,
261        )

Create an async paperless-ngx client.

Arguments:
  • url: Base URL of the paperless-ngx instance (e.g. "http://localhost:8000").
  • api_token: API token. Generate one in paperless-ngx under Settings → API → Generate Token.
  • timeout: Default request timeout in seconds. Default: 30.0.
  • poll_interval: Seconds between status checks when wait=True is passed to documents.upload(). Default: 2.0.
  • poll_timeout: Maximum seconds to wait for a document to finish processing before raising ~easypaperless.exceptions.TaskTimeoutError. Default: 60.0.
  • retry_attempts: Maximum number of retry attempts after the first failure. 0 (the default) disables retrying entirely, preserving backward-compatible behaviour.
  • retry_backoff: Initial sleep in seconds between retry attempts; doubles on each subsequent attempt. Default: 1.0.
  • retry_on: Tuple of exception types that trigger a retry. Defaults to (ServerError, httpx.TimeoutException, httpx.ConnectError). NotFoundError is intentionally excluded from the default set so that genuine 404 responses are never silently retried. Note: httpx.TimeoutException and httpx.ConnectError are intercepted inside the HTTP layer and re-raised as ServerError before the retry loop runs, so including them in a custom retry_on tuple has no effect unless ServerError is also present.
  • tenacity_retrying: An optional pre-configured tenacity.AsyncRetrying instance. When supplied, the retry_attempts, retry_backoff, and retry_on parameters are ignored and tenacity drives the retry loop instead. Must be AsyncRetrying — the sync tenacity.Retrying is not compatible with the async HTTP layer used internally.
class SyncPaperlessClient(easypaperless.sync._SyncCore):
 83class SyncPaperlessClient(_SyncCore):
 84    """Synchronous interface to paperless-ngx.
 85
 86    Resources are accessible as attributes:
 87
 88    * ``client.correspondents`` — correspondent CRUD + bulk ops -
 89      see `easypaperless.resources.SyncCorrespondentsResource`
 90    * ``client.custom_fields`` — custom field CRUD -
 91      see `easypaperless.resources.SyncCustomFieldsResource`
 92    * ``client.document_types`` — document type CRUD + bulk ops -
 93      see `easypaperless.resources.SyncDocumentTypesResource`
 94    * ``client.documents`` — document CRUD, bulk ops, upload, download -
 95      see `easypaperless.resources.SyncDocumentsResource`
 96    * ``client.documents.notes`` — document notes -
 97      see `easypaperless.resources.SyncNotesResource`
 98    * ``client.storage_paths`` — storage path CRUD + bulk ops -
 99      see `easypaperless.resources.SyncStoragePathsResource`
100    * ``client.tags`` — tag CRUD + bulk ops -
101      see `easypaperless.resources.SyncTagsResource`
102    * ``client.users`` — user CRUD -
103      see `easypaperless.resources.SyncUsersResource`
104    * ``client.trash`` — list, restore, and permanently delete trashed documents -
105      see `easypaperless.resources.SyncTrashResource`
106
107    All methods are synchronous wrappers around the async
108    :class:`~easypaperless.client.PaperlessClient`.  Operations run on a
109    dedicated background event loop thread so that the httpx connection pool
110    is reused across calls and cleanup works correctly.
111
112    Use as a context manager to ensure proper cleanup:
113
114    Example:
115        with SyncPaperlessClient(url="http://localhost:8000", api_token="abc") as client:
116            tags = client.tags.list()
117            docs = client.documents.list(search="invoice")
118
119    Note:
120        Cannot be used inside an already-running event loop (e.g. Jupyter
121        notebooks).  Use :class:`~easypaperless.client.PaperlessClient`
122        directly in those environments.
123    """
124
125    def __init__(self, url: str, api_token: str, **kwargs: Any) -> None:
126        """Create a synchronous paperless-ngx client.
127
128        Args:
129            url: Base URL of the paperless-ngx instance
130                (e.g. ``"http://localhost:8000"``).
131            api_token: API token.  Generate one in paperless-ngx under
132                *Settings → API → Generate Token*.
133            **kwargs: Additional keyword arguments forwarded to
134                :class:`~easypaperless.client.PaperlessClient` (e.g.
135                ``poll_interval``, ``poll_timeout``, ``retry_attempts``,
136                ``retry_backoff``, ``retry_on``, ``tenacity_retrying``).
137                When using ``tenacity_retrying``, pass a
138                ``tenacity.AsyncRetrying`` instance — the sync
139                ``tenacity.Retrying`` is not compatible because all requests
140                run on an internal async event loop.
141        """
142        super().__init__(url, api_token, **kwargs)
143
144    def __enter__(self) -> SyncPaperlessClient:
145        return self
146
147    def __exit__(self, *args: Any) -> None:
148        self.close()

Synchronous interface to paperless-ngx.

Resources are accessible as attributes:

  • client.correspondents — correspondent CRUD + bulk ops - see easypaperless.resources.SyncCorrespondentsResource
  • client.custom_fields — custom field CRUD - see easypaperless.resources.SyncCustomFieldsResource
  • client.document_types — document type CRUD + bulk ops - see easypaperless.resources.SyncDocumentTypesResource
  • client.documents — document CRUD, bulk ops, upload, download - see easypaperless.resources.SyncDocumentsResource
  • client.documents.notes — document notes - see easypaperless.resources.SyncNotesResource
  • client.storage_paths — storage path CRUD + bulk ops - see easypaperless.resources.SyncStoragePathsResource
  • client.tags — tag CRUD + bulk ops - see easypaperless.resources.SyncTagsResource
  • client.users — user CRUD - see easypaperless.resources.SyncUsersResource
  • client.trash — list, restore, and permanently delete trashed documents - see easypaperless.resources.SyncTrashResource

All methods are synchronous wrappers around the async ~easypaperless.client.PaperlessClient. Operations run on a dedicated background event loop thread so that the httpx connection pool is reused across calls and cleanup works correctly.

Use as a context manager to ensure proper cleanup:

Example:

with SyncPaperlessClient(url="http://localhost:8000", api_token="abc") as client: tags = client.tags.list() docs = client.documents.list(search="invoice")

Note:

Cannot be used inside an already-running event loop (e.g. Jupyter notebooks). Use ~easypaperless.client.PaperlessClient directly in those environments.

SyncPaperlessClient(url: str, api_token: str, **kwargs: Any)
125    def __init__(self, url: str, api_token: str, **kwargs: Any) -> None:
126        """Create a synchronous paperless-ngx client.
127
128        Args:
129            url: Base URL of the paperless-ngx instance
130                (e.g. ``"http://localhost:8000"``).
131            api_token: API token.  Generate one in paperless-ngx under
132                *Settings → API → Generate Token*.
133            **kwargs: Additional keyword arguments forwarded to
134                :class:`~easypaperless.client.PaperlessClient` (e.g.
135                ``poll_interval``, ``poll_timeout``, ``retry_attempts``,
136                ``retry_backoff``, ``retry_on``, ``tenacity_retrying``).
137                When using ``tenacity_retrying``, pass a
138                ``tenacity.AsyncRetrying`` instance — the sync
139                ``tenacity.Retrying`` is not compatible because all requests
140                run on an internal async event loop.
141        """
142        super().__init__(url, api_token, **kwargs)

Create a synchronous paperless-ngx client.

Arguments:
  • url: Base URL of the paperless-ngx instance (e.g. "http://localhost:8000").
  • api_token: API token. Generate one in paperless-ngx under Settings → API → Generate Token.
  • **kwargs: Additional keyword arguments forwarded to ~easypaperless.client.PaperlessClient (e.g. poll_interval, poll_timeout, retry_attempts, retry_backoff, retry_on, tenacity_retrying). When using tenacity_retrying, pass a tenacity.AsyncRetrying instance — the sync tenacity.Retrying is not compatible because all requests run on an internal async event loop.
UNSET = UNSET
class Unset:
 9class Unset:
10    """Sentinel type signalling that a parameter was not provided.
11
12    Use the singleton :data:`UNSET` constant — do not instantiate directly.
13    """
14
15    __slots__ = ()
16
17    def __repr__(self) -> str:
18        return "UNSET"

Sentinel type signalling that a parameter was not provided.

Use the singleton UNSET constant — do not instantiate directly.

class MatchingAlgorithm(enum.IntEnum):
 9class MatchingAlgorithm(IntEnum):
10    """Auto-matching algorithm used by tags, correspondents, document types, and storage paths."""
11
12    NONE = 0
13    ANY_WORD = 1
14    ALL_WORDS = 2
15    EXACT = 3
16    REGEX = 4
17    FUZZY = 5
18    AUTO = 6

Auto-matching algorithm used by tags, correspondents, document types, and storage paths.

ANY_WORD = <MatchingAlgorithm.ANY_WORD: 1>
ALL_WORDS = <MatchingAlgorithm.ALL_WORDS: 2>
class PagedResult(pydantic.main.BaseModel, typing.Generic[~T]):
13class PagedResult(BaseModel, Generic[T]):
14    """Wrapper returned by all ``list()`` methods.
15
16    Holds the pagination metadata returned by paperless-ngx alongside the
17    deserialized resource items.
18
19    Attributes:
20        count: Total number of matching items as reported by the server on
21            the first fetched page.
22        next: URL of the next page as returned by the API, or ``None``.
23            Always ``None`` when auto-pagination is active (the default
24            ``page=None``), because the navigation URL is meaningless once
25            all pages have been consumed by the library.
26        previous: URL of the previous page as returned by the API, or
27            ``None``.  Always ``None`` when auto-pagination is active.
28        all: All matching item IDs when the API includes them; ``None``
29            otherwise.
30        results: The deserialized resource items for this page / all fetched
31            pages.
32    """
33
34    count: int
35    next: str | None = None
36    previous: str | None = None
37    all: List[int] | None = None
38    results: List[T] = Field(default_factory=list)

Wrapper returned by all list() methods.

Holds the pagination metadata returned by paperless-ngx alongside the deserialized resource items.

Attributes:
  • count: Total number of matching items as reported by the server on the first fetched page.
  • next: URL of the next page as returned by the API, or None. Always None when auto-pagination is active (the default page=None), because the navigation URL is meaningless once all pages have been consumed by the library.
  • previous: URL of the previous page as returned by the API, or None. Always None when auto-pagination is active.
  • all: All matching item IDs when the API includes them; None otherwise.
  • results: The deserialized resource items for this page / all fetched pages.
count: int = PydanticUndefined
next: str | None = None
previous: str | None = None
all: Optional[List[int]] = None
results: List[~T] = PydanticUndefined
class AuditLogActor(pydantic.main.BaseModel):
82class AuditLogActor(BaseModel):
83    """The user who performed an audited action.
84
85    Attributes:
86        id: Numeric user ID.
87        username: Username of the actor.
88    """
89
90    model_config = ConfigDict(extra="ignore")
91
92    id: int
93    username: str

The user who performed an audited action.

Attributes:
  • id: Numeric user ID.
  • username: Username of the actor.
id: int = PydanticUndefined
username: str = PydanticUndefined
class AuditLogEntry(pydantic.main.BaseModel):
 96class AuditLogEntry(BaseModel):
 97    """A single entry in a document's audit log.
 98
 99    Attributes:
100        id: Unique audit log entry ID.
101        timestamp: When the action occurred.
102        action: Action type (e.g. ``"create"``, ``"update"``).
103        changes: Free-form dict describing what changed.  Keys and value
104            shapes vary by action type.
105        actor: The user who performed the action, or ``None`` for
106            system-generated entries.
107    """
108
109    model_config = ConfigDict(extra="ignore")
110
111    id: int
112    timestamp: datetime
113    action: str
114    changes: dict[str, Any]
115    actor: AuditLogActor | None = None

A single entry in a document's audit log.

Attributes:
  • id: Unique audit log entry ID.
  • timestamp: When the action occurred.
  • action: Action type (e.g. "create", "update").
  • changes: Free-form dict describing what changed. Keys and value shapes vary by action type.
  • actor: The user who performed the action, or None for system-generated entries.
id: int = PydanticUndefined
timestamp: datetime.datetime = PydanticUndefined
action: str = PydanticUndefined
changes: dict[str, typing.Any] = PydanticUndefined
actor: AuditLogActor | None = None
class Correspondent(pydantic.main.BaseModel):
13class Correspondent(BaseModel):
14    """A paperless-ngx correspondent (sender or recipient of a document).
15
16    Attributes:
17        id: Unique correspondent ID.
18        name: Correspondent name.
19        document_count: Number of documents assigned to this correspondent.
20        last_correspondence: Date of the most recent document assigned here,
21            or ``None``.
22    """
23
24    model_config = ConfigDict(extra="ignore")
25
26    id: int
27    name: str
28    slug: str | None = None
29    match: str | None = None
30    matching_algorithm: MatchingAlgorithm | None = None
31    is_insensitive: bool | None = None
32    document_count: int | None = None
33    last_correspondence: date | None = None
34    owner: int | None = None
35    user_can_change: bool | None = None

A paperless-ngx correspondent (sender or recipient of a document).

Attributes:
  • id: Unique correspondent ID.
  • name: Correspondent name.
  • document_count: Number of documents assigned to this correspondent.
  • last_correspondence: Date of the most recent document assigned here, or None.
id: int = PydanticUndefined
name: str = PydanticUndefined
slug: str | None = None
match: str | None = None
matching_algorithm: MatchingAlgorithm | None = None
is_insensitive: bool | None = None
document_count: int | None = None
last_correspondence: datetime.date | None = None
owner: int | None = None
user_can_change: bool | None = None
class CustomField(pydantic.main.BaseModel):
26class CustomField(BaseModel):
27    """A custom field definition in paperless-ngx.
28
29    Attributes:
30        id: Unique custom-field ID.
31        name: Field name shown in the UI.
32        data_type: The value type for this field (see
33            :class:`FieldDataType`).
34        extra_data: Additional configuration (e.g. select options), or
35            ``None``.
36        document_count: Number of documents that have a value for this field.
37    """
38
39    model_config = ConfigDict(extra="ignore")
40
41    id: int
42    name: str
43    data_type: FieldDataType
44    extra_data: Any = None
45    document_count: int | None = None

A custom field definition in paperless-ngx.

Attributes:
  • id: Unique custom-field ID.
  • name: Field name shown in the UI.
  • data_type: The value type for this field (see FieldDataType).
  • extra_data: Additional configuration (e.g. select options), or None.
  • document_count: Number of documents that have a value for this field.
id: int = PydanticUndefined
name: str = PydanticUndefined
data_type: FieldDataType = PydanticUndefined
extra_data: Any = None
document_count: int | None = None
class CustomFieldValue(pydantic.main.BaseModel):
66class CustomFieldValue(BaseModel):
67    """A custom field value attached to a document.
68
69    Attributes:
70        field: ID of the :class:`~easypaperless.models.custom_fields.CustomField`
71            definition.
72        value: The stored value; its Python type depends on the field's
73            ``data_type``.
74    """
75
76    model_config = ConfigDict(extra="ignore")
77
78    field: int
79    value: Any = None

A custom field value attached to a document.

Attributes:
field: int = PydanticUndefined
value: Any = None
class Document(pydantic.main.BaseModel):
209class Document(BaseModel):
210    """A paperless-ngx document.
211
212    Attributes:
213        id: Unique document ID.
214        title: Document title.
215        content: Full OCR text content, if available.
216        tags: List of tag IDs assigned to this document.
217        document_type: ID of the assigned document type, or ``None``.
218        correspondent: ID of the assigned correspondent, or ``None``.
219        storage_path: ID of the assigned storage path, or ``None``.
220        created: Document creation date (``date`` object). Changed from
221            ``datetime`` to ``date`` in paperless-ngx API v9.
222        created_date: Date portion of creation. **Deprecated** by
223            paperless-ngx as of v9 — use ``created`` instead. Will be
224            removed in a future API version.
225        archive_serial_number: Archive serial number (ASN), or ``None``.
226        custom_fields: List of :class:`CustomFieldValue` instances.
227        notes: User notes attached to this document.
228        search_hit: Full-text search relevance metadata, populated only when
229            the document was returned by a full-text search.
230        metadata: Extended file-level metadata (checksums, sizes, MIME type).
231            ``None`` unless the document was fetched with
232            ``include_metadata=True`` or retrieved via
233            :meth:`~easypaperless._internal.resources.documents.DocumentsResource.get_metadata`.
234    """
235
236    model_config = ConfigDict(extra="ignore", populate_by_name=True)
237
238    id: int
239    title: str
240    content: str | None = None
241    tags: list[int] = Field(default_factory=list)
242    document_type: int | None = None
243    correspondent: int | None = None
244    storage_path: int | None = None
245    created: date | None = None
246    created_date: date | None = None
247    modified: datetime | None = None
248    added: datetime | None = None
249    archive_serial_number: int | None = None
250    original_file_name: str | None = None
251    archived_file_name: str | None = None
252    owner: int | None = None
253    user_can_change: bool | None = None
254    is_shared_by_requester: bool | None = None
255    notes: list[DocumentNote] = Field(default_factory=list)
256    custom_fields: list[CustomFieldValue] = Field(default_factory=list)
257    search_hit: SearchHit | None = Field(default=None, alias="__search_hit__")
258    metadata: DocumentMetadata | None = None

A paperless-ngx document.

Attributes:
  • id: Unique document ID.
  • title: Document title.
  • content: Full OCR text content, if available.
  • tags: List of tag IDs assigned to this document.
  • document_type: ID of the assigned document type, or None.
  • correspondent: ID of the assigned correspondent, or None.
  • storage_path: ID of the assigned storage path, or None.
  • created: Document creation date (date object). Changed from datetime to date in paperless-ngx API v9.
  • created_date: Date portion of creation. Deprecated by paperless-ngx as of v9 — use created instead. Will be removed in a future API version.
  • archive_serial_number: Archive serial number (ASN), or None.
  • custom_fields: List of CustomFieldValue instances.
  • notes: User notes attached to this document.
  • search_hit: Full-text search relevance metadata, populated only when the document was returned by a full-text search.
  • metadata: Extended file-level metadata (checksums, sizes, MIME type). None unless the document was fetched with include_metadata=True or retrieved via ~easypaperless._internal.resources.documents.DocumentsResource.get_metadata().
id: int = PydanticUndefined
title: str = PydanticUndefined
content: str | None = None
tags: list[int] = PydanticUndefined
document_type: int | None = None
correspondent: int | None = None
storage_path: int | None = None
created: datetime.date | None = None
created_date: datetime.date | None = None
modified: datetime.datetime | None = None
added: datetime.datetime | None = None
archive_serial_number: int | None = None
original_file_name: str | None = None
archived_file_name: str | None = None
owner: int | None = None
user_can_change: bool | None = None
is_shared_by_requester: bool | None = None
notes: list[DocumentNote] = PydanticUndefined
custom_fields: list[CustomFieldValue] = PydanticUndefined
search_hit: SearchHit | None = None
metadata: DocumentMetadata | None = None
class DocumentMetadata(pydantic.main.BaseModel):
167class DocumentMetadata(BaseModel):
168    """Extended file-level metadata for a document.
169
170    Returned by ``GET /api/documents/{id}/metadata/`` and optionally attached
171    to a :class:`Document` when
172    :meth:`~easypaperless._internal.resources.documents.DocumentsResource.get`
173    is called with ``include_metadata=True``.
174
175    Because reading metadata requires disk I/O it is **not** included in
176    document list responses; it must be requested explicitly.
177
178    Attributes:
179        original_checksum: MD5 checksum of the original uploaded file.
180        original_size: Size of the original file in bytes.
181        original_mime_type: MIME type of the original file
182            (e.g. ``"application/pdf"``).
183        media_filename: Path of the archived file relative to the
184            paperless-ngx media root.
185        has_archive_version: ``True`` when paperless-ngx has produced an
186            archived (post-processed) PDF in addition to the original.
187        original_metadata: File-level metadata entries extracted from the
188            original document (PDF XMP/info tags, etc.).
189        archive_checksum: MD5 checksum of the archived file, or ``None`` if
190            no archive version exists.
191        archive_size: Size of the archived file in bytes, or ``None``.
192        archive_metadata: File-level metadata entries from the archived
193            document, or ``None``.
194    """
195
196    model_config = ConfigDict(extra="ignore")
197
198    original_checksum: str | None = None
199    original_size: int | None = None
200    original_mime_type: str | None = None
201    media_filename: str | None = None
202    has_archive_version: bool | None = None
203    original_metadata: list[FileMetadataEntry] = Field(default_factory=list)
204    archive_checksum: str | None = None
205    archive_size: int | None = None
206    archive_metadata: list[FileMetadataEntry] | None = None

Extended file-level metadata for a document.

Returned by GET /api/documents/{id}/metadata/ and optionally attached to a Document when ~easypaperless._internal.resources.documents.DocumentsResource.get() is called with include_metadata=True.

Because reading metadata requires disk I/O it is not included in document list responses; it must be requested explicitly.

Attributes:
  • original_checksum: MD5 checksum of the original uploaded file.
  • original_size: Size of the original file in bytes.
  • original_mime_type: MIME type of the original file (e.g. "application/pdf").
  • media_filename: Path of the archived file relative to the paperless-ngx media root.
  • has_archive_version: True when paperless-ngx has produced an archived (post-processed) PDF in addition to the original.
  • original_metadata: File-level metadata entries extracted from the original document (PDF XMP/info tags, etc.).
  • archive_checksum: MD5 checksum of the archived file, or None if no archive version exists.
  • archive_size: Size of the archived file in bytes, or None.
  • archive_metadata: File-level metadata entries from the archived document, or None.
original_checksum: str | None = None
original_size: int | None = None
original_mime_type: str | None = None
media_filename: str | None = None
has_archive_version: bool | None = None
original_metadata: list[FileMetadataEntry] = PydanticUndefined
archive_checksum: str | None = None
archive_size: int | None = None
archive_metadata: list[FileMetadataEntry] | None = None
class DocumentNote(pydantic.main.BaseModel):
118class DocumentNote(BaseModel):
119    """A user note attached to a document.
120
121    Attributes:
122        id: Unique note ID.
123        note: Text content of the note.
124        created: Timestamp when the note was created.
125        document: ID of the parent document.
126        user: ID of the user who created the note.
127    """
128
129    model_config = ConfigDict(extra="ignore")
130
131    id: int | None = None
132    note: str
133    created: datetime | None = None
134    document: int | None = None
135    user: int | None = None
136
137    @field_validator("user", mode="before")
138    @classmethod
139    def _coerce_user(cls, v: object) -> int | None:
140        if isinstance(v, dict):
141            return v.get("id")
142        return v  # type: ignore[return-value]

A user note attached to a document.

Attributes:
  • id: Unique note ID.
  • note: Text content of the note.
  • created: Timestamp when the note was created.
  • document: ID of the parent document.
  • user: ID of the user who created the note.
id: int | None = None
note: str = PydanticUndefined
created: datetime.datetime | None = None
document: int | None = None
user: int | None = None
class DocumentType(pydantic.main.BaseModel):
11class DocumentType(BaseModel):
12    """A paperless-ngx document type (e.g. Invoice, Receipt, Contract).
13
14    Attributes:
15        id: Unique document-type ID.
16        name: Document-type name.
17        document_count: Number of documents assigned to this document type.
18    """
19
20    model_config = ConfigDict(extra="ignore")
21
22    id: int
23    name: str
24    slug: str | None = None
25    match: str | None = None
26    matching_algorithm: MatchingAlgorithm | None = None
27    is_insensitive: bool | None = None
28    document_count: int | None = None
29    owner: int | None = None
30    user_can_change: bool | None = None

A paperless-ngx document type (e.g. Invoice, Receipt, Contract).

Attributes:
  • id: Unique document-type ID.
  • name: Document-type name.
  • document_count: Number of documents assigned to this document type.
id: int = PydanticUndefined
name: str = PydanticUndefined
slug: str | None = None
match: str | None = None
matching_algorithm: MatchingAlgorithm | None = None
is_insensitive: bool | None = None
document_count: int | None = None
owner: int | None = None
user_can_change: bool | None = None
class FieldDataType(enum.StrEnum):
12class FieldDataType(StrEnum):
13    """Allowed data types for a custom field."""
14
15    string = "string"
16    boolean = "boolean"
17    integer = "integer"
18    float = "float"
19    monetary = "monetary"
20    date = "date"
21    url = "url"
22    documentlink = "documentlink"
23    select = "select"

Allowed data types for a custom field.

string = <FieldDataType.string: 'string'>
boolean = <FieldDataType.boolean: 'boolean'>
integer = <FieldDataType.integer: 'integer'>
float = <FieldDataType.float: 'float'>
monetary = <FieldDataType.monetary: 'monetary'>
date = <FieldDataType.date: 'date'>
url = <FieldDataType.url: 'url'>
select = <FieldDataType.select: 'select'>
class FileMetadataEntry(pydantic.main.BaseModel):
145class FileMetadataEntry(BaseModel):
146    """A single embedded metadata key-value pair from a document file.
147
148    Paperless-ngx reads file-level metadata (e.g. PDF XMP/info tags) and
149    exposes each entry in this format.  ``namespace`` and ``prefix`` are
150    ``None`` for non-namespaced entries.
151
152    Attributes:
153        namespace: XML namespace URI, or ``None``.
154        prefix: Namespace prefix (e.g. ``"pdf"``), or ``None``.
155        key: Metadata key (e.g. ``"Producer"``).
156        value: Metadata value as a string.
157    """
158
159    model_config = ConfigDict(extra="ignore")
160
161    namespace: str | None = None
162    prefix: str | None = None
163    key: str
164    value: str

A single embedded metadata key-value pair from a document file.

Paperless-ngx reads file-level metadata (e.g. PDF XMP/info tags) and exposes each entry in this format. namespace and prefix are None for non-namespaced entries.

Attributes:
  • namespace: XML namespace URI, or None.
  • prefix: Namespace prefix (e.g. "pdf"), or None.
  • key: Metadata key (e.g. "Producer").
  • value: Metadata value as a string.
namespace: str | None = None
prefix: str | None = None
key: str = PydanticUndefined
value: str = PydanticUndefined
class PermissionSet(pydantic.main.BaseModel):
7class PermissionSet(BaseModel):
8    users: list[int] = Field(default_factory=list)
9    groups: list[int] = Field(default_factory=list)

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
users: list[int] = PydanticUndefined
groups: list[int] = PydanticUndefined
class SearchHit(pydantic.main.BaseModel):
49class SearchHit(BaseModel):
50    """Full-text search relevance metadata returned alongside a document.
51
52    Attributes:
53        score: Relevance score assigned by the Whoosh FTS engine.
54        highlights: HTML snippet with matching terms highlighted.
55        rank: Position in the result set by relevance.
56    """
57
58    model_config = ConfigDict(extra="ignore")
59
60    score: float | None = None
61    highlights: str | None = None
62    note_highlights: str | None = None
63    rank: int | None = None

Full-text search relevance metadata returned alongside a document.

Attributes:
  • score: Relevance score assigned by the Whoosh FTS engine.
  • highlights: HTML snippet with matching terms highlighted.
  • rank: Position in the result set by relevance.
score: float | None = None
highlights: str | None = None
note_highlights: str | None = None
rank: int | None = None
class SetPermissions(pydantic.main.BaseModel):
12class SetPermissions(BaseModel):
13    view: PermissionSet = Field(default_factory=PermissionSet)
14    change: PermissionSet = Field(default_factory=PermissionSet)

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
view: PermissionSet = PydanticUndefined
change: PermissionSet = PydanticUndefined
class StoragePath(pydantic.main.BaseModel):
11class StoragePath(BaseModel):
12    """A paperless-ngx storage path — controls where archived files are stored.
13
14    Attributes:
15        id: Unique storage-path ID.
16        name: Storage-path name.
17        path: Template string used to build the storage path, e.g.
18            ``"{created_year}/{correspondent}/{title}"``.
19        document_count: Number of documents using this storage path.
20    """
21
22    model_config = ConfigDict(extra="ignore")
23
24    id: int
25    name: str
26    slug: str | None = None
27    path: str | None = None
28    match: str | None = None
29    matching_algorithm: MatchingAlgorithm | None = None
30    is_insensitive: bool | None = None
31    document_count: int | None = None
32    owner: int | None = None
33    user_can_change: bool | None = None

A paperless-ngx storage path — controls where archived files are stored.

Attributes:
  • id: Unique storage-path ID.
  • name: Storage-path name.
  • path: Template string used to build the storage path, e.g. "{created_year}/{correspondent}/{title}".
  • document_count: Number of documents using this storage path.
id: int = PydanticUndefined
name: str = PydanticUndefined
slug: str | None = None
path: str | None = None
match: str | None = None
matching_algorithm: MatchingAlgorithm | None = None
is_insensitive: bool | None = None
document_count: int | None = None
owner: int | None = None
user_can_change: bool | None = None
class Tag(pydantic.main.BaseModel):
11class Tag(BaseModel):
12    """A paperless-ngx tag.
13
14    Attributes:
15        id: Unique tag ID.
16        name: Tag name.
17        color: Hex colour code used in the UI (e.g. ``"#ff0000"``).
18        is_inbox_tag: If ``True``, newly ingested documents receive this tag
19            automatically until they are processed.
20        document_count: Number of documents currently assigned to this tag.
21        parent: ID of the parent tag for hierarchical tag trees, or ``None``.
22        children: IDs of child tags, or ``None``.
23    """
24
25    model_config = ConfigDict(extra="ignore")
26
27    id: int
28    name: str
29    slug: str | None = None
30    color: str | None = None
31    text_color: str | None = None
32    match: str | None = None
33    matching_algorithm: MatchingAlgorithm | None = None
34    is_insensitive: bool | None = None
35    is_inbox_tag: bool | None = None
36    document_count: int | None = None
37    owner: int | None = None
38    user_can_change: bool | None = None
39    parent: int | None = None
40    children: list[int] | None = None

A paperless-ngx tag.

Attributes:
  • id: Unique tag ID.
  • name: Tag name.
  • color: Hex colour code used in the UI (e.g. "#ff0000").
  • is_inbox_tag: If True, newly ingested documents receive this tag automatically until they are processed.
  • document_count: Number of documents currently assigned to this tag.
  • parent: ID of the parent tag for hierarchical tag trees, or None.
  • children: IDs of child tags, or None.
id: int = PydanticUndefined
name: str = PydanticUndefined
slug: str | None = None
color: str | None = None
text_color: str | None = None
match: str | None = None
matching_algorithm: MatchingAlgorithm | None = None
is_insensitive: bool | None = None
is_inbox_tag: bool | None = None
document_count: int | None = None
owner: int | None = None
user_can_change: bool | None = None
parent: int | None = None
children: list[int] | None = None
class Task(pydantic.main.BaseModel):
24class Task(BaseModel):
25    """A paperless-ngx background processing task (e.g. document ingestion).
26
27    Attributes:
28        task_id: Unique Celery task identifier.
29        task_file_name: Original file name submitted for processing.
30        status: Current task status as a :class:`TaskStatus` enum value.
31        result: Human-readable result or error message, set on completion.
32        related_document: String representation of the resulting document ID
33            on success, ``None`` otherwise.
34    """
35
36    model_config = ConfigDict(extra="ignore")
37
38    task_id: str
39    task_file_name: str | None = None
40    date_created: datetime | None = None
41    date_done: datetime | None = None
42    type: str | None = None
43    status: TaskStatus | None = None
44    result: str | None = None
45    acknowledged: bool | None = None
46    related_document: str | None = None

A paperless-ngx background processing task (e.g. document ingestion).

Attributes:
  • task_id: Unique Celery task identifier.
  • task_file_name: Original file name submitted for processing.
  • status: Current task status as a TaskStatus enum value.
  • result: Human-readable result or error message, set on completion.
  • related_document: String representation of the resulting document ID on success, None otherwise.
task_id: str = PydanticUndefined
task_file_name: str | None = None
date_created: datetime.datetime | None = None
date_done: datetime.datetime | None = None
type: str | None = None
status: TaskStatus | None = None
result: str | None = None
acknowledged: bool | None = None
related_document: str | None = None
class TaskStatus(enum.StrEnum):
13class TaskStatus(StrEnum):
14    """Status values for a paperless-ngx background processing task."""
15
16    PENDING = "PENDING"
17    STARTED = "STARTED"
18    SUCCESS = "SUCCESS"
19    FAILURE = "FAILURE"
20    RETRY = "RETRY"
21    REVOKED = "REVOKED"

Status values for a paperless-ngx background processing task.

PENDING = <TaskStatus.PENDING: 'PENDING'>
STARTED = <TaskStatus.STARTED: 'STARTED'>
SUCCESS = <TaskStatus.SUCCESS: 'SUCCESS'>
FAILURE = <TaskStatus.FAILURE: 'FAILURE'>
RETRY = <TaskStatus.RETRY: 'RETRY'>
REVOKED = <TaskStatus.REVOKED: 'REVOKED'>
class User(pydantic.main.BaseModel):
205class User(BaseModel):
206    """A paperless-ngx user account.
207
208    Attributes:
209        id: Unique user ID (set by the API).
210        username: Login username.
211        email: Email address.
212        password: Password field as returned by the API (write-only in practice).
213        first_name: Given name.
214        last_name: Family name.
215        date_joined: Timestamp of account creation.
216        is_staff: Whether the user has staff (admin UI) access.
217        is_active: Whether the account is active.
218        is_superuser: Whether the user has unrestricted superuser access.
219        groups: IDs of groups the user belongs to.
220        user_permissions: Directly assigned permission strings.
221        inherited_permissions: Effective permissions inherited from groups
222            (read-only, not sent on create/update).
223        is_mfa_enabled: Whether multi-factor authentication is enabled
224            (read-only, not sent on create/update).
225    """
226
227    model_config = ConfigDict(extra="ignore")
228
229    id: int
230    username: str
231    email: str | None = None
232    password: str | None = None
233    first_name: str | None = None
234    last_name: str | None = None
235    date_joined: datetime | None = None
236    is_staff: bool | None = None
237    is_active: bool | None = None
238    is_superuser: bool | None = None
239    groups: list[int] | None = None
240    user_permissions: list[str] | None = None
241    inherited_permissions: list[str] | None = None
242    is_mfa_enabled: bool | None = None

A paperless-ngx user account.

Attributes:
  • id: Unique user ID (set by the API).
  • username: Login username.
  • email: Email address.
  • password: Password field as returned by the API (write-only in practice).
  • first_name: Given name.
  • last_name: Family name.
  • date_joined: Timestamp of account creation.
  • is_staff: Whether the user has staff (admin UI) access.
  • is_active: Whether the account is active.
  • is_superuser: Whether the user has unrestricted superuser access.
  • groups: IDs of groups the user belongs to.
  • user_permissions: Directly assigned permission strings.
  • inherited_permissions: Effective permissions inherited from groups (read-only, not sent on create/update).
  • is_mfa_enabled: Whether multi-factor authentication is enabled (read-only, not sent on create/update).
id: int = PydanticUndefined
username: str = PydanticUndefined
email: str | None = None
password: str | None = None
first_name: str | None = None
last_name: str | None = None
date_joined: datetime.datetime | None = None
is_staff: bool | None = None
is_active: bool | None = None
is_superuser: bool | None = None
groups: list[int] | None = None
user_permissions: list[str] | None = None
inherited_permissions: list[str] | None = None
is_mfa_enabled: bool | None = None
PaperlessPermission = typing.Literal['account.add_emailaddress', 'account.add_emailconfirmation', 'account.change_emailaddress', 'account.change_emailconfirmation', 'account.delete_emailaddress', 'account.delete_emailconfirmation', 'account.view_emailaddress', 'account.view_emailconfirmation', 'admin.add_logentry', 'admin.change_logentry', 'admin.delete_logentry', 'admin.view_logentry', 'auth.add_group', 'auth.add_permission', 'auth.add_user', 'auth.change_group', 'auth.change_permission', 'auth.change_user', 'auth.delete_group', 'auth.delete_permission', 'auth.delete_user', 'auth.view_group', 'auth.view_permission', 'auth.view_user', 'authtoken.add_token', 'authtoken.add_tokenproxy', 'authtoken.change_token', 'authtoken.change_tokenproxy', 'authtoken.delete_token', 'authtoken.delete_tokenproxy', 'authtoken.view_token', 'authtoken.view_tokenproxy', 'auditlog.add_logentry', 'auditlog.change_logentry', 'auditlog.delete_logentry', 'auditlog.view_logentry', 'contenttypes.add_contenttype', 'contenttypes.change_contenttype', 'contenttypes.delete_contenttype', 'contenttypes.view_contenttype', 'django_celery_results.add_chordcounter', 'django_celery_results.add_groupresult', 'django_celery_results.add_taskresult', 'django_celery_results.change_chordcounter', 'django_celery_results.change_groupresult', 'django_celery_results.change_taskresult', 'django_celery_results.delete_chordcounter', 'django_celery_results.delete_groupresult', 'django_celery_results.delete_taskresult', 'django_celery_results.view_chordcounter', 'django_celery_results.view_groupresult', 'django_celery_results.view_taskresult', 'documents.add_correspondent', 'documents.add_customfield', 'documents.add_customfieldinstance', 'documents.add_document', 'documents.add_documenttype', 'documents.add_log', 'documents.add_note', 'documents.add_paperlesstask', 'documents.add_savedview', 'documents.add_savedviewfilterrule', 'documents.add_sharelink', 'documents.add_storagepath', 'documents.add_tag', 'documents.add_uisettings', 'documents.add_workflow', 'documents.add_workflowaction', 'documents.add_workflowactionemail', 'documents.add_workflowactionwebhook', 'documents.add_workflowrun', 'documents.add_workflowtrigger', 'documents.change_correspondent', 'documents.change_customfield', 'documents.change_customfieldinstance', 'documents.change_document', 'documents.change_documenttype', 'documents.change_log', 'documents.change_note', 'documents.change_paperlesstask', 'documents.change_savedview', 'documents.change_savedviewfilterrule', 'documents.change_sharelink', 'documents.change_storagepath', 'documents.change_tag', 'documents.change_uisettings', 'documents.change_workflow', 'documents.change_workflowaction', 'documents.change_workflowactionemail', 'documents.change_workflowactionwebhook', 'documents.change_workflowrun', 'documents.change_workflowtrigger', 'documents.delete_correspondent', 'documents.delete_customfield', 'documents.delete_customfieldinstance', 'documents.delete_document', 'documents.delete_documenttype', 'documents.delete_log', 'documents.delete_note', 'documents.delete_paperlesstask', 'documents.delete_savedview', 'documents.delete_savedviewfilterrule', 'documents.delete_sharelink', 'documents.delete_storagepath', 'documents.delete_tag', 'documents.delete_uisettings', 'documents.delete_workflow', 'documents.delete_workflowaction', 'documents.delete_workflowactionemail', 'documents.delete_workflowactionwebhook', 'documents.delete_workflowrun', 'documents.delete_workflowtrigger', 'documents.view_correspondent', 'documents.view_customfield', 'documents.view_customfieldinstance', 'documents.view_document', 'documents.view_documenttype', 'documents.view_log', 'documents.view_note', 'documents.view_paperlesstask', 'documents.view_savedview', 'documents.view_savedviewfilterrule', 'documents.view_sharelink', 'documents.view_storagepath', 'documents.view_tag', 'documents.view_uisettings', 'documents.view_workflow', 'documents.view_workflowaction', 'documents.view_workflowactionemail', 'documents.view_workflowactionwebhook', 'documents.view_workflowrun', 'documents.view_workflowtrigger', 'guardian.add_groupobjectpermission', 'guardian.add_userobjectpermission', 'guardian.change_groupobjectpermission', 'guardian.change_userobjectpermission', 'guardian.delete_groupobjectpermission', 'guardian.delete_userobjectpermission', 'guardian.view_groupobjectpermission', 'guardian.view_userobjectpermission', 'mfa.add_authenticator', 'mfa.change_authenticator', 'mfa.delete_authenticator', 'mfa.view_authenticator', 'paperless.add_applicationconfiguration', 'paperless.change_applicationconfiguration', 'paperless.delete_applicationconfiguration', 'paperless.view_applicationconfiguration', 'paperless_mail.add_mailaccount', 'paperless_mail.add_mailrule', 'paperless_mail.add_processedmail', 'paperless_mail.change_mailaccount', 'paperless_mail.change_mailrule', 'paperless_mail.change_processedmail', 'paperless_mail.delete_mailaccount', 'paperless_mail.delete_mailrule', 'paperless_mail.delete_processedmail', 'paperless_mail.view_mailaccount', 'paperless_mail.view_mailrule', 'paperless_mail.view_processedmail', 'sessions.add_session', 'sessions.change_session', 'sessions.delete_session', 'sessions.view_session', 'socialaccount.add_socialaccount', 'socialaccount.add_socialapp', 'socialaccount.add_socialtoken', 'socialaccount.change_socialaccount', 'socialaccount.change_socialapp', 'socialaccount.change_socialtoken', 'socialaccount.delete_socialaccount', 'socialaccount.delete_socialapp', 'socialaccount.delete_socialtoken', 'socialaccount.view_socialaccount', 'socialaccount.view_socialapp', 'socialaccount.view_socialtoken']
class PaperlessError(builtins.Exception):
 7class PaperlessError(Exception):
 8    """Base exception for all easypaperless errors.
 9
10    Attributes:
11        status_code: The HTTP status code associated with the error, or
12            ``None`` for non-HTTP errors (e.g. timeouts, local validation).
13    """
14
15    def __init__(self, message: str, status_code: int | None = None) -> None:
16        """Create a PaperlessError.
17
18        Args:
19            message: Human-readable error description.
20            status_code: HTTP status code, if applicable.
21        """
22        super().__init__(message)
23        self.status_code = status_code

Base exception for all easypaperless errors.

Attributes:
  • status_code: The HTTP status code associated with the error, or None for non-HTTP errors (e.g. timeouts, local validation).
PaperlessError(message: str, status_code: int | None = None)
15    def __init__(self, message: str, status_code: int | None = None) -> None:
16        """Create a PaperlessError.
17
18        Args:
19            message: Human-readable error description.
20            status_code: HTTP status code, if applicable.
21        """
22        super().__init__(message)
23        self.status_code = status_code

Create a PaperlessError.

Arguments:
  • message: Human-readable error description.
  • status_code: HTTP status code, if applicable.
status_code
class AuthError(easypaperless.PaperlessError):
26class AuthError(PaperlessError):
27    """Raised on 401 or 403 responses.
28
29    Indicates that the API key is missing, invalid, or lacks permission for
30    the requested operation.
31    """

Raised on 401 or 403 responses.

Indicates that the API key is missing, invalid, or lacks permission for the requested operation.

class NotFoundError(easypaperless.PaperlessError):
34class NotFoundError(PaperlessError):
35    """Raised on 404 responses or when a name lookup fails."""

Raised on 404 responses or when a name lookup fails.

class ValidationError(easypaperless.PaperlessError):
38class ValidationError(PaperlessError):
39    """Raised on 422 responses or bad input supplied by the caller."""

Raised on 422 responses or bad input supplied by the caller.

class ServerError(easypaperless.PaperlessError):
42class ServerError(PaperlessError):
43    """Raised on 5xx responses or unrecoverable transport errors."""

Raised on 5xx responses or unrecoverable transport errors.

class UploadError(easypaperless.PaperlessError):
46class UploadError(PaperlessError):
47    """Raised when file submission or document processing fails.
48
49    Typically raised when paperless-ngx reports a ``FAILURE`` status on the
50    Celery task created by
51    :meth:`~easypaperless.client.PaperlessClient.upload_document`.
52    """

Raised when file submission or document processing fails.

Typically raised when paperless-ngx reports a FAILURE status on the Celery task created by ~easypaperless.client.PaperlessClient.upload_document().

class TaskTimeoutError(easypaperless.PaperlessError):
55class TaskTimeoutError(PaperlessError):
56    """Raised when upload polling exceeds the configured timeout.
57
58    Raised by :meth:`~easypaperless.client.PaperlessClient.upload_document`
59    (with ``wait=True``) when the document processing task does not reach a
60    terminal state within ``poll_timeout`` seconds.
61    """
62
63    def __init__(self, message: str) -> None:
64        super().__init__(message, status_code=None)

Raised when upload polling exceeds the configured timeout.

Raised by ~easypaperless.client.PaperlessClient.upload_document() (with wait=True) when the document processing task does not reach a terminal state within poll_timeout seconds.

TaskTimeoutError(message: str)
63    def __init__(self, message: str) -> None:
64        super().__init__(message, status_code=None)

Create a PaperlessError.

Arguments:
  • message: Human-readable error description.
  • status_code: HTTP status code, if applicable.
class RetryExhaustedError(easypaperless.PaperlessError):
67class RetryExhaustedError(PaperlessError):
68    """Raised when all retry attempts are exhausted.
69
70    Attributes:
71        attempts: Total number of attempts made (initial + retries).
72        url: The URL that was requested.
73    """
74
75    def __init__(self, message: str, attempts: int, url: str) -> None:
76        """Create a RetryExhaustedError.
77
78        Args:
79            message: Human-readable error description.
80            attempts: Total number of attempts made.
81            url: The URL that was requested.
82        """
83        super().__init__(message, status_code=None)
84        self.attempts = attempts
85        self.url = url

Raised when all retry attempts are exhausted.

Attributes:
  • attempts: Total number of attempts made (initial + retries).
  • url: The URL that was requested.
RetryExhaustedError(message: str, attempts: int, url: str)
75    def __init__(self, message: str, attempts: int, url: str) -> None:
76        """Create a RetryExhaustedError.
77
78        Args:
79            message: Human-readable error description.
80            attempts: Total number of attempts made.
81            url: The URL that was requested.
82        """
83        super().__init__(message, status_code=None)
84        self.attempts = attempts
85        self.url = url

Create a RetryExhaustedError.

Arguments:
  • message: Human-readable error description.
  • attempts: Total number of attempts made.
  • url: The URL that was requested.
attempts
url