Local API
Use the current FastAPI endpoints on 127.0.0.1:7242, with request, response, and error examples.
The backend exposes JSON over HTTP. The default base URL is:
http://127.0.0.1:7242Start it with the desktop app or from backend:
uv run memsearch serveNetwork safety
Unauthenticated API with broad CORS
The API has no authentication or authorization. Its CORS middleware allows every origin, method, and header. The default 127.0.0.1 bind limits listening to the local Mac; changing MEMSEARCH_HOST to 0.0.0.0 or a network interface can expose search metadata, thumbnails, configuration changes, indexing controls, and destructive index clearing to other clients that can reach the port.
Keep the loopback default. If remote access is required, put authentication and network controls in front of the service; the current app does not provide them.
Endpoint map
| Method | Path | Purpose |
|---|---|---|
POST | /search | Embed a query and search the local index |
GET | /status | Return index statistics and live progress |
POST | /index/start | Start folder indexing |
POST | /index/photos | Start Photos indexing |
POST | /index/stop | Request cancellation |
GET | /people | List named people for autocomplete |
POST | /people/refresh | Reload people data and backfill indexed photos |
GET | /config | Return public runtime configuration |
PUT | /config | Update persistent UI-managed settings |
DELETE | /index | Clear all embeddings and thumbnails |
GET | /thumbnails/{filename} | Return one cached JPEG thumbnail |
Search
POST /search
{
"query": "@Mira beach sunset",
"n_results": 10,
"modality": "image"
}| Field | Type | Default | Notes |
|---|---|---|---|
query | string | required | Supports @name and @"Full Name" mentions |
n_results | integer | 20 | Maximum results returned |
modality | string or null | null | Current values used by clients: image, pdf, text |
curl -X POST http://127.0.0.1:7242/search \
-H 'Content-Type: application/json' \
-d '{"query":"roadmap about embeddings","n_results":5,"modality":"pdf"}'Example response:
{
"results": [
{
"file_path": "/Users/me/Documents/Q3-roadmap.pdf",
"score": 0.8734,
"modality": "pdf",
"filename": "Q3-roadmap.pdf",
"thumbnail_filename": "4602f7....jpg",
"text_summary": "Q3 roadmap and release priorities...",
"file_size": 483221,
"indexed_at": 1778528124.14,
"person_names": ""
}
],
"query_time_ms": 42.1,
"total_indexed": 1387
}score is cosine similarity (1 - distance). Search returns 503 when Gemini cannot create the query embedding.
Status
GET /status
curl http://127.0.0.1:7242/statusExample while indexing files:
{
"total": 1387,
"modalities": { "image": 800, "pdf": 87, "text": 500 },
"last_indexed_at": 1778528124.14,
"is_indexing": true,
"indexed_count": 42,
"error_count": 1,
"current_file": "/Users/me/Documents/notes.md",
"total_files_found": 240,
"errors": [
{ "file_path": "/Users/me/Documents/broken.pdf", "error": "..." }
],
"folder_progress": {
"/Users/me/Documents": { "total": 240, "indexed": 42, "errors": 1 }
},
"start_time": 1778528000.0,
"source": "files",
"phase": null,
"last_error": null,
"last_result": null
}When Photos is active, the backend maps Photos counts and current asset into the common pipeline fields, sets source to photos, and adds a Photos phase. A recent Photos result/error remains visible for roughly 60 seconds.
Folder indexing
POST /index/start
The body is optional. Missing or empty folders use the configured watched folders.
{
"folders": ["/Users/me/Documents", "/Users/me/Projects"],
"limit": 250
}curl -X POST http://127.0.0.1:7242/index/start \
-H 'Content-Type: application/json' \
-d '{"folders":["/Users/me/Documents"],"limit":250}'{
"status": "started",
"folders": ["/Users/me/Documents"]
}The response is immediate; poll /status. Paths that are not directories are silently removed from the resolved run. A request made while either pipeline is active returns 400.
Photos indexing
POST /index/photos
The body is optional.
{
"limit": 100,
"favorites_only": true
}{
"status": "started",
"source": "icloud_photos"
}The endpoint checks Photos permission before starting. It returns 400 if another job is active and 403 if Photos access is not authorized.
Stop indexing
POST /index/stop
curl -X POST http://127.0.0.1:7242/index/stop{ "status": "cancelling" }Cancellation is cooperative. A PhotoKit download or in-flight Gemini call may finish before the worker observes the flag.
People
GET /people
{
"people": [
{ "name": "Mira", "face_count": 214 },
{ "name": "Jordan", "face_count": 87 }
]
}The list is sorted by Photos face count descending. If the Photos database is unavailable, the endpoint returns an empty list rather than an error.
POST /people/refresh
{
"status": "refreshed",
"people_count": 28,
"photos_updated": 742
}Returns 400 when the people database object is unavailable and 500 when Photos.sqlite cannot be read after refresh.
Configuration
GET /config
{
"watched_folders": ["/Users/me/Documents"],
"max_file_size_mb": 50,
"auto_index_enabled": false,
"index_photos_enabled": false,
"embedding_model": "gemini-embedding-2-preview",
"embedding_dimensions": 768,
"port": 7242
}The Gemini key and storage paths are not returned.
PUT /config
All fields are optional:
{
"watched_folders": ["/Users/me/Documents"],
"max_file_size_mb": 25,
"auto_index_enabled": true,
"index_photos_enabled": false
}{ "status": "updated" }The backend saves these fields to MacMemorySearch/config.json and starts, stops, or updates the file watcher as necessary.
Clear the index
DELETE /index
curl -X DELETE http://127.0.0.1:7242/index{
"cleared_embeddings": 1387,
"cleared_thumbnails": 802
}No confirmation at the API layer
This endpoint immediately deletes the collection and cached thumbnails. It does not delete source files or saved configuration.
Thumbnails
GET /thumbnails/{filename}
Use the thumbnail_filename returned by search:
curl http://127.0.0.1:7242/thumbnails/4602f7....jpg --output preview.jpgThe response is image/jpeg. A filename containing /, \, or .. returns 400; a missing file returns 404.
Error reference
FastAPI errors use a JSON detail field.
| Status | Current cases |
|---|---|
400 Bad Request | Indexing already active; people database unavailable; invalid thumbnail filename |
403 Forbidden | Photos indexing requested without authorized Photos access |
404 Not Found | Thumbnail missing or route not found |
422 Unprocessable Entity | Request body fails FastAPI/Pydantic validation |
500 Internal Server Error | People refresh cannot read Photos.sqlite |
503 Service Unavailable | Gemini key/access denied, model missing/renamed, rate limited, or another embedding API error during search |
An upstream Gemini 403, 404, or 429 is deliberately translated into a local /search response with status 503 and a more specific detail message.