REST API

Ordnung!

REST API

Everything the interface does is available through the REST API as well: for scripts, iOS Shortcuts, Home Assistant or a scanner that should deliver straight into the inbox. Requests and responses are JSON. The examples below are real responses from a demo installation with the invented Muster family.

Contents
  1. Getting started
  2. Endpoints
  3. List and search
  4. Examples
  5. From a script
  6. Errors

Getting started

  1. Sign in to Ordnung! as an administrator, open Settings → API and click Create new. Copy puts the key on the clipboard.
  2. Every request sends it as a header: Authorization: Bearer <key>.
  3. A first try in the terminal:
curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?q=insurance&limit=5"

The key acts like an administrator and sees every area, so keep it to trusted scripts. Create new disables the old key at once, Delete turns key access off. Without a key the API can only be used signed in from a browser.

Every endpoint to try out: Ordnung! describes its own API at /api/docs (machine-readable at /api/openapi.json). Signed in in the browser, you can send any call right there with Try it out. The link is under Settings → API as well.

Documents have an id, the six characters at the end of the file name. Areas are named like their folders (familie, erika …), folders are paths below them (Insurance/Nordlicht/Contents).

↑ to the top

Endpoints

MethodPathPurpose
System
GET/api/versionversion, no sign-in needed
GET/api/statusnumber of documents, text recognition progress, last scan
POST/api/rescanread the folders again now
Archive
GET/api/areasareas with display names
GET/api/tree?areas=…folder tree with counts
GET/api/documentslist and search, parameters below
GET/api/documents/{id}one document with title, date, folder, tags
GET/api/documents/{id}/filethe file itself (PDF)
GET/api/documents/{id}/textrecognised text
PATCH/api/documents/{id}change title and date, renames the file
POST/api/documents/{id}/moveto another folder or area
POST/api/documents/{id}/trashinto the trash
Tags and collections
GET/api/tagsall tags with counts
PUT/api/documents/{id}/tagsset a document's tags
POST/api/tags/changeadd or remove tags on many documents
GET/api/mappencollections
GET/api/mappen/download?name=…&format=pdfa collection as one PDF (or zip)
Inbox
GET/api/inboxnew documents with suggestions
POST/api/inbox/uploadupload files (Base64), photos become PDFs
POST/api/inbox/{key}/filefile it: area, folder, title, date, tags
POST/api/inbox/{key}/dismissdismiss
Old files
POST/api/altablagedocuments, folders or everything older than X years in or back; dry_run only counts

↑ to the top

Examples

System

Version

GET /api/version

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/version"

Response · 200

{
  "name": "Ordnung!",
  "version": "2026.11.70"
}

Status

GET /api/status

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/status"

Response · 200

{
  "total": 17,
  "last_scan": "2026-11-09T09:34:34",
  "last_scan_seconds": 0.0,
  "scanning": false,
  "texts": {
    "total": 17,
    "done": 17,
    "ocr_pages": 0,
    "errors": 0,
    "empty": 0,
    "running": false
  },
  "readonly": false,
  "version": "2026.11.70",
  "ocr": false,
  "inbox": {
    "new": 3,
    "filed": 0,
    "dismissed": 0,
    "reading": 0
  },
  "reference": null
}

Archive

Areas

GET /api/areas

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/areas"

Response · 200

[
  {
    "name": "erika",
    "count": 4,
    "label": "Erika"
  },
  {
    "name": "familie",
    "count": 5,
    "label": "Family"
  },
  "…"
]

Folder tree

GET /api/tree?areas=erika

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/tree?areas=erika"

Response · 200

{
  "name": "",
  "path": "",
  "count": 4,
  "own": 0,
  "areas": [
    "erika"
  ],
  "children": [
    {
      "name": "Health",
      "path": "Health",
      "count": 2,
      "own": 0,
      "areas": [
        "erika"
      ],
      "children": [
        {
          "name": "Doctors",
          "path": "Health/Doctors",
          "count": 1,
          "own": 1,
          "areas": [
            "erika"
          ],
          "children": []
        },
        {
          "name": "Health insurer",
          "path": "Health/Health insurer",
          "count": 1,
          "own": 1,
          "areas": [
            "erika"
          ],
          "children": []
        }
      ]
    },
    {
      "name": "ID documents",
      "path": "ID documents",
      "count": 1,
      "own": 1,
      "areas": [
        "erika"
      ],
      "children": []
    },
    "…"
  ],
  "alt": {
    "name": "Altablage",
    "path": "Altablage",
    "count": 0,
    "own": 0,
    "areas": [],
    "children": []
  }
}

Search

GET /api/documents?q=insurance&limit=2

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?q=insurance&limit=2"

Response · 200

{
  "total": 5,
  "items": [
    {
      "id": "f2c6c0",
      "sha256": "f2c6c0c42a10…",
      "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "area": "familie",
      "folder": "Insurance/Nordlicht/Contents",
      "name": "2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "ext": "pdf",
      "title": "Contents insurance policy",
      "date": "2026-01-12",
      "size": 1846,
      "snippet": "…nts \u0002insurance\u0003 poli…",
      "tags": []
    },
    {
      "id": "0cc24c",
      "sha256": "0cc24c45ca5c…",
      "path": "max/Insurance/Motor/2025-12-01_Motor insurance premium 2026_0cc24c.pdf",
      "area": "max",
      "folder": "Insurance/Motor",
      "name": "2025-12-01_Motor insurance premium 2026_0cc24c.pdf",
      "ext": "pdf",
      "title": "Motor insurance premium 2026",
      "date": "2025-12-01",
      "size": 1863,
      "snippet": "…tor \u0002insurance\u0003 prem…",
      "tags": [
        "Tax return 2026"
      ]
    }
  ]
}

Best matches first

GET /api/documents?q=insurance&sort=relevance&limit=2

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?q=insurance&sort=relevance&limit=2"

Response · 200

{
  "total": 5,
  "items": [
    {
      "id": "f2c6c0",
      "sha256": "f2c6c0c42a10…",
      "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "area": "familie",
      "folder": "Insurance/Nordlicht/Contents",
      "name": "2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "ext": "pdf",
      "title": "Contents insurance policy",
      "date": "2026-01-12",
      "size": 1846,
      "snippet": "…nts \u0002insurance\u0003 poli…",
      "tags": []
    },
    {
      "id": "0cc24c",
      "sha256": "0cc24c45ca5c…",
      "path": "max/Insurance/Motor/2025-12-01_Motor insurance premium 2026_0cc24c.pdf",
      "area": "max",
      "folder": "Insurance/Motor",
      "name": "2025-12-01_Motor insurance premium 2026_0cc24c.pdf",
      "ext": "pdf",
      "title": "Motor insurance premium 2026",
      "date": "2025-12-01",
      "size": 1863,
      "snippet": "…tor \u0002insurance\u0003 prem…",
      "tags": [
        "Tax return 2026"
      ]
    }
  ]
}

One folder, A–Z

GET /api/documents?folder=Insurance/Nordlicht/Contents&areas=familie&sort=title&desc=false

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?folder=Insurance/Nordlicht/Contents&areas=familie&sort=title&desc=false"

Response · 200

{
  "total": 1,
  "items": [
    {
      "id": "f2c6c0",
      "sha256": "f2c6c0c42a10…",
      "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "area": "familie",
      "folder": "Insurance/Nordlicht/Contents",
      "name": "2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "ext": "pdf",
      "title": "Contents insurance policy",
      "date": "2026-01-12",
      "size": 1846,
      "snippet": null,
      "tags": []
    }
  ]
}

One document

GET /api/documents/f2c6c0

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents/f2c6c0"

Response · 200

{
  "id": "f2c6c0",
  "sha256": "f2c6c0c42a10…",
  "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf",
  "area": "familie",
  "folder": "Insurance/Nordlicht/Contents",
  "name": "2026-01-12_Contents insurance policy_f2c6c0.pdf",
  "ext": "pdf",
  "title": "Contents insurance policy",
  "date": "2026-01-12",
  "size": 1846,
  "snippet": null,
  "copies": [
    "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf"
  ],
  "text": {
    "pages": 1,
    "ocr_pages": 0,
    "method": "text",
    "error": "",
    "chars": 452
  },
  "tags": []
}

Recognised text

GET /api/documents/f2c6c0/text

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents/f2c6c0/text"

Response · 200

Nordlicht Versicherung 
Nordlicht Versicherung · www.nordlicht-versicherung.test · info@nordlicht-versicherung.test 
Familie Muster 
5 Linden Lane 
Sampletown AB1 2CD 
Sampletown, 12 January 2026 
Contents insurance policy 
Dear Sir or Mada…

Change title and date

PATCH /api/documents/f2c6c0

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     -X PATCH \
     -H "Content-Type: application/json" \
     -d '{"title": "Contents insurance policy (copy for the tax office)", "date": "2026-01-12"}' \
     "https://ordnung.example.org/api/documents/f2c6c0"

Response · 200

{
  "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy (copy for the tax office)_f2c6c0.pdf",
  "id": "f2c6c0"
}

Move

POST /api/documents/f2c6c0/move

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"folder": "Taxes/2025"}' \
     "https://ordnung.example.org/api/documents/f2c6c0/move"

Response · 200

{
  "path": "familie/Taxes/2025/2026-01-12_Contents insurance policy_f2c6c0.pdf",
  "id": "f2c6c0"
}

Tags and collections

Tags for many documents

POST /api/tags/change

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"ids": ["f2c6c0"], "add": ["Tax 2026"]}' \
     "https://ordnung.example.org/api/tags/change"

Response · 200

{
  "changed": 1
}

All tags

GET /api/tags

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/tags"

Response · 200

[
  {
    "name": "Bathroom",
    "count": 1
  },
  {
    "name": "Dental work",
    "count": 1
  },
  "…"
]

Filter by tag

GET /api/documents?tags=Tax%202026

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?tags=Tax%202026"

Response · 200

{
  "total": 1,
  "items": [
    {
      "id": "f2c6c0",
      "sha256": "f2c6c0c42a10…",
      "path": "familie/Insurance/Nordlicht/Contents/2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "area": "familie",
      "folder": "Insurance/Nordlicht/Contents",
      "name": "2026-01-12_Contents insurance policy_f2c6c0.pdf",
      "ext": "pdf",
      "title": "Contents insurance policy",
      "date": "2026-01-12",
      "size": 1846,
      "snippet": null,
      "tags": [
        "Tax 2026"
      ]
    }
  ]
}

Collections

GET /api/mappen

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/mappen"

Response · 200

[
  {
    "name": "Tax return 2026",
    "area": "familie",
    "count": 6,
    "writable": true
  }
]

Inbox

File into the inbox

POST /api/inbox/upload

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"files": [{"name": "heating-invoice.pdf", "data": "JVBERi0xLjQK…"}], "combine": false}' \
     "https://ordnung.example.org/api/inbox/upload"

Response · 201

{
  "names": [
    "heating-invoice.pdf"
  ]
}

Inbox with suggestions

GET /api/inbox

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/inbox"

Response · 200

{
  "items": [
    {
      "key": "09ef7a962f5f",
      "inbox": "d64afa9d",
      "inbox_name": "Scanner",
      "rel": "scan_20261103_001.pdf",
      "name": "scan_20261103_001.pdf",
      "ext": "pdf",
      "size": 1799,
      "status": "new",
      "added": "2026-11-09T09:34:33",
      "filed_path": "",
      "text": {
        "chars": 444,
        "pages": 1,
        "ocr_pages": 0,
        "method": "text",
        "error": ""
      },
      "ai": null,
      "suggestion": {
        "area": "",
        "folder": "Insurance/Nordlicht/Buildings",
        "source": "rule",
        "title": "",
        "title_fallback": "Buildings",
        "date": "2026-11-03",
        "date_fallback": "2026-11-09",
        "candidates": [
          {
            "folder": "Insurance/Nordlicht/Buildings",
            "source": "rule",
            "rules": [
              {
                "rule": "819bad0d",
                "folder": "Insurance/Nordlicht/Buildings",
                "source": "auto",
                "conditions": [
                  {
                    "type": "contains",
                    "value": "wg-4471-2026"
                  }
                ]
              }
            ]
          }
        ],
        "conflict": false,
        "duplicate": null
      }
    },
    {
      "key": "b933309e3a89",
      "inbox": "d64afa9d",
      "inbox_name": "Scanner",
      "rel": "scan_20261105_002.pdf",
      "name": "scan_20261105_002.pdf",
      "ext": "pdf",
      "size": 1733,
      "status": "new",
      "added": "2026-11-09T09:34:33",
      "filed_path": "",
      "text": {
        "chars": 378,
        "pages": 1,
        "ocr_pages": 0,
        "method": "text",
        "error": ""
      },
      "ai": null,
      "suggestion": {
        "area": "",
        "folder": "",
        "source": "",
        "title": "",
        "title_fallback": "scan_20261105_002",
        "date": "2026-11-05",
        "date_fallback": "2026-11-09",
        "candidates": [],
        "conflict": false,
        "duplicate": null
      }
    },
    "…"
  ],
  "counts": {
    "new": 4,
    "filed": 0,
    "dismissed": 0,
    "reading": 1
  },
  "archive_writable": true,
  "inboxes": [
    {
      "id": "d64afa9d",
      "name": "Scanner",
      "area": "",
      "enabled": true,
      "after_import": "move",
      "delete_days": 0,
      "status": {
        "exists": true,
        "readable": true,
        "writable": true
      }
    }
  ],
  "folders": [
    "Banking",
    "Banking/Sample Savings Bank",
    "…"
  ],
  "areas": [
    "erika",
    "familie",
    "…"
  ]
}

Old files

Dry run: everything older than a year

POST /api/altablage

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"older_than_years": 1, "dry_run": true}' \
     "https://ordnung.example.org/api/altablage"

Response · 200

{
  "count": 1,
  "folders": [
    {
      "folder": "ID documents",
      "count": 1
    }
  ]
}

Errors

Unknown document

GET /api/documents/000000

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents/000000"

Response · 404

{
  "detail": "document not found"
}

Invalid parameter

GET /api/documents?sort=zufall

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/documents?sort=zufall"

Response · 422

{
  "detail": [
    {
      "type": "string_pattern_mismatch",
      "loc": [
        "query",
        "sort"
      ],
      "msg": "String should match pattern '^(|date|title|area|relevance)$'",
      "input": "zufall",
      "ctx": {
        "pattern": "^(|date|title|area|relevance)$"
      }
    }
  ]
}

Wrong key

GET /api/me

Request

curl -H "Authorization: Bearer $ORDNUNG_KEY" \
     "https://ordnung.example.org/api/me"

Response · 401

{
  "detail": "not authenticated"
}

↑ to the top

From a script

The same in Python without extra packages: print the five newest hits for “insurance” and put a PDF into the inbox.

import base64, json, urllib.request

HOST = "https://ordnung.example.org"
KEY = "your-key"                   # Settings → API

def api(path, body=None):
    req = urllib.request.Request(HOST + path, method="POST" if body else "GET",
                                 data=json.dumps(body).encode() if body else None,
                                 headers={"Authorization": "Bearer " + KEY,
                                          "Content-Type": "application/json"})
    with urllib.request.urlopen(req) as r:
        return json.load(r)

for d in api("/api/documents?q=insurance&limit=5")["items"]:
    print(d["date"], d["title"], "→", d["area"] + "/" + d["folder"])

pdf = base64.b64encode(open("invoice.pdf", "rb").read()).decode()
print(api("/api/inbox/upload", {"files": [{"name": "invoice.pdf", "data": pdf}]}))

↑ to the top

Errors

Errors come as an HTTP status with a reason in detail.

StatusMeaning
400change not allowed, e.g. already in that folder
401not signed in or wrong key
403no rights in that area
404not found
409conflict, e.g. the file already exists at the target
422invalid parameters

↑ to the top

← To the manual