-
-
Notifications
You must be signed in to change notification settings - Fork 40
API Reference
All endpoints require an Authorization: Bearer YOUR_TOKEN header except CORS preflight.
Error responses are standardized as { "ok": false, "error": "..." } across all routes (e.g. 401 { "ok": false, "error": "Unauthorized" }).
Store an entry. Duplicate detection runs synchronously. Embedding happens in the background so the response is instant.
Request body:
{
"content": "your note here",
"tags": ["work", "idea"],
"source": "api"
}| Field | Required? | Default | Description |
|---|---|---|---|
content |
Required | — | The text to store. Rejected if missing or empty. |
tags |
Optional | [] |
Array of tags to attach to the entry |
source |
Optional | "api" |
Free-text label for where the note came from |
Responses:
Stored successfully:
{ "ok": true, "id": "uuid-v4" }Stored but similar entry exists (tagged duplicate-candidate):
{
"ok": true,
"id": "uuid-v4",
"warning": "similar",
"matchId": "existing-uuid",
"score": 88.5,
"message": "Stored but similar entry exists — tagged as duplicate-candidate"
}Blocked — near-exact duplicate:
{
"ok": false,
"duplicate": true,
"matchId": "existing-uuid",
"score": 97.2,
"message": "Near-exact duplicate detected — not stored"
}Merged into an existing entry (no new row created):
{ "ok": true, "id": "existing-uuid", "action": "merged", "message": "Memories merged into a single combined entry" }Replaced an outdated existing entry:
{ "ok": true, "id": "existing-uuid", "action": "replaced", "message": "New memory replaced an outdated existing entry" }Resolved a contradiction (old conflicting entry deleted, new one stored and tagged contradiction-resolved):
{ "ok": true, "id": "uuid-v4", "resolved_conflict": "deleted-entry-uuid", "reason": "The new note says the meeting moved to Wednesday, superseding the Tuesday entry." }See How It Works → Duplicate detection, contradictions, and smart merging for when each of these outcomes (
merged/replaced/contradiction/flagged/blocked) gets triggered.
| Status | Meaning |
|---|---|
200 ok:true |
Stored, merged, replaced, or contradiction resolved |
200 ok:false duplicate:true |
Blocked — near-exact duplicate |
400 |
Missing or invalid content
|
401 |
Invalid auth token |
Append new information to an existing entry. The original content is preserved and the update is added with a timestamp.
Request body:
{
"id": "existing-entry-uuid",
"addition": "New information to append"
}| Field | Required? | Description |
|---|---|---|
id |
Required | UUID of the entry to append to. Rejected (400) if missing/empty. |
addition |
Required | Text to append. Rejected (400) if missing/empty. |
Responses:
Success:
{
"ok": true,
"id": "existing-entry-uuid",
"message": "Update appended successfully with timestamp"
}Entry not found:
{
"ok": false,
"error": "No entry found with ID: existing-entry-uuid"
}Append failed:
{
"ok": false,
"error": "Append failed: <error details>"
}| Status | Meaning |
|---|---|
200 ok:true |
Update appended successfully |
404 ok:false |
Entry not found |
500 ok:false |
Append operation failed |
400 |
Missing or invalid id or addition
|
401 |
Invalid auth token |
List recent entries in reverse chronological order, with optional tag and time-range filters.
curl "https://<your-worker-url>/list?n=20&tag=work&after=1700000000000&before=1750000000000" \
-H "Authorization: Bearer YOUR_TOKEN"All query parameters are optional.
| Query param | Required? | Default | Max | Description |
|---|---|---|---|---|
n |
Optional | 20 |
100 |
Number of entries to return |
tag |
Optional | — (no filter) | — | Only return entries with this exact tag |
after |
Optional | — (no filter) | — | Only return entries created at/after this Unix ms timestamp |
before |
Optional | — (no filter) | — | Only return entries created at/before this Unix ms timestamp |
Returns a JSON array of entry objects (same filtering behavior as the list_recent MCP tool).
Semantic search over your memories — vector search with time-decay reranking, chunk dedup, and an LLM-synthesized insight. Mirrors the recall MCP tool.
curl "https://<your-worker-url>/recall?query=what+did+I+decide+about+pricing&topK=5&tag=work" \
-H "Authorization: Bearer YOUR_TOKEN"| Query param | Required? | Default | Range | Description |
|---|---|---|---|---|
query |
Required | — | — | Natural-language search query. Returns 400 if missing/empty. |
topK |
Optional | 5 |
clamped to 1–20
|
Max number of results to return |
tag |
Optional | — (no filter) | — | Restrict results to entries carrying this exact tag |
after |
Optional | — (no filter) | — | Only consider entries created at/after this Unix ms timestamp |
before |
Optional | — (no filter) | — | Only consider entries created at/before this Unix ms timestamp |
Responses:
Matches found:
{
"ok": true,
"results": [
{
"id": "entry-uuid",
"content": "Decided to go with usage-based pricing...",
"score": 91.4,
"tags": ["work", "pricing"],
"source": "api",
"created_at": 1718000000000,
"updated": false
}
],
"insight": "You've been leaning toward usage-based pricing models."
}Nothing found:
{ "ok": true, "results": [], "message": "Nothing found matching that query." }| Status | Meaning |
|---|---|
200 ok:true |
Search executed (results may be empty) |
400 ok:false |
Missing or empty query
|
401 |
Invalid auth token |
Permanently delete an entry and all of its associated vectors (original + chunked updates) from D1 and Vectorize. Mirrors the forget MCP tool.
Request body:
{ "id": "existing-entry-uuid" }| Field | Required? | Description |
|---|---|---|
id |
Required | UUID of the entry to delete. Rejected (400) if missing/empty. Whitespace is trimmed before lookup. |
Responses:
Success:
{ "ok": true, "id": "existing-entry-uuid", "deletedVectors": 2 }Entry not found:
{ "ok": false, "error": "No entry found with ID: existing-entry-uuid" }| Status | Meaning |
|---|---|
200 ok:true |
Entry and vectors deleted |
400 ok:false |
Missing or invalid id, or invalid JSON body |
404 ok:false |
No entry found with that ID |
401 |
Invalid auth token |
Note: Vectorize cleanup is non-fatal — if vector deletion fails, the D1 row is still removed and the response still reports success.
Replace an entry's content (re-extracts hashtags as tags and re-embeds it). Unlike /append, this overwrites rather than preserving the original text.
Request body:
{ "id": "existing-entry-uuid", "content": "the corrected note text" }| Field | Required? | Description |
|---|---|---|
id |
Required | UUID of the entry to overwrite. Rejected (400) if missing/empty. |
content |
Required | New content. Replaces the existing text entirely (hashtags are re-extracted into tags, and the entry is re-embedded). Rejected (400) if missing/empty. |
Responses:
Success:
{ "ok": true, "id": "existing-entry-uuid", "vectors": 1 }Entry not found:
{ "ok": false, "error": "No entry found with ID: existing-entry-uuid" }| Status | Meaning |
|---|---|
200 ok:true |
Entry updated and re-embedded |
400 ok:false |
Missing id/content, or invalid JSON body |
404 ok:false |
No entry found with that ID |
401 |
Invalid auth token |
Returns the total number of stored entries. No parameters.
curl "https://<your-worker-url>/count" -H "Authorization: Bearer YOUR_TOKEN"Response:
{ "count": 142 }Returns every distinct tag currently in use, alphabetically sorted. No parameters.
curl "https://<your-worker-url>/tags" -H "Authorization: Bearer YOUR_TOKEN"Response:
["idea", "pricing", "work"]Returns summary statistics about your second brain — entry count, average importance score, top tags, and tags that are candidates for digest synthesis (high-volume tags without a recent digest). No parameters.
curl "https://<your-worker-url>/stats" -H "Authorization: Bearer YOUR_TOKEN"Response:
{
"count": 142,
"avg_importance": 2.3,
"top_tags": ["work", "idea", "pricing", "personal", "claude-response"],
"digest_candidates": [
{ "tag": "work", "count": 27 }
]
}Streams an LLM-generated answer to a question, grounded in a set of memories you provide (typically the results of a prior /recall call). Used by the web dashboard's chat feature.
Request body:
| Field | Required? | Description |
|---|---|---|
query |
Required | The question to answer. Rejected (400) if missing/empty. |
memories |
Optional | A text blob of relevant memories to ground the answer in (e.g. formatted /recall results) |
Response: a text/event-stream of the LLM's streamed response (Server-Sent Events) — not a single JSON payload.
| Status | Meaning |
|---|---|
200 |
Streaming response started |
400 ok:false |
Missing query, or invalid JSON body |
401 |
Invalid auth token |
Synthesizes a high-volume tag's entries into a single condensed summary entry (tagged synthesized), to keep recall results from being dominated by repetitive low-value notes. This is the same compression the nightly cron job runs automatically — /digest lets you trigger it on demand for a specific tag.
| Query param | Required? | Description |
|---|---|---|
tag |
Required | The tag to compress. Returns 400 if missing/empty. |
Responses:
Digest created:
{
"tag": "work",
"synthesis": "Condensed summary text...",
"entry_id": "new-synthesized-entry-uuid",
"source_count": 23
}Not enough entries, or compressed too recently:
{
"tag": "work",
"error": "Could not create digest — tag may have fewer than 20 entries or was recently compressed",
"source_count": 8
}| Status | Meaning |
|---|---|
200 |
Either a digest was created, or a reason is returned for why one wasn't (check for the error field) |
400 ok:false |
Missing tag
|
401 |
Invalid auth token |
MCP server endpoint using the Streamable HTTP transport. Authentication is required — either:
- An
Authorization: Bearer <your-token>header (yourAUTH_TOKEN), or - A
?token=<your-token>query param (less secure — can leak via browser history/logs; prefer the header where supported), or - A full OAuth flow via
/oauth/authorize(for clients that support OAuth, e.g. browser-based MCP clients)
Connect any MCP-compatible client using:
https://<your-worker-url>/mcp
See Connect to AI Clients for client-specific setup instructions and config examples.
? after a parameter name means it's optional. All others are required.
| Tool | Parameters | Description |
|---|---|---|
remember |
content, tags? (array), source?
|
Store a note with duplicate detection |
append |
id, addition
|
Append new info to an existing entry, preserving the original |
update |
id, content
|
Replace an entry's full content (overwrites, re-embeds) |
recall |
query, topK? (default 5, range 1–20), tag?, after? (Unix ms), before? (Unix ms) |
Semantic search with chunk deduplication and time-decay reranking |
list_recent |
n? (default 10, max 50), tag?, after? (Unix ms), before? (Unix ms) |
Chronological listing |
forget |
id |
Delete entry and all chunks from D1 and Vectorize |
Note:
recall's REST counterpart (GET /recall) clampstopKto1–20with a default of5;list_recent's REST counterpart (GET /list) defaultsnto20with a max of100(the MCP tool itself defaults to10/max50).
Returns the web dashboard (single-page HTML app). No auth required — auth is handled client-side via localStorage.