Receipts Space bietet mehrere Schnittstellen, um Belege und Dokumente automatisiert zu erzeugen, zu importieren, weiterzuverarbeiten und wieder zu exportieren.
Überblick
Import
- Dateisystem - Dateien und Ordner per Drag & Drop, über
Datei > Öffnenoder als Kommandozeilen-Parameter. Unterstützt werden PDF, Bilder (JPEG, PNG, HEIC …), E-Mails (EML) sowie JSON-Dateien im unten beschriebenen Format. - Ordnerüberwachung - einmalig konfigurierte Ordner (z. B. Scanner-Ausgabe oder iCloud-Ordner) werden dauerhaft beobachtet; neue Dateien werden automatisch importiert.
- JSON-Import - strukturierter Import ganzer Dokumente inklusive Asset, Beträgen, Kategorien, Kontakten und Tags.
- URL-Schema - Aufruf aus Browser, Mail oder Shortcuts über
receipts-space://.... Ideal, um aus Web-Portalen direkt in die Library zu importieren.
Export
- Drag & Drop / Zwischenablage - ausgewählte Dokumente lassen sich als PDF, als Originaldatei oder im JSON-Format (gleiches Schema wie der JSON-Import) in andere Apps übernehmen.
- Datei > Exportieren - Stapel-Export in einen Ordner, inklusive optionaler Metadaten-Sidecars.
- AppleScript
export-Kommando - programmatischer Export einzelner oder gefilterter Dokumente. GitHub holtwick/receipts-api
Automatisierung
- AppleScript - vollständige Automatisierung der App aus Skripten, Automator oder Shortcuts heraus. Das Terminologie-Lexikon ist direkt im Skripteditor von macOS einsehbar. Beispiele unter GitHub holtwick/receipts-api.
- Direkter Bibliothekszugriff - die Bibliothek ist ein offenes Dokument-Bundle und kann von externen Tools gelesen und geschrieben werden. Details zum Aufbau stehen in der technischen Dokumentation und GitHub holtwick/receipts-space.
Bei Rückfragen hilft unser Support-Team gerne weiter.
Logfiles einsehen
Beim Arbeiten mit den Schnittstellen ist ein Blick ins Log oft der schnellste Weg zur Ursachenanalyse. Im Hauptmenü der App unter Hilfe:
- Normal: Eintrag Support & Feedback - öffnet das Feedback-Formular.
- Mit gedrückter ALT-Taste: Der Eintrag wechselt auf Open Log Files und öffnet den Log-Ordner im Finder.
Direkter Pfad:
~/Library/Logs/Receipts/de_holtwick_mac_homebrew_Receipts2.logIn der Mac-App-Store-Version weicht der Bundle-Identifier im Dateinamen leicht ab.
URL-Schema receipts-space://import
Importiert eine einzelne PDF-Datei, deren Binärdaten direkt in der URL übergeben werden. Aufrufbar aus Browser, Mail, Shortcuts oder beliebigen anderen Apps.
| Parameter | Typ | Bedeutung |
|---|---|---|
content | String (Base64-URL) | Binärdaten des PDFs, kodiert nach RFC 4648 §5 (Base64-URL: -/_ statt +//, Padding = optional). |
Beispiel:
receipts-space://import?content=JVBERi0xLjQKJeLjz9MKCg...Hinweise:
- Der Inhalt wird immer als PDF behandelt (UTI
com.adobe.pdf). Andere Dateitypen werden von diesem Endpunkt derzeit nicht unterstützt - für Bilder, E-Mails oder strukturierte Daten bitte den JSON-Import oder eine Datei-basierte Übergabe verwenden. - Fehlt
contentoder lässt sich der Wert nicht dekodieren, wird der Aufruf stillschweigend verworfen. - Die Länge einer URL ist systembedingt begrenzt (typisch einige MB über
open, deutlich weniger in Browsern). Für größere Dateien ist ein Datei-basierter Import stabiler. - Der Import läuft als manuelle Session durch die reguläre Import-Pipeline; Dublettenerkennung, Ordnerüberwachung etc. verhalten sich wie beim Datei-Import.
- Weitere Metadaten (Titel, Kategorie, Beträge,
idusw.) lassen sich über dieses Schema nicht mitgeben. Wer Metadaten setzen möchte, nutzt den JSON-Import (z. B. über eine.receipts-import-Datei oder ein.receipts-package).
Dateiendungen
Receipts Space registriert sich bei macOS für eine Reihe von Dateiendungen. Beim Öffnen einer solchen Datei (Doppelklick, Drag & Drop auf das App-Icon, open im Terminal) reagiert die App entsprechend der Endung. Hier die relevantesten:
| Endung | Rolle | Bedeutung |
|---|---|---|
.receipts-import | Importer (JSON) | Explizite Endung für eine JSON-Datei im oben beschriebenen Format. Wird eindeutig als Import erkannt - ohne Verwechslungsgefahr mit anderen .json-Dateien. |
.receipts-package | Importer (Paket) | Importpaket als Bundle: kombiniert eine JSON-Beschreibung mit einer oder mehreren Asset-Dateien in einem einzigen, per Drag & Drop transportierbaren Container. |
.json | Importer (JSON) | Reguläre JSON-Datei. Wird geprüft und, wenn sie dem Dokumenten-Schema entspricht, importiert. |
.pdf | Importer | Wird als neues Dokument mit der PDF-Datei als Asset angelegt; Text wird extrahiert. |
.png, .jpg, .jpeg, .tif, .tiff, .gif | Importer | Bild wird als Asset importiert; bei aktivierter OCR wird zusätzlich der Text erkannt. |
.eml, .emlx | Importer | E-Mail-Datei; Anhänge werden als Belege importiert, der E-Mail-Text bleibt als Kontext erhalten. |
.xml | Viewer | Strukturierte XML-Daten (z. B. ZUGFeRD/X-Rechnung-Anhänge) werden geparst, soweit unterstützt. |
Aufbau eines .receipts-package
Ein .receipts-package ist ein Ordner-Bundle mit folgendem Aufbau:
Meinpaket.receipts-package/
├── Info.json
└── Files/
├── rechnung-1.pdf
└── scan-2.jpgInfo.json enthält das Manifest:
{
"note": "Optionaler Hinweis, wird allen Dokumenten als Notiz angefügt.",
"files": [
{
"filename": "rechnung-1.pdf",
"title": "Hotelrechnung Berlin",
"url": "https://example.com/invoice/42"
},
{
"filename": "scan-2.jpg"
}
]
}filenameverweist auf eine Datei innerhalb vonFiles/.title(optional) wird als vorgeschlagener Titel übernommen, z. B. ein Seitentitel aus Safari.url(optional) wird als Quell-URL im Dokument gespeichert; kann auch allein verwendet werden (ohnefilename), dann wird die URL direkt importiert.
Automatisches Aufräumen: Präfix ReceiptsMove-
Dateinamen, die mit ReceiptsMove- beginnen, werden nach erfolgreichem Import automatisch in den Papierkorb verschoben. Gedacht war der Mechanismus ursprünglich für Mail.app-Temporärdateien, er funktioniert aber generisch:
ReceiptsMove-rechnung.pdfSchlägt das Verschieben in den System-Papierkorb fehl (z. B. bei Netzlaufwerken), wird als Fallback ein Ordner .ReceiptsTrash neben der Datei angelegt und sie dort abgelegt.
JSON-Import in Receipts Space
Receipts Space kann Dokumente aus JSON-Dateien importieren. Dieses Dokument beschreibt das unterstützte Format und alle erkannten Felder.
Aufruf
Ein JSON-Import wird ausgelöst, sobald eine Datei mit UTI public.json an die App übergeben wird (Drag & Drop, Ordnerüberwachung, File > Open, AppleScript, URL-Schema usw.). Die Datei wird in import-from-url.swift erkannt und an den JSON-Importer in import-from-json.swift weitergereicht.
Die eigentliche Zuordnung der JSON-Felder auf ein DocumentSchema erfolgt in document-json-read.swift. Alle gültigen Schlüssel sind als Enum in document-json-keys.swift definiert.
Struktur der JSON-Datei
Die JSON-Datei enthält entweder ein einzelnes Dokument-Objekt oder ein Array von Dokument-Objekten. Arrays werden automatisch aufgespalten, jedes Element wird als eigenes Dokument importiert.
[
{ "id": "…", "title": "…", … },
{ "id": "…", "title": "…", … }
]Felder
Identifikation
| Key | Typ | Bedeutung |
|---|---|---|
id | String | Eindeutige UID des Dokuments. Existiert sie bereits in der Bibliothek, wird das Dokument als Duplikat behandelt (siehe unten). Fehlt sie, wird eine neue UID vergeben. |
title | String | Titel des Dokuments. |
via | String | Quelle/Import-Kanal (z. B. "mail", "scan"). Wird andernfalls aus der Import-Session oder auf "json" gesetzt. |
reference | String | Referenznummer (Rechnungs-/Beleg-Nr.), wird auf das Feld name abgebildet. |
notes | String | Freitext-Notizen. |
text | String | Extrahierter Textinhalt des Dokuments (z. B. OCR-Ergebnis). Wird auch automatisch aus dem Asset extrahiert, wenn das Asset ein PDF ist und kein text mitgegeben wurde. |
doctype | String | Dokumenttyp (intern; wird überschrieben, wenn isCredit = true). |
Flags
| Key | Typ | Bedeutung |
|---|---|---|
isConfirmed | Bool | “Bestätigt”-Flag. |
isMarked | Bool | Stern/Markierung. |
isCredit | Bool | Haben-Buchung. Setzt gleichzeitig doctype zurück. |
Datum
Datumsfelder akzeptieren entweder ein natives Date-Objekt oder einen ISO-8601-String.
| Key | Typ | Bedeutung |
|---|---|---|
date | ISO-Datum | Belegdatum. |
datePayment | ISO-Datum | Zahlungsdatum. |
dateAdded | ISO-Datum | Erstelldatum. Wird bei Duplikaten ignoriert. |
Beträge
Beträge werden in zwei Blöcken verwaltet: amountsOriginal (Originalwährung des Belegs) und amounts (umgerechnet in die Default-Währung der Bibliothek).
"amountsOriginal": {
"currency": "USD",
"gross": 123.45,
"tax": 19.70,
"taxDetails": [
{ "percent": 19, "value": 19.70 }
]
},
"amounts": {
"gross": 115.12,
"exchangeRate": 0.9325
}Key (unter amountsOriginal) | Typ | Bedeutung |
|---|---|---|
currency | String (ISO 4217) | Originalwährung des Belegs. |
gross | Number/String | Bruttobetrag. Auf zwei Nachkommastellen gerundet. |
tax | Number/String | Gesamtsteuer (optional). |
taxDetails | Array | Einzelne Steuersätze. Entweder als Objekte { "percent": …, "value": … } oder als Tuple-Arrays [percent, value]. |
Key (unter amounts) | Typ | Bedeutung |
|---|---|---|
gross | Number/String | Bruttobetrag in der Default-Währung. Wird nur verwendet, wenn die Originalwährung von der Default-Währung abweicht. |
exchangeRate | Number/String | Explizit gesetzter Wechselkurs. Fehlt er, wird nach dem Import asynchron ein Kurs nachgeladen. |
Relationen
| Key | Typ | Bedeutung |
|---|---|---|
category | String oder Objekt | Kategorie. Als String (= Titel) oder Objekt { "id": "…", "title": "…" }. Bei id wird die existierende Kategorie per UID zugeordnet; sonst per Titel (wird ggf. neu angelegt). |
contact | String oder Objekt | Kontakt/Händler. Gleiches Format wie category. |
provider | String oder Objekt | Alias für contact, wird nur beim Import ausgewertet. |
tags | Array | Tags. Entweder ["Urlaub", "Reise"] oder [{ "title": "Urlaub" }, …]. |
IBAN
| Key | Typ | Bedeutung |
|---|---|---|
iban | String | IBAN. E-Mail-artige Werte (enthalten @) werden ignoriert (Workaround für PayPal-Daten). |
Assets (Dateianhang)
Das eigentliche Beleg-Dokument wird als asset angehängt, optional zusätzlich das Original unter assetOriginal (z. B. das unveränderte Scan-PDF vor OCR).
"asset": {
"name": "rechnung.pdf",
"uti": "com.adobe.pdf",
"mime": "application/pdf",
"data": "<base64>"
}| Key | Typ | Bedeutung |
|---|---|---|
name | String | Dateiname (Default: "unnamed"). |
uti | String | Uniform Type Identifier. Wird verwendet, um den MIME-Typ abzuleiten, falls dieser fehlt. |
mime | String | MIME-Typ, überschreibt den aus uti abgeleiteten Wert. |
data | Data oder Base64-String | Direkte Binärdaten (bevorzugt). |
fileurl | String (URL) | Fallback 1: URL, von der die Daten gelesen werden. |
path | String | Fallback 2: Pfad zu einer lokalen Datei. Wird primär als absoluter Pfad interpretiert; kommt der JSON-Import aus einer Datei, wird zusätzlich relativ zu deren Ordner aufgelöst. |
url | String (URL) | Fallback 3: weitere URL-Quelle. |
Die Quellen werden in der angegebenen Reihenfolge probiert; die erste, die nicht-leere Daten liefert, wird verwendet. Bei PDF-Assets wird zusätzlich der Textinhalt extrahiert, wenn text nicht bereits gesetzt ist.
Export/Import-Roundtrip
Der JSON-Export eines Dokuments (Drag & Drop, Zwischenablage, AppleScript export-Kommando) verwendet dasselbe Schema wie der Import und ist damit direkt wieder importierbar. Exportierte und importierte Felder teilen sich in der Implementierung das gleiche Schlüssel-Enum, so dass ein Roundtrip Export → Import die Daten verlustfrei zurückbringt. Assets werden beim Export wahlweise als url (interner Webserver), fileurl oder path referenziert; beim Import wird die erste verfügbare Quelle genutzt.
Bestehende Dokumente aktualisieren
Ein JSON-Import mit einer id, die bereits in der Bibliothek existiert, überschreibt die darin angegebenen Felder des vorhandenen Dokuments - es handelt sich also zugleich um eine Update-Schnittstelle. Nicht erwähnte Felder bleiben unverändert.
Standardmäßig wird das Dokument dabei als Duplikat markiert (Status “Duplikat” in der Liste). Für ein stilles Update ohne Markierung:
{
"id": "…bestehende-uid…",
"title": "Neuer Titel",
"notes": "Ergänzte Notiz",
"onDuplicateFlag": false
}Mit onDuplicateIncludeKeys lässt sich das Update auf einzelne Felder beschränken; onDuplicateExcludeKeys bewirkt das Gegenteil. Details dazu im nächsten Abschnitt.
Duplikat-Handling
Ist bereits ein Dokument mit derselben id in der Bibliothek vorhanden, greift die Duplikat-Logik:
- Dokument war endgültig gelöscht: wird wieder hergestellt und wie ein Neu-Import behandelt.
- Dokument war im Papierkorb (archiviert): wird als Duplikat markiert. Verhalten steuerbar über folgende Keys.
| Key | Typ | Default | Bedeutung |
|---|---|---|---|
onDuplicateSkip | Bool | false | Duplikat komplett überspringen, es erfolgt keine Aktualisierung. |
onDuplicateUnarchive | Bool | true | Archiviertes Duplikat wieder aus dem Papierkorb holen. |
onDuplicateFlag | Bool | true | Duplikat als solches markieren (Status-Code STATUS_CODE_DUPLICATE). |
onDuplicateIncludeKeys | Array<String> | - | Wenn gesetzt: nur diese Keys aus dem JSON werden angewendet; alle anderen ignoriert. |
onDuplicateExcludeKeys | Array<String> | - | Diese Keys werden bei Duplikaten ignoriert. |
Das Feld dateAdded wird bei Duplikaten nie übernommen, damit das ursprüngliche Anlage-Datum erhalten bleibt.
Beispiel
{
"title": "Büromaterial",
"via": "scan",
"reference": "RE-2025-00123",
"date": "2025-11-14",
"datePayment": "2025-11-18",
"isConfirmed": true,
"amountsOriginal": {
"currency": "EUR",
"gross": 42.80,
"taxDetails": [
{ "percent": 19, "value": 6.83 }
]
},
"category": "Büro",
"contact": { "title": "Müller GmbH" },
"tags": ["Q4", "Verbrauchsmaterial"],
"iban": "DE89370400440532013000",
"asset": {
"path": "re-2025-00123.pdf",
}
}