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, filtered by date, status, category, contact, or tag. 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.
AppleScript
The app can be automated entirely from AppleScript. Its terminology dictionary can be inspected in macOS Script Editor (File > Open Dictionary), and example scripts are available at GitHub holtwick/receipts-api.
Recognizing a library
A document’s name is only its display name: it depends on the location on disk and changes as soon as the library is moved or renamed, which makes it unsuitable as an identifier. Use workspace id instead - the identifier stored inside the library itself, which survives renaming and moving.
tell application "Receipts Space"
set theLibrary to document 1
set theId to workspace id of theLibrary
set theLocation to file of theLibrary
end tellTwo things to keep in mind:
- A copy of a library carries the same
workspace id. Scripts that have to tell copies apart useworkspace idtogether withfile. - While a library is still opening, the property returns
missing value.
Exporting receipts
export returns the receipts of the open library as JSON - in the same schema as the JSON import, so with id (the uid), amounts, category, contact, tags, and references to the file (asset with path and url, assetOriginal for the originally imported file).
tell application "Receipts Space"
set theJSON to export category "Business Meals" as json
end tellAll filters are optional and can be combined - a receipt then has to match all of them:
| Parameter | Meaning |
|---|---|
from / to | Date range (AppleScript date). |
where | Which date the range refers to: date sent (receipt date, default), date paid, or date created. |
with paid / with mark / with confirmed | Only paid, marked, or confirmed receipts. |
category / contact / tag | Only receipts with the category, contact, or tag of this name. The name has to match exactly, ignoring case. An unknown name returns an empty list. Since 4.0. |
in | Also write the result to this file. |
Leave out `items`
Receipts are the default. Please do not write the word items: AppleScript reads it as its own keyword (“every item”), and the command fails. For the other kinds of data it works: export categories as json, export contacts as json, export tags as json.
Importing files and data
import creates a new receipt. type states what is passed:
tell application "Receipts Space"
import "/Users/me/Downloads/invoice.pdf" type path
import "https://example.com/invoice.pdf" type url
import "{\"title\": \"Parking ticket\", \"date\": \"2026-09-01\"}" type json
end telltype url(default) - a local or remote URL.type path- an absolute file path.type json- a receipt in the JSON import format. If the JSON contains theidof an existing receipt, only the given fields change - this is how scripts set title, category, contact, tags, and so on (see Updating Existing Documents). Before version 4.0,type jsonfailed with an error when called from AppleScript.type mail- the source of an email.
The import runs in the background; the command returns right away.
Replacing the file of a receipt
replace file swaps the file of an existing receipt - for example for an edited or extended version. Since 4.0.
tell application "Receipts Space"
replace file "/Users/me/Desktop/business-meal.pdf" for uid "..."
end tell- The receipt keeps all its data: date, amounts, contact, category, tags, and notes. No values are taken from the new file; only its text is recognized again (for search).
- No second entry is created, and no duplicate question comes up.
- A file works as well as a path:
replace file (POSIX file "/...") for uid "...". - The command waits until the file is processed and returns the uid. Errors - unknown uid, missing file, unsupported file type - arrive as script errors and can be caught with
try. - Receipts protected by the revision safety mode cannot be changed.
The uid of a receipt is the id field in the result of export.
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 a native date object, an ISO 8601 timestamp as the export writes it (2026-09-01T12:00:00.000Z), or, since 4.0, a plain day (2026-09-01).
| 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",
}
}