HTTP API
Every type gets the same REST endpoints, generated from the ontology.
Authentication
Send Authorization: Bearer arc_… with a token, or the session cookie the web app uses. Without either, requests get 401 with WWW-Authenticate: Bearer.
curl localhost:8080/api/receipt?limit=10 -H "Authorization: Bearer $TOKEN"Errors
| Status | When |
|---|---|
| 400 | Bad JSON, a bad id or a bad parameter |
| 401 | Not signed in, or an invalid or expired token |
| 403 | Not allowed in that space, or a scoped token managing users |
| 404 | Unknown type, object, file or source |
| 409 | Conflicts, such as a change based on an old spec or a source already syncing |
| 422 | Validation: {"type", "errors": [{"path", "message"}]} |
Other errors are {"error": "…"}.
Objects
Lists are ordered by id, which is creation time. Page with after, the id of the last object on the previous page; limit is up to 1000 and defaults to 100.
curl -X POST "localhost:8080/api/receipt?space=household" -H "Authorization: Bearer $TOKEN" \
-d '{"shop": "Albert Heijn", "date": "3 Oct 2026", "total": "€18,34"}'Endpoints
| Method | Path | Does |
|---|---|---|
GET | /api/types | The spec, plus the names of built-in and edited built-in types |
GET | /api/types/<name> | One type with its resolved fields, subtypes and JSON Schema |
GET | /api/changes | Proposed, applied and reverted changes, newest first |
POST | /api/changes | Propose {"ops": […]}; returns the change |
POST | /api/changes/<id>/preview | Dry run: touched, failing, failures and samples |
POST | /api/changes/<id>/apply | Apply a proposed change |
POST | /api/changes/<id>/revert | Revert an applied change |
GET | /api/<type> | List objects of a type and its subtypes; field=value filters, limit, after, space, reveal=true |
POST | /api/<type> | Create; ?space= picks the space |
GET | /api/<type>/<id> | Read one object; reveal=true |
PUT | /api/<type>/<id> | Replace the whole object |
PATCH | /api/<type>/<id> | Set some fields; null clears a field |
DELETE | /api/<type>/<id> | Delete with provenance and links |
GET | /api/<type>/<id>/provenance | Provenance per field |
GET | /api/<type>/<id>/links | Links of the object |
GET | /api/search | Search; see Search |
GET | /api/files | List files |
POST | /api/files | Upload a multipart file |
GET | /api/files/<id> | File metadata |
GET | /api/files/<id>/content | File bytes |
GET | /api/files/<id>/thumbnail | Image thumbnail |
GET | /api/files/<id>/text | Extracted text |
POST | /api/files/<id>/link | Signed link; ?expires=1h |
POST | /api/files/tus | Start a tus upload; then HEAD, PATCH and DELETE on its Location |
GET | /api/sources | List sources |
POST | /api/sources | Add a source; Google sources return auth_url |
GET | /api/sources/<id|name> | One source |
PATCH | /api/sources/<id|name> | Change type, schedule or rate |
POST | /api/sources/<id|name>/run | Sync now; returns fetched, new, mapped, status and error |
DELETE | /api/sources/<id|name> | Remove a source |
GET | /api/sources/oauth/callback | Google OAuth redirect URI |
GET | /api/views | Saved views |
POST | /api/views | Save a view: name, space, type, layout (table, board, calendar), by, where |
GET | /api/views/<id> | One view |
PUT | /api/views/<id> | Replace a view |
DELETE | /api/views/<id> | Delete a view |
Sign-in and access
Scoped tokens cannot use the space, member and token endpoints; full tokens and sessions can.
| Method | Path | Does |
|---|---|---|
GET | /auth/methods | Sign-in providers and whether mail is set up; no sign-in needed |
POST | /auth/magic | Send a magic link to {"email"} |
GET | /auth/magic?token= | Use a magic link; sets the session cookie |
GET | /auth/setup?token= | Open the first-run setup page |
POST | /auth/setup | Create the first owner: {"token", "email", "name"} |
POST | /auth/passkey/login | Start a passkey sign-in; then /auth/passkey/login/finish |
POST | /auth/passkey/register | Start adding a passkey; then /auth/passkey/register/finish |
GET | /auth/oidc/<provider> | Sign in with an OIDC provider |
GET | /auth/me | The signed-in actor, their spaces and home space |
POST | /auth/signout | End the session |
GET | /auth/spaces | Your spaces with your role |
POST | /auth/spaces | Add a space: {"name"} |
GET | /auth/spaces/<space>/members | Members of a space |
POST | /auth/spaces/<space>/members | Set a role: {"email", "role"}; none removes |
GET | /auth/tokens | Your tokens |
POST | /auth/tokens | Make a token: {"name", "spaces", "expires", "full"} |
DELETE | /auth/tokens/<id> | Revoke a token |
Other routes
| Path | Does |
|---|---|
/healthz | 204 when the server is up |
/files/<id>?exp=&sig= | Signed file links |
/mcp | MCP over streamable HTTP; see MCP |
/app/ | The web app; / redirects there |