Skip to content

REST API

Secretary exposes a JSON REST API used by the Web UI and available for programmatic control.


Authentication

Routes are split into three authentication tiers:

Tier Auth required Routes
Public None GET /api/health, POST /api/auth, POST /api/logout
UI (session) Session cookie (secretary_session JWT) GET /api/ui/*
Shared Session cookie or Authorization: Bearer <token> POST /api/run, POST /api/reload, GET /api/traces
Webhook Authorization: Bearer <SECRETARY_API_TOKEN> POST /api/webhook/paperless

Public routes

GET /api/health

Health check. Returns HTTP 200 when the service is running.

{ "status": "healthy" }

POST /api/auth

Exchange admin credentials for an HttpOnly session cookie.

Request body:

{ "username": "admin", "password": "your-password" }

Response: Sets secretary_session cookie on success. Returns HTTP 403 for invalid credentials or if no admin account is configured.


POST /api/logout

Clears the session cookie.


UI routes (/api/ui/*)

All UI routes require a valid session cookie.

GET /api/ui/me

Returns the authenticated admin username.

{ "username": "admin" }

GET /api/ui/config

Returns non-secret configuration values needed by the frontend.

{ "paperless_url": "https://paperless.example.com" }

GET /api/ui/schema

Returns the Rule JSON schema and the editor vocabulary used for the YAML editor autocomplete.


GET /api/ui/rules

Lists all rule files in the rules.d directory with their metadata.

{
  "files": [
    {
      "id": "<file-id>",
      "name": "invoices.yml",
      "path": "invoices.yml",
      "package": null,
      "is_vars": false,
      "has_draft": false
    }
  ],
  "loaded": {
    "invoice_acme_title": "Sets the title for ACME invoices.",
    "tag_inbox": null
  }
}

GET /api/ui/rules/{file_id}

Returns the raw YAML content of a rule file.

{
  "id": "<file-id>",
  "name": "invoices.yml",
  "path": "invoices.yml",
  "content": "---\n- id: ..."
}

PUT /api/ui/rules/{file_id}

Validates and saves the content of a rule file. The request body must be raw UTF-8 YAML. Max 512 KB.

On validation error:

{ "ok": false, "error": "YAML/Pydantic error message" }

On success:

{ "ok": true }

DELETE /api/ui/rules/{file_id}

Deletes the rule file.

{ "ok": true }

POST /api/ui/rules

Creates a new empty rule file.

Request body:

{ "filename": "my-new-rule.yml" }

Response:

{ "ok": true, "id": "<file-id>", "name": "my-new-rule.yml", "path": "my-new-rule.yml" }

POST /api/ui/rules/{file_id}/preview

Renders a _vars.yml file and returns the resulting YAML. Only available for _vars.yml files.

Request body: raw YAML content to preview.

Response:

{ "ok": true, "result": "rendered YAML string" }

Shared routes

POST /api/reload

Forces an immediate reload of all rule files from disk.

{ "ok": true }

POST /api/run

Runs rules against documents. Accepts query parameters:

Parameter Type Description
document int Paperless document ID
rule_id string Rule ID to execute
dry_run bool Default true

Dispatch table:

document rule_id Behaviour
All rules against one document (synchronous, returns traces)
One rule against all documents (background task, returns event ID)
One rule against one document (synchronous, returns traces)
HTTP 400

Example — dry-run a single document:

POST /api/run?document=42&dry_run=true

Response (synchronous):

{
  "ok": true,
  "queued": false,
  "document": 42,
  "rule_id": null,
  "dry_run": true,
  "traces": [ ... ]
}

Response (background task):

{
  "ok": true,
  "queued": true,
  "rule_id": "invoice_acme_title",
  "dry_run": false,
  "event_id": 7
}

GET /api/traces

Returns recent execution records from the SQLite history.

Parameter Default Description
limit 100 Maximum number of records to return
{
  "traces": [ ... ]
}