paperless

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 15 Imported by: 0

README

go-paperless

CI Go Reference Go

Paperless-ngx REST client SDK for Go.

One client, two consumers: InboxClean and bank-sync share this client instead of maintaining divergent forks. Scope is deliberately client only — document sync pipelines are domain-coupled and stay in the consuming repos.

Features

  • Upload documents (content-hash friendly metadata: tags, correspondents, document types, custom fields)
  • Ensure* idempotent lookups: EnsureTag, EnsureCorrespondent, EnsureDocumentType, EnsureCustomField, EnsureStoragePath (tags self-heal legacy auto-matching; storage paths keep their existing directory template)
  • Task polling (GetTask, TaskOutcome, WaitForTask) for Paperless' async consumption pipeline, including duplicate-refusal detection (TaskOutcome.Duplicate)
  • Document management: list checksums/metadata, update metadata, download, delete
  • Document notes: ListDocumentNotes, AddDocumentNote, DeleteDocumentNote
  • Share links: CreateShareLink (server-generated slug), ListShareLinks, DeleteShareLink
  • Saved views: ListSavedViews, CreateSavedView, DeleteSavedView
  • Storage paths: FindStoragePath, EnsureStoragePath, ListStoragePaths
  • Name resolution: GetCorrespondentName, GetDocumentTypeName
  • Capability probing (ProbeCapabilities) for version differences
  • Respectful retry: RetryAfterError carries Retry-After hints; opt-in automatic retries via WithRetry(RetryPolicy) (transient-only, bodies replay, hints override backoff)
  • Observability hooks: WithRequestHook / WithResponseHook value snapshots
  • Typed errors via go-error-family

Installation

go get github.com/larsartmann/go-paperless

Requirements

Go 1.27+. The module uses encoding/json/v2, which is the default there — no GOEXPERIMENT is needed. (On a Go ≤ 1.26 toolchain json/v2 only exists behind GOEXPERIMENT=jsonv2, and builds fail with "build constraints exclude all Go files" without it.)

Getting started

package main

import (
	"context"
	"fmt"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New("http://paperless.local:8000", "my-token")
	if err != nil {
		panic(err)
	}
	ctx := context.Background()
	if err := client.Ping(ctx); err != nil {
		panic(err)
	}
	tagID, err := client.EnsureTag(ctx, "inboxclean")
	if err != nil {
		panic(err)
	}
	fmt.Println(tagID)
}

Options

Option Effect
WithHTTPClient(*http.Client) Use a custom HTTP client (transport, proxies, timeouts)
WithTimeout(time.Duration) Per-request timeout on the default client
WithRetry(RetryPolicy) Opt-in automatic retries for transient failures (default: fail fast)
WithRequestHook(func(RequestInfo)) Observe every outgoing request (headers include the token — redact)
WithResponseHook(func(ResponseInfo)) Observe every response (2xx full body; errors capped at 512 bytes)

Retries

Retries are opt-in and cover transient failures only (network errors, 429, 5xx). Rejections (401/403, other 4xx) fail fast. Request bodies replay byte-for-byte per attempt; a server Retry-After hint overrides the exponential backoff.

client, err := paperless.New(url, token, paperless.WithRetry(paperless.RetryPolicy{
    MaxAttempts: 4,
}))

Lookup verbs

Verb Contract
Get* Read by ID; not found is an error or a false flag
Find* Read-only exact-name lookup; returns exists=false when absent
Ensure* Find-or-create; never mutates an existing object's config

Development

nix develop          # dev shell (Go 1.27, GOEXPERIMENT=jsonv2,simd)
nix run .#check      # all checks (build, test, lint, format)
nix build            # build the client (packages.default)
nix run .#build      # build
nix run .#test       # tests
nix run .#test-race  # tests with race detector
nix run .#lint       # golangci-lint
nix fmt              # format
nix flake check      # all checks (CI equivalent)

License

MIT — see LICENSE.

For security reporting, see SECURITY.md; to contribute, see CONTRIBUTING.md.

Documentation

Overview

Package paperless provides a Go client for the Paperless-ngx REST API: document upload, tag/correspondent/type/custom-field management, task polling, and document management.

It targets API version 10 and authenticates via the static token scheme (`Authorization: Token <token>`), which users generate in the Paperless-ngx web UI under "My Profile".

Requirements

Go 1.27 or newer. The module decodes with `encoding/json/v2`, which is part of the standard library there. On a Go 1.26 or older toolchain it only exists behind `GOEXPERIMENT=jsonv2` and builds fail without it.

Options

WithHTTPClient(*http.Client) — use a custom HTTP client (transport, proxies, timeouts)
WithTimeout(time.Duration)   — per-request timeout on the default client

Index

Examples

Constants

View Source
const (
	// DefaultMaxIdleConns is the total idle connection pool size.
	DefaultMaxIdleConns = 100
	// DefaultMaxIdleConnsPerHost is the per-host idle pool — the value that
	// actually matters when all traffic targets one API host.
	DefaultMaxIdleConnsPerHost = 8
	// DefaultIdleConnTimeout matches the default transport's 90s so pooled
	// connections do not outlive typical server keep-alive windows.
	DefaultIdleConnTimeout = 90 * time.Second
)

Default transport tuning shared by every consumer of this SDK. The default transport keeps only 2 idle connections per host, so parallel requests to the single Paperless-ngx host would close and re-handshake TLS connections constantly; a cloned transport with a per-host idle pool turns that into connection reuse.

View Source
const (
	// DefaultRetryMaxAttempts is the total attempt count including the first
	// call when a RetryPolicy leaves MaxAttempts unset.
	DefaultRetryMaxAttempts = 3
	// DefaultRetryInitialDelay is the pause before the second attempt when a
	// RetryPolicy leaves InitialDelay unset.
	DefaultRetryInitialDelay = 100 * time.Millisecond
	// DefaultRetryMaxDelay caps the exponential backoff when a RetryPolicy
	// leaves MaxDelay unset.
	DefaultRetryMaxDelay = 5 * time.Second
	// DefaultRetryMultiplier is the backoff growth factor when a RetryPolicy
	// leaves Multiplier unset.
	DefaultRetryMultiplier = 2.0
)

Default retry tuning for WithRetry, mirroring go-retry's defaults.

View Source
const DefaultTaskPollInterval = 2 * time.Second

DefaultTaskPollInterval is the pause between polls used by WaitForTask when the caller passes a non-positive interval.

Variables

View Source
var ErrInvalidConfig = errors.New("paperless: base URL and token are required")

ErrInvalidConfig is returned when the client is constructed with a missing base URL or token. The integration is optional; callers that have not configured Paperless should never construct a client.

Functions

This section is empty.

Types

type Capabilities

type Capabilities struct {
	// AcceptAPIVersion echoes the API version the server negotiated from
	// the Accept header (empty when the response omits it).
	AcceptAPIVersion string
	// FlatChecksum: sampled documents carry the legacy flat checksum field.
	FlatChecksum bool
	// VersionedChecksum: sampled documents carry checksums in versions[].
	VersionedChecksum bool
	// DocumentsSampled is how many documents the probe inspected.
	DocumentsSampled int
}

Capabilities reports what the connected Paperless-ngx server actually serves. The checksum shape is the load-bearing part: --verify, --prune, and --backfill all reconcile by checksum, and since paperless-ngx 3.x the flat checksum field is gone from the serializers (served via versions[] instead) — a server serving NEITHER shape makes every ledger row look drifted. Doctor surfaces this before it bites.

func (Capabilities) ChecksumShape

func (c Capabilities) ChecksumShape() string

ChecksumShape names the checksum delivery the server uses, for humans.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to a single Paperless-ngx instance. The zero value is not usable — construct via New.

func New

func New(baseURL, token string, opts ...Option) (*Client, error)

New creates a client for the given base URL (e.g. "https://paperless.example.com") and API token. Returns ErrInvalidConfig when either is empty, the URL is not parseable, or a WithRetry policy is malformed. Options customize the HTTP transport.

Example
package main

import (
	"log"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New("https://paperless.example.com", "token-from-web-ui")
	if err != nil {
		log.Fatal(err)
	}

	_ = client // reference the client so the example compiles
}
Example (InvalidConfig)
package main

import (
	"errors"
	"fmt"

	"github.com/larsartmann/go-paperless"
)

func main() {
	_, err := paperless.New("", "token-from-web-ui")
	if errors.Is(err, paperless.ErrInvalidConfig) {
		fmt.Println("configure the base URL before retrying")
	}
}
Output:
configure the base URL before retrying
Example (WithOptions)
package main

import (
	"log"
	"time"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New(
		"https://paperless.example.com",
		"token-from-web-ui",
		paperless.WithTimeout(30*time.Second),
	)
	if err != nil {
		log.Fatal(err)
	}

	_ = client // reference the client so the example compiles
}

func (*Client) AddDocumentNote added in v0.3.0

func (c *Client) AddDocumentNote(
	ctx context.Context,
	documentID int,
	note string,
) ([]DocumentNote, error)

AddDocumentNote appends one note to a document and returns the server's updated note list (the notes endpoint answers every mutation with the full remaining list, newest first).

func (*Client) CreateSavedView added in v0.3.0

func (c *Client) CreateSavedView(
	ctx context.Context,
	req CreateSavedViewRequest,
) (int, error)

CreateSavedView stores one saved view and returns its ID.

func (c *Client) CreateShareLink(
	ctx context.Context,
	req CreateShareLinkRequest,
) (ShareLink, error)

CreateShareLink makes one public download link for a document. The server generates the slug — the POST deliberately sends only the document, the optional file version, and the optional expiration.

func (*Client) DeleteDocument

func (c *Client) DeleteDocument(ctx context.Context, documentID int) error

DeleteDocument permanently removes one document from Paperless-ngx. Used by the backfill's --prune to drop duplicate server-side copies; callers own the destructive-action decision.

func (*Client) DeleteDocumentNote added in v0.3.0

func (c *Client) DeleteDocumentNote(
	ctx context.Context,
	documentID, noteID int,
) ([]DocumentNote, error)

DeleteDocumentNote removes one note from a document and returns the server's updated note list. The note is addressed by the query parameter the endpoint expects (DELETE .../notes/?id=<noteID>).

func (*Client) DeleteSavedView added in v0.3.0

func (c *Client) DeleteSavedView(ctx context.Context, viewID int) error

DeleteSavedView removes one saved view from the server.

func (c *Client) DeleteShareLink(ctx context.Context, linkID int) error

DeleteShareLink revokes one public link; every consumer of the slug loses access immediately.

func (*Client) DownloadDocument

func (c *Client) DownloadDocument(ctx context.Context, documentID int) ([]byte, error)

DownloadDocument fetches one document's stored ORIGINAL file bytes (GET /api/documents/{id}/download/ — not the archive rendition). The decrypt-repair scans them for the /Encrypt trailer before replacing.

func (*Client) EnsureCorrespondent

func (c *Client) EnsureCorrespondent(ctx context.Context, name string) (int, error)

EnsureCorrespondent returns the ID of the correspondent with the given name, creating it when it does not exist yet.

Correspondents keep the "auto" matching algorithm (deliberately, unlike tags): learning "documents from sender X look like this" is exactly the value auto matching adds for documents NOT uploaded by this pipeline (manual scans), and correspondents carry no provenance semantics that auto prediction could corrupt.

func (*Client) EnsureCustomField

func (c *Client) EnsureCustomField(ctx context.Context, name string) (int, error)

EnsureCustomField returns the ID of the custom field definition with the given name, creating it as a string field when missing (paperless-ngx 2.x+ custom fields). Used for the provenance field carrying the Gmail message ID. An existing definition of any data type is kept — the caller decides whether a non-string field is acceptable by the value it assigns.

func (*Client) EnsureDocumentType

func (c *Client) EnsureDocumentType(ctx context.Context, name string) (int, error)

EnsureDocumentType returns the ID of the document type with the given name, creating it with the "none" matching algorithm when missing. A document type applied deterministically at upload time is provenance metadata: classifier-learned matching would leak the type onto manual scans, mirroring the tags rationale. An EXISTING type keeps its configured algorithm — unlike tags there is no legacy-release shape to heal, and overriding a deliberate user config would be wrong.

func (*Client) EnsureStoragePath added in v0.2.0

func (c *Client) EnsureStoragePath(ctx context.Context, name, path string) (int, error)

EnsureStoragePath returns the ID of the storage path with the given name, creating it with the given directory template when missing. An EXISTING path keeps its configured template — mirroring the document type policy: the template is deliberate user config, and overriding it from a sync pipeline would be wrong.

func (*Client) EnsureTag

func (c *Client) EnsureTag(ctx context.Context, name string) (int, error)

EnsureTag returns the ID of the tag with the given name, creating it when it does not exist yet.

Tags are provenance metadata applied deterministically at upload time, so they are created with the "none" matching algorithm: a "gmail" tag that Paperless-ngx's classifier learns to predict would silently leak onto manually scanned documents that merely look similar. An existing tag still carrying "auto" (created by older InboxClean versions) is self-healed to "none" — the classifier then no longer trains against it. Self-healing is tag-specific on purpose: correspondents deliberately keep "auto".

Example

ExampleClient_EnsureTag mirrors the README quick start so signature drift between README and code breaks the build.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New("http://paperless.local:8000", "my-token")
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	tagID, err := client.EnsureTag(ctx, "inboxclean")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(tagID)
}

func (*Client) FindCustomField

func (c *Client) FindCustomField(ctx context.Context, name string) (int, bool, error)

FindCustomField looks up a custom field definition by name WITHOUT creating it — the read-only half of EnsureCustomField, used by dry-run backfills to report what they would record without mutating the server.

func (*Client) FindStoragePath added in v0.2.0

func (c *Client) FindStoragePath(ctx context.Context, name string) (int, bool, error)

FindStoragePath looks up a storage path by exact (case-insensitive) name WITHOUT creating it — the read-only lookup for dry-run reporting.

func (*Client) GetCorrespondentName

func (c *Client) GetCorrespondentName(ctx context.Context, id int) (string, error)

GetCorrespondentName resolves a correspondent ID to its display name. The backfill needs it to decide whether a document's existing non-null correspondent actually matches the derived sender name — an ID alone cannot answer that question.

func (*Client) GetDocumentTypeName

func (c *Client) GetDocumentTypeName(ctx context.Context, id int) (string, error)

GetDocumentTypeName resolves a document type ID to its display name, the document-type sibling of GetCorrespondentName: the backfill compares the stored name against the configured type to repair drifted assignments.

func (*Client) GetTask

func (c *Client) GetTask(ctx context.Context, taskID string) (TaskOutcome, bool, error)

GetTask fetches one consumption task by ID (the UUID Upload returns). found is false when the server has no such task — the record may not be persisted yet (polling callers retry) or was pruned.

The response is expected in the v10 paginated envelope (`{"results": [...]}`); a bare JSON array is tolerated defensively for deployments that predate pagination.

Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New("https://paperless.example.com", "token-from-web-ui")
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	outcome, found, err := client.GetTask(ctx, "0198f7a2-9d3f-7c31-b5e4-5f2a9c1d8e77")
	if err != nil {
		log.Fatal(err)
	}

	if found {
		fmt.Println(outcome.Status, outcome.DocumentID)
	}
}

func (*Client) ListDocumentChecksums

func (c *Client) ListDocumentChecksums(ctx context.Context) (map[string]struct{}, error)

ListDocumentChecksums returns the SHA-256 checksum of every document currently stored in Paperless-ngx. Used to reconcile the local upload ledger against reality: ledger entries whose checksum disappeared from Paperless-ngx (documents deleted there) are candidates for re-upload.

func (*Client) ListDocumentMetas

func (c *Client) ListDocumentMetas(ctx context.Context) ([]DocumentMeta, error)

ListDocumentMetas returns id, title, correspondent, created date, tags, and checksum of every stored document. The backfill matches ledger records against server documents (by checksum) and detects duplicates (same checksum stored more than once).

func (*Client) ListDocumentNotes added in v0.3.0

func (c *Client) ListDocumentNotes(ctx context.Context, documentID int) ([]DocumentNote, error)

ListDocumentNotes returns the notes attached to one document, newest first (the server's ordering). The notes endpoint is not paginated — the response is a bare JSON array.

func (*Client) ListSavedViews added in v0.3.0

func (c *Client) ListSavedViews(ctx context.Context) ([]SavedView, error)

ListSavedViews returns every saved view on the server, paginating the same bounded way as the document listings.

func (c *Client) ListShareLinks(ctx context.Context) ([]ShareLink, error)

ListShareLinks returns every share link on the server, paginating the same bounded way as the document listings.

func (*Client) ListStoragePaths added in v0.2.0

func (c *Client) ListStoragePaths(ctx context.Context) ([]StoragePath, error)

ListStoragePaths returns every storage path definition on the server, paginating the same bounded way as the document listings.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping verifies base URL and token by hitting the authenticated document list view (a real JSON endpoint, bounded to one entry). The API root is deliberately avoided: Paperless-ngx serves it as browsable HTML only, so a JSON Accept header is answered 406 regardless of token validity (observed on paperless 3.0.5 — 406 classified as a client rejection, silently skipping every sync). A 401/403 means the token is wrong; a transport error means the URL is unreachable.

func (*Client) ProbeCapabilities

func (c *Client) ProbeCapabilities(ctx context.Context) (Capabilities, error)

ProbeCapabilities fetches one small documents page and inspects the checksum shapes the server serves. Read-only, one request, safe to run against any paperless-ngx version.

func (*Client) UpdateDocument

func (c *Client) UpdateDocument(
	ctx context.Context,
	documentID int,
	req UpdateDocumentRequest,
) error

UpdateDocument PATCHes one document's metadata. Empty requests are rejected so callers never burn a round trip on a no-op.

func (*Client) Upload

func (c *Client) Upload(ctx context.Context, req UploadRequest) (string, error)

Upload posts a document to the consumption queue. It returns the task ID (UUID) Paperless-ngx assigned; consumption itself is asynchronous — the caller can poll `/api/tasks/?task_id=<id>` for the resulting document.

Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/larsartmann/go-paperless"
)

func main() {
	client, err := paperless.New("https://paperless.example.com", "token-from-web-ui")
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	tagID, err := client.EnsureTag(ctx, "bank-sync")
	if err != nil {
		log.Fatal(err)
	}

	taskID, err := client.Upload(ctx, paperless.UploadRequest{
		Filename: "statement-2026-08.pdf",
		Content:  []byte("%PDF-1.4 ..."),
		Title:    "Statement August 2026",
		TagIDs:   []int{tagID},
	})
	if err != nil {
		log.Fatal(err)
	}

	outcome, found, err := client.GetTask(ctx, taskID)
	if err != nil {
		log.Fatal(err)
	}

	if found && outcome.Status.Terminal() {
		fmt.Println("consumed:", outcome.Status)
	}
}

func (*Client) WaitForTask added in v0.2.0

func (c *Client) WaitForTask(
	ctx context.Context,
	taskID string,
	interval time.Duration,
) (TaskOutcome, error)

WaitForTask polls one consumption task until it reaches a terminal state (success or failure), the context is done, or the server stops answering.

Polling starts immediately; interval is the pause between polls (a non-positive interval means DefaultTaskPollInterval). Bounds come from the context: pass ctx with a deadline/timeout to cap total wait time.

The task may not be visible yet right after Upload returns (the server persists it asynchronously) — that case keeps polling. Transient poll failures (network blips, decode hiccups) also keep polling; the most recent error surfaces only when the context expires.

On a terminal outcome the outcome is fully populated. err is non-nil only for a real terminal failure (status failure without a duplicate refusal — duplicate refusals are honest outcomes, not errors).

type CreateSavedViewRequest added in v0.3.0

type CreateSavedViewRequest struct {
	Name            string
	ShowOnDashboard bool
	ShowInSidebar   bool
	SortField       string
	SortReverse     bool
	FilterRules     []SavedViewFilterRule
}

CreateSavedViewRequest asks for one saved view. Name is required; the filter rules carry the server's numeric rule types.

type CreateShareLinkRequest added in v0.3.0

type CreateShareLinkRequest struct {
	DocumentID  int
	FileVersion ShareLinkFileVersion
	Expiration  *time.Time
}

CreateShareLinkRequest asks for one share link. A zero FileVersion is omitted from the POST so the server applies its default (archive); a nil Expiration means the link never expires.

type CustomFieldValue

type CustomFieldValue struct {
	Field int
	Value string
}

CustomFieldValue assigns a value to one custom field by its definition ID.

type DocumentMeta

type DocumentMeta struct {
	ID             int
	Title          string
	Correspondent  int
	Created        time.Time
	TagIDs         []int
	DocumentTypeID int
	CustomFields   []CustomFieldValue
	Checksum       string
}

DocumentMeta is the metadata snapshot of one stored Paperless-ngx document.

type DocumentNote added in v0.3.0

type DocumentNote struct {
	ID      int
	Note    string
	Created time.Time
	// User is the note's author, or nil when the server cannot resolve it
	// (e.g. the author account was deleted).
	User *DocumentNoteUser
}

DocumentNote is one operator comment attached to a stored document.

type DocumentNoteUser added in v0.3.0

type DocumentNoteUser struct {
	ID        int
	Username  string
	FirstName string
	LastName  string
}

DocumentNoteUser is the (possibly anonymous) author of a document note.

type Option

type Option func(*Client)

Option configures a Client at construction time.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient uses the given HTTP client instead of the default one. Note that a later WithTimeout option still sets Timeout on the supplied client — options apply in order and the last writer wins.

func WithRequestHook added in v0.2.0

func WithRequestHook(hook func(RequestInfo)) Option

WithRequestHook installs an observer called with a snapshot of every outgoing API request before it is sent. The header INCLUDES the Authorization token — hooks that log headers must redact it. The hook observes only; mutating the snapshot has no effect on the request.

func WithResponseHook added in v0.2.0

func WithResponseHook(hook func(ResponseInfo)) Option

WithResponseHook installs an observer called with a snapshot of every API response after its body has been read. The header INCLUDES any Set-Cookie values — hooks that log headers must redact secrets. The hook observes only; mutating the snapshot has no effect on the caller's data.

func WithRetry added in v0.2.0

func WithRetry(policy RetryPolicy) Option

WithRetry turns on automatic retries for transient failures according to the given policy. The fail-fast single-attempt behavior is unchanged unless this option is passed.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the per-request timeout of the client's HTTP client.

type RequestInfo added in v0.2.0

type RequestInfo struct {
	Method string
	URL    string
	Header http.Header
}

RequestInfo is the observation snapshot of one outgoing API request. Body is not included (multipart uploads are single-read streams).

type ResponseInfo added in v0.2.0

type ResponseInfo struct {
	Status int
	Header http.Header
	Body   []byte
}

ResponseInfo is the observation snapshot of one API response. Body is the full body for 2xx responses and the error snippet (capped, see maxErrorBodyBytes) otherwise.

type RetryAfterError

type RetryAfterError struct {
	Err error
	// After is the parsed hint. Seconds-only or HTTP-date forms are
	// accepted; a date in the past parses as 0 (retry immediately).
	After time.Duration
}

RetryAfterError reports a rate-limit (or maintenance) response that carried a Retry-After header. It wraps the classified family error so retry policies can honor the server's hint instead of blind exponential backoff, while IsRetryable keeps working through Unwrap.

func (*RetryAfterError) Error

func (e *RetryAfterError) Error() string

func (*RetryAfterError) Unwrap

func (e *RetryAfterError) Unwrap() error

type RetryPolicy added in v0.2.0

type RetryPolicy struct {
	// MaxAttempts is the total number of attempts including the first call.
	// Zero selects DefaultRetryMaxAttempts; negative values are rejected by
	// New with ErrInvalidConfig.
	MaxAttempts int
	// InitialDelay is the pause before the second attempt. Zero selects
	// DefaultRetryInitialDelay.
	InitialDelay time.Duration
	// MaxDelay caps the backoff between attempts. Zero selects
	// DefaultRetryMaxDelay.
	MaxDelay time.Duration
	// Multiplier is the exponential backoff factor. Zero selects
	// DefaultRetryMultiplier.
	Multiplier float64
}

RetryPolicy configures opt-in automatic retries. The zero value means "use the defaults" (DefaultRetryMaxAttempts attempts, 100ms initial delay, 5s cap, 2x growth).

Retries apply to every API round-trip of the client: transient failures (network errors, 429/503 with Retry-After, 5xx) are retried with exponential backoff + jitter, server-provided Retry-After hints take precedence, and rejections (4xx) fail immediately. Without WithRetry the client makes exactly one attempt per call.

type SavedView added in v0.3.0

type SavedView struct {
	ID   int
	Name string
	// ShowOnDashboard and ShowInSidebar mirror the view's visibility
	// flags; a server that no longer serves them decodes as false.
	ShowOnDashboard bool
	ShowInSidebar   bool
	SortField       string
	SortReverse     bool
	FilterRules     []SavedViewFilterRule
}

SavedView is one stored filter view ("Inbox", ...) in the web UI. The SDK models the stable core fields; servers add or drop UI fields (icon, page_size, display mode, ...) across versions and unknown JSON fields are ignored.

type SavedViewFilterRule added in v0.3.0

type SavedViewFilterRule struct {
	RuleType int
	Value    string
}

SavedViewFilterRule is one filter criterion of a saved view: the server's numeric rule type (e.g. 6 = "has tag ...") and its string value.

type ShareLink struct {
	ID      int
	Created time.Time
	// Expiration is when the link stops working; zero means it never
	// expires.
	Expiration time.Time
	Slug       string
	DocumentID int
	// FileVersion says which rendition the link serves (archive or
	// original).
	FileVersion ShareLinkFileVersion
}

ShareLink is one public download link for a document. Slug is server-generated; the full share URL is <base>/share/<slug>.

type ShareLinkFileVersion added in v0.3.0

type ShareLinkFileVersion string

ShareLinkFileVersion names which rendition of a document a share link exposes. The server's default (and the zero-value fallback it applies when the field is omitted) is the archive version.

const (
	// ShareLinkFileVersionArchive exposes the OCR'd archive rendition.
	ShareLinkFileVersionArchive ShareLinkFileVersion = "archive"
	// ShareLinkFileVersionOriginal exposes the untouched original file.
	ShareLinkFileVersionOriginal ShareLinkFileVersion = "original"
)

type StoragePath added in v0.2.0

type StoragePath struct {
	ID   int
	Slug string
	Name string
	Path string
}

StoragePath is one Paperless-ngx storage path definition: the server-side directory template (e.g. "{created_year}/{correspondent}") documents are filed into, addressed by name.

type TaskOutcome

type TaskOutcome struct {
	Status TaskStatus
	// DocumentID is the server document this task points at: the newly
	// created document after a successful consumption, or the pre-existing
	// duplicate when the server refused the upload. Zero when unknown.
	DocumentID int64
	// DuplicateRefused is true when the consumer rejected the upload because
	// an identical document already exists (checksum dedup). The ledger uses
	// this to separate honest refusals from real failures.
	DuplicateRefused bool
	// DuplicateInTrash refines DuplicateRefused: the duplicate document is
	// in the trash (server treats trash duplicates as re-consumable).
	DuplicateInTrash bool
	// ErrorMessage is the server's failure reason for non-duplicate failures.
	ErrorMessage string
}

TaskOutcome is the classified result of one consumption-task poll.

func (TaskOutcome) Duplicate added in v0.2.0

func (o TaskOutcome) Duplicate() (int64, bool, bool)

Duplicate reports the duplicate-refusal details of an outcome. refused is true when the consumer rejected the upload because an identical document already exists (checksum dedup); documentID is that pre-existing duplicate and inTrash says whether it sits in the trash (the server treats trash duplicates as re-consumable). For non-refusals all returns are zero.

type TaskStatus

type TaskStatus string

TaskStatus is a Paperless-ngx consumption task's lifecycle state. The v10 API serves lowercase values; terminal states are success and failure (verified against paperless-ngx 3.x PaperlessTask.Status).

const (
	TaskStatusPending TaskStatus = "pending"
	TaskStatusStarted TaskStatus = "started"
	TaskStatusSuccess TaskStatus = "success"
	TaskStatusFailure TaskStatus = "failure"
)

Task consumption statuses served by the v10 API (lowercase values).

func (TaskStatus) Terminal

func (s TaskStatus) Terminal() bool

Terminal reports whether the status is a final task state. Unknown status strings (future server versions) poll forever — the safe default for a caller deciding whether to retry.

type UpdateDocumentRequest

type UpdateDocumentRequest struct {
	Title           *string
	Created         *time.Time
	CorrespondentID *int
	TagIDs          []int
	DocumentTypeID  *int
	CustomFields    []CustomFieldValue
}

UpdateDocumentRequest carries the fields a metadata backfill may change. Nil pointers leave the field untouched; TagIDs replaces the full tag set (Paperless-ngx PATCH semantics for many-to-many fields).

type UploadRequest

type UploadRequest struct {
	// Filename is the original file name (e.g. "invoice.pdf"). Paperless-ngx
	// derives the stored document name and archive serial numbering from it.
	Filename string
	// Content holds the raw file bytes. Gmail attachments are capped at 25 MB,
	// so buffering in memory is safe.
	Content []byte
	// Title overrides the consumer-assigned title when set.
	Title string
	// Created sets the document's creation date (typically the email date).
	Created time.Time
	// CorrespondentID is the Paperless-ngx correspondent (e.g. the email
	// sender) assigned on consumption. Zero leaves the field unset.
	CorrespondentID int
	// TagIDs are Paperless-ngx tag IDs applied on consumption.
	TagIDs []int
	// DocumentTypeID is the Paperless-ngx document type (e.g. "Email")
	// applied on consumption. Zero leaves the type unset.
	DocumentTypeID int
	// CustomFields are custom-field values applied on consumption, e.g. the
	// provenance field carrying the Gmail message ID. Nil leaves them unset.
	CustomFields []CustomFieldValue
}

UploadRequest describes one document to hand to Paperless-ngx's consumer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL