Receipts Space offers several interfaces to create, import, process, and export documents and receipts programmatically.
Overview
Import
- File system - drag & drop files or folders, open them via
File > Open, or pass them as command-line arguments. Supported formats include PDF, images (JPEG, PNG, HEIC …), e-mails (EML), and JSON files in the format described below. - Folder watching - configured folders (e.g. a scanner output folder or an iCloud folder) are watched permanently; new files are imported automatically.
- JSON import - structured import of complete documents, including asset, amounts, categories, contacts, and tags.
- URL scheme - invocation from a browser, mail client, or Shortcuts via
receipts-space://.... Ideal for importing directly into the library from web portals.
Export
- Drag & drop / clipboard - selected documents can be handed over to other apps as PDF, as the original file, or in JSON format (the same schema as the JSON import).
- File > Export - batch export into a folder, with optional metadata sidecars.
- AppleScript
exportcommand - programmatic export of individual or filtered documents. GitHub holtwick/receipts-api
Automation
- AppleScript - full automation of the app from scripts, Automator, or Shortcuts. The terminology dictionary can be inspected directly in macOS Script Editor. Examples are available at GitHub holtwick/receipts-api.
- Direct library access - the library is an open document bundle and can be read and written by external tools. Details on its structure are available in the technical documentation and GitHub holtwick/receipts-space.
If you have any further questions, our support team is happy to help.
Viewing Log Files
When working with these interfaces, the log is often the quickest way to diagnose issues. In the app’s main menu, under Help:
- Normal: the item reads Support & Feedback - opens the feedback form.
- With the Option (alt) key held down: the item switches to Open Log Files and reveals the log folder in Finder.
Direct path:
~/Library/Logs/Receipts/de_holtwick_mac_homebrew_Receipts2.logIn the Mac App Store edition, the bundle identifier in the filename differs slightly.
URL Scheme receipts-space://import
Imports a single PDF file whose binary data is passed directly inside the URL. Can be invoked from a browser, mail client, Shortcuts, or any other app.
| Parameter | Type | Meaning |
|---|---|---|
content | String (Base64-URL) | Binary data of the PDF, encoded as RFC 4648 §5 Base64-URL (-/_ instead of +//, padding = optional). |
Example:
receipts-space://import?content=JVBERi0xLjQKJeLjz9MKCg...Notes:
- The payload is always treated as PDF (UTI
com.adobe.pdf). Other file types are not supported by this endpoint - for images, e-mails, or structured data, use the JSON import or a file-based hand-off instead. - If
contentis missing or cannot be decoded, the call is silently dropped. - URL length is limited by the host system (typically a few MB via
open, considerably less in browsers). For larger files, a file-based import is more robust. - The import runs as a manual session through the regular import pipeline; duplicate detection, folder watching, etc. behave exactly as with a file import.
- Additional metadata (title, category, amounts,
id, …) cannot be supplied through this scheme. For metadata, use the JSON import (e.g. via a.receipts-importfile or a.receipts-package).
File Extensions
Receipts Space registers itself with macOS for a number of file extensions. When such a file is opened (double click, drag & drop onto the app icon, open in Terminal), the app responds according to the extension. The most relevant ones:
| Extension | Role | Meaning |
|---|---|---|
.receipts-import | Importer (JSON) | Explicit extension for a JSON file in the format described above. Recognized unambiguously as an import - no risk of confusion with other .json files. |
.receipts-package | Importer (package) | Import package as a bundle: combines a JSON description with one or more asset files in a single container that can be handled via drag & drop. |
.json | Importer (JSON) | A regular JSON file. Inspected and, if it matches the document schema, imported. |
.pdf | Importer | Added as a new document with the PDF as its asset; text is extracted. |
.png, .jpg, .jpeg, .tif, .tiff, .gif | Importer | The image is imported as an asset; if OCR is enabled, the text is recognized as well. |
.eml, .emlx | Importer | E-mail file; attachments are imported as receipts, the message body is retained as context. |
.xml | Viewer | Structured XML data (e.g. ZUGFeRD / X-Rechnung attachments) is parsed where supported. |
Structure of a .receipts-package
A .receipts-package is a folder bundle with the following layout:
MyPackage.receipts-package/
├── Info.json
└── Files/
├── invoice-1.pdf
└── scan-2.jpgInfo.json contains the manifest:
{
"note": "Optional note, attached to every document as its notes field.",
"files": [
{
"filename": "invoice-1.pdf",
"title": "Hotel invoice Berlin",
"url": "https://example.com/invoice/42"
},
{
"filename": "scan-2.jpg"
}
]
}filenamerefers to a file insideFiles/.title(optional) is used as the suggested title, e.g. a page title from Safari.url(optional) is stored as the source URL on the document; may also be used on its own (withoutfilename), in which case the URL is imported directly.
Auto-cleanup: ReceiptsMove- prefix
File names starting with ReceiptsMove- are moved to the trash automatically after a successful import. The mechanism was originally intended for Mail.app temporary files but works generically:
ReceiptsMove-invoice.pdfIf moving into the system trash fails (e.g. on network volumes), a fallback folder named .ReceiptsTrash is created next to the file and used instead.
JSON Import in Receipts Space
Receipts Space can import documents from JSON files. This section describes the supported format and all recognized fields.
Invocation
A JSON import is triggered as soon as a file with UTI public.json is passed to the app (drag & drop, folder watching, File > Open, AppleScript, URL scheme, etc.). The file is recognized in import-from-url.swift and forwarded to the JSON importer in import-from-json.swift.
The actual mapping of JSON fields onto a DocumentSchema happens in document-json-read.swift. All valid keys are defined as an enum in document-json-keys.swift.
Structure of the JSON File
The JSON file contains either a single document object or an array of document objects. Arrays are flattened automatically; each element is imported as its own document.
[
{ "id": "…", "title": "…", … },
{ "id": "…", "title": "…", … }
]Fields
Identification
| Key | Type | Meaning |
|---|---|---|
id | String | Unique UID of the document. If it already exists in the library, the document is treated as a duplicate (see below). If missing, a new UID is generated. |
title | String | Title of the document. |
via | String | Source / import channel (e.g. "mail", "scan"). Otherwise taken from the import session or defaults to "json". |
reference | String | Reference number (invoice / receipt number), mapped to the name field. |
notes | String | Free-form notes. |
text | String | Extracted text content of the document (e.g. OCR result). Also extracted automatically from the asset if the asset is a PDF and text was not supplied. |
doctype | String | Document type (internal; overridden when isCredit = true). |
Flags
| Key | Type | Meaning |
|---|---|---|
isConfirmed | Bool | “Confirmed” flag. |
isMarked | Bool | Star / flag. |
isCredit | Bool | Credit entry. Also resets doctype. |
Dates
Date fields accept either a native date object or an ISO 8601 string.
| Key | Type | Meaning |
|---|---|---|
date | ISO date | Document date. |
datePayment | ISO date | Payment date. |
dateAdded | ISO date | Creation date. Ignored for duplicates. |
Amounts
Amounts are stored in two blocks: amountsOriginal (the original currency of the receipt) and amounts (converted into the library’s default currency).
"amountsOriginal": {
"currency": "USD",
"gross": 123.45,
"tax": 19.70,
"taxDetails": [
{ "percent": 19, "value": 19.70 }
]
},
"amounts": {
"gross": 115.12,
"exchangeRate": 0.9325
}Key (inside amountsOriginal) | Type | Meaning |
|---|---|---|
currency | String (ISO 4217) | Original currency of the receipt. |
gross | Number/String | Gross amount. Rounded to two decimal places. |
tax | Number/String | Total tax (optional). |
taxDetails | Array | Individual tax rates. Either as objects { "percent": …, "value": … } or as tuple arrays [percent, value]. |
Key (inside amounts) | Type | Meaning |
|---|---|---|
gross | Number/String | Gross amount in the default currency. Only used when the original currency differs from the default. |
exchangeRate | Number/String | Explicit exchange rate. If missing, a rate is fetched asynchronously after import. |
Relations
| Key | Type | Meaning |
|---|---|---|
category | String or object | Category. Either as a string (= title) or as an object { "id": "…", "title": "…" }. With id, an existing category is matched by UID; otherwise by title (a new one is created if necessary). |
contact | String or object | Contact / merchant. Same format as category. |
provider | String or object | Alias for contact, recognized only on import. |
tags | Array | Tags. Either ["Travel", "Vacation"] or [{ "title": "Travel" }, …]. |
IBAN
| Key | Type | Meaning |
|---|---|---|
iban | String | IBAN. E-mail-like values (containing @) are ignored (workaround for PayPal data). |
Assets (File Attachment)
The actual receipt document is attached as asset, optionally with the untouched original under assetOriginal (e.g. the unmodified scan PDF before OCR).
"asset": {
"name": "invoice.pdf",
"uti": "com.adobe.pdf",
"mime": "application/pdf",
"data": "<base64>"
}| Key | Type | Meaning |
|---|---|---|
name | String | File name (default: "unnamed"). |
uti | String | Uniform Type Identifier. Used to derive the MIME type if that is missing. |
mime | String | MIME type; overrides the value derived from uti. |
data | Data or Base64 string | Direct binary data (preferred). |
fileurl | String (URL) | Fallback 1: URL the data is read from. |
path | String | Fallback 2: path to a local file. Interpreted as an absolute path first; when the JSON import comes from a file, the path is also resolved relative to that file’s directory. |
url | String (URL) | Fallback 3: additional URL source. |
The sources are tried in the order shown; the first one that yields non-empty data is used. For PDF assets, the text content is also extracted unless text has already been set.
Export/Import Round-trip
The JSON export of a document (drag & drop, clipboard, AppleScript export command) uses the same schema as the import and can be fed straight back in. Exported and imported fields share the same key enum internally, so an export → import round-trip brings the data back without loss. Assets on export are referenced either as url (internal web server), fileurl, or path; on import the first available source is used.
Updating Existing Documents
A JSON import with an id that already exists in the library overwrites the given fields on the existing document - the endpoint doubles as an update interface. Fields not mentioned remain unchanged.
By default the document is marked as a duplicate (status “Duplicate” in the list). For a silent update without that marker:
{
"id": "…existing-uid…",
"title": "New title",
"notes": "Amended note",
"onDuplicateFlag": false
}onDuplicateIncludeKeys limits the update to specific fields; onDuplicateExcludeKeys does the opposite. Details in the next section.
Duplicate Handling
If a document with the same id already exists in the library, the duplicate logic kicks in:
- Document was permanently deleted: it is restored and treated as a new import.
- Document was in the trash (archived): it is marked as a duplicate. Behavior is controlled by the keys below.
| Key | Type | Default | Meaning |
|---|---|---|---|
onDuplicateSkip | Bool | false | Skip the duplicate entirely; no update is performed. |
onDuplicateUnarchive | Bool | true | Bring an archived duplicate back out of the trash. |
onDuplicateFlag | Bool | true | Mark the duplicate as such (status code STATUS_CODE_DUPLICATE). |
onDuplicateIncludeKeys | Array<String> | - | If set: only these keys from the JSON are applied; all others are ignored. |
onDuplicateExcludeKeys | Array<String> | - | These keys are ignored for duplicates. |
The dateAdded field is never applied to duplicates, to preserve the original creation date.
Example
{
"title": "Office supplies",
"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": "Office",
"contact": { "title": "Müller GmbH" },
"tags": ["Q4", "Consumables"],
"iban": "DE89370400440532013000",
"asset": {
"path": "re-2025-00123.pdf",
}
}