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.
Getting started
- Sign in to Ordnung! as an administrator, open Settings → API and click Create new. Copy puts the key on the clipboard.
- Every request sends it as a header:
Authorization: Bearer <key>. - 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).
Endpoints
| Method | Path | Purpose |
|---|---|---|
| System | ||
| GET | /api/version | version, no sign-in needed |
| GET | /api/status | number of documents, text recognition progress, last scan |
| POST | /api/rescan | read the folders again now |
| Archive | ||
| GET | /api/areas | areas with display names |
| GET | /api/tree?areas=… | folder tree with counts |
| GET | /api/documents | list and search, parameters below |
| GET | /api/documents/{id} | one document with title, date, folder, tags |
| GET | /api/documents/{id}/file | the file itself (PDF) |
| GET | /api/documents/{id}/text | recognised text |
| PATCH | /api/documents/{id} | change title and date, renames the file |
| POST | /api/documents/{id}/move | to another folder or area |
| POST | /api/documents/{id}/trash | into the trash |
| Tags and collections | ||
| GET | /api/tags | all tags with counts |
| PUT | /api/documents/{id}/tags | set a document's tags |
| POST | /api/tags/change | add or remove tags on many documents |
| GET | /api/mappen | collections |
| GET | /api/mappen/download?name=…&format=pdf | a collection as one PDF (or zip) |
| Inbox | ||
| GET | /api/inbox | new documents with suggestions |
| POST | /api/inbox/upload | upload files (Base64), photos become PDFs |
| POST | /api/inbox/{key}/file | file it: area, folder, title, date, tags |
| POST | /api/inbox/{key}/dismiss | dismiss |
| Old files | ||
| POST | /api/altablage | documents, folders or everything older than X years in or back; dry_run only counts |
List and search
| Parameter | Meaning |
|---|---|
q | search words, all must occur; #tag filters by tag. Without folder the search covers the whole archive. |
folder, recursive | folder and whether subfolders count |
areas | areas, comma-separated; without: all allowed ones |
tags | tags, comma-separated, all must match |
alt | true searches the old files, too |
sort, desc | date (default, newest first), title, area or relevance (best matches first, searches only); desc=false reverses |
limit, offset | paging, default 500 |
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"
}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}]}))Errors
Errors come as an HTTP status with a reason in detail.
| Status | Meaning |
|---|---|
400 | change not allowed, e.g. already in that folder |
401 | not signed in or wrong key |
403 | no rights in that area |
404 | not found |
409 | conflict, e.g. the file already exists at the target |
422 | invalid parameters |