REST API
innernet speaks two protocols over the same memory: an MCP endpoint for AI clients, and this REST API for the agents you build. They are at full parity — every tool a connected AI client can call has an HTTP twin here, running the same handler against the same data. What your agent writes over REST, the user's Claude, Cursor and ChatGPT read over MCP. What they save there, your agent reads here.
Base URL: https://innernet.live/api/v1. GET /api/v1 returns a discovery document — the standing guidance, the endpoint map, and the tool-parity table — so an agent can learn innernet without being handed documentation by a human.
start here#
One call. Pass the question you are actually trying to answer, and innernet returns the slice that matters rather than the whole map:
curl "https://innernet.live/api/v1/context?slug=my-project&intent=what+did+we+decide+about+pricing" \
-H "Authorization: Bearer innernet_..."You get back a spine (what this project is), focus (the sections that answer the ask, budgeted to ~1600 tokens), periphery (one-line summaries of everything else, with how to expand each), and retrieval_advice (what to read next). Plus a receipt: how much was sent, and how many private facts were withheld.
Reach for the specific endpoints below when you already know which page you want.
the families#
- Context — projects → dimensions → captures: the structured world-model innernet maintains.
- Versioning — commits, branches, diff, merge, handoffs: fork an idea-space, let an agent write to the branch, read exactly what changed, then merge or discard. The part no flat memory store can do.
- Memories — a flat, namespaced store for apps you build: scope rows to your own end-users, agents, and runs.
- Tasks — the user's checklist, the same rows their dashboard and their AI client see.
- Artifacts — living documents that re-organise themselves as findings land.
- Personal memory — who the user is, behind disclosure gates.
privatenever crosses the wire, at any ceiling you ask for.
Plus ranked full-text search across all of it. The machine-readable spec lives at /api/v1/openapi.json.
authentication#
Mint an API key in your dashboard under connections → api. Keys are shown once, stored hashed, carry read and/or write scopes, and can be revoked individually (up to 10 active keys).
curl https://innernet.live/api/v1/projects \
-H "Authorization: Bearer innernet_..."OAuth 2.1 access tokens (the ones MCP clients hold) work on every endpoint too.
add and recall memories#
# remember something about one of YOUR users
curl -X POST https://innernet.live/api/v1/memories \
-H "Authorization: Bearer innernet_..." \
-H "Content-Type: application/json" \
-d '{
"content": "Prefers concise answers; works in TypeScript.",
"user_id": "user_42",
"tags": ["preference"]
}'
# recall them later
curl "https://innernet.live/api/v1/memories?user_id=user_42&limit=20" \
-H "Authorization: Bearer innernet_..."user_id, agent_id, and run_id are your namespaces — innernet keeps each end-user's memories separate under your account. metadata is free-form JSON; tags are filterable.
search everything#
curl "https://innernet.live/api/v1/search?q=pricing+decision" \
-H "Authorization: Bearer innernet_..."One query ranks across dimensions, nodes, captures, projects, and memories, returning highlighted snippets with kind + ref so you can fetch the source. Scope to one project with &project=slug.
read and write context#
# the full map
curl https://innernet.live/api/v1/projects/my-product \
-H "Authorization: Bearer innernet_..."
# one dimension
curl https://innernet.live/api/v1/projects/my-product/dimensions/roadmap \
-H "Authorization: Bearer innernet_..."
# replace it (writes a commit)
curl -X PUT https://innernet.live/api/v1/projects/my-product/dimensions/roadmap \
-H "Authorization: Bearer innernet_..." \
-H "Content-Type: application/json" \
-d '{"content": "# Roadmap\n\n- ship v1", "commit_message": "trim roadmap"}'
# append a capture (consolidated into dimensions on next sync)
curl -X POST https://innernet.live/api/v1/projects/my-product/captures \
-H "Authorization: Bearer innernet_..." \
-H "Content-Type: application/json" \
-d '{"content": "Decided: usage-based pricing.", "tags": ["decision"]}'version everything: commits & branches#
This is the part no other memory API has. Every save and capture is a commit; a branch forks the whole context map so two versions of an idea can exist at once — then diff and merge when a direction wins.
# history
curl https://innernet.live/api/v1/projects/my-product/commits \
-H "Authorization: Bearer innernet_..."
# fork the map at its current head
curl -X POST https://innernet.live/api/v1/projects/my-product/branches \
-H "Authorization: Bearer innernet_..." -H "Content-Type: application/json" \
-d '{"name": "pricing-experiment", "summary": "what if usage-based?"}'
# work on the branch — trunk untouched
curl -X PUT https://innernet.live/api/v1/projects/my-product/branches/pricing-experiment/dimensions/pricing \
-H "Authorization: Bearer innernet_..." -H "Content-Type: application/json" \
-d '{"content": "# Pricing\n\nUsage-based, $0.005/1k ops."}'
# what changed vs trunk?
curl https://innernet.live/api/v1/projects/my-product/branches/pricing-experiment/diff \
-H "Authorization: Bearer innernet_..."
# the experiment won — fold it back (records a merge commit, bumps head)
curl -X POST https://innernet.live/api/v1/projects/my-product/branches/pricing-experiment/merge \
-H "Authorization: Bearer innernet_..."Not ready to decide? PATCH the branch with {"status": "parked"} — it's archived with its overlay intact, revivable any time. Merge semantics are branch-wins; conflict-aware merge is on the roadmap.
personal memory over the API#
The account owner's Self Map — atomic facts with disclosure classes — is readable and writable with the same key. private facts never cross the API, whatever ceiling you ask for.
# facts up to a disclosure ceiling (self | trusted | work | public)
curl "https://innernet.live/api/v1/self/facts?max_disclosure=work" \
-H "Authorization: Bearer innernet_..."
# queue a fact-candidate (the consolidator distills it on next sync)
curl -X POST https://innernet.live/api/v1/self/capture \
-H "Authorization: Bearer innernet_..." -H "Content-Type: application/json" \
-d '{"content": "Prefers dark mode everywhere.", "dimension_hint": "preferences"}'And any project load can carry the owner's context with it — GET /v1/projects/{slug}?include_self=1 appends a disclosure-gated personal_context slice, so an app you build knows how you work the moment it loads what you're working on.
errors & rate limits#
Every error is one shape:
{ "error": { "code": "not_found", "message": "Project not found: my-product" } }| status | code | meaning |
|---|---|---|
| 401 | unauthorized | Missing/invalid bearer token |
| 403 | insufficient_scope | Key lacks read or write |
| 404 | not_found | Resource doesn't exist (or isn't yours) |
| 400 | invalid_body / invalid_query | Malformed request |
| 429 | rate_limited | Over 300 req/min — honor Retry-After |
CORS is open (Access-Control-Allow-Origin: *), so browser apps work — but never ship a write-scoped key to a browser; mint a read-only key instead.
endpoint reference#
parity — every tool, and the endpoint that mirrors it#
Each row is the same handler reached two ways. Nothing below is a re-implementation.
context
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_context | GET /v1/context | the one door — pass an intent, get a budgeted slice: spine, focus, periphery, and what to read next |
innernet_list_projects | GET /v1/projects | every context map you own, plus the ones shared into your rooms |
innernet_load_project | GET /v1/projects/{slug} | one map — lean by default, ?full=1 for every dimension body |
innernet_save_context | POST /v1/projects | create or update a map from structured content — writes a commit |
innernet_get_dimension | GET /v1/projects/{slug}/dimensions/{name} | a single dimension's prose, in full |
innernet_forget_project | DELETE /v1/projects/{slug} | permanently delete a map and everything in it — two calls: the first previews what is lost, the second needs `confirm` equal to the slug |
innernet_get_capture_protocol | GET /v1/projects/{slug}/capture-protocol | how this project asks to be captured into |
innernet_set_capture_protocol | PUT /v1/projects/{slug}/capture-protocol | change what gets captured here, and how |
memory
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_capture | POST /v1/captures | land a note without naming a project — innernet routes it and folds it in |
search | GET /v1/search | ranked full-text across dimensions, nodes, captures, projects and memories |
fetch | GET /v1/fetch | one map flattened to a single readable document |
versioning
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_list_branches | GET /v1/projects/{slug}/branches | every branch of this map |
innernet_branch_new | POST /v1/projects/{slug}/branches | fork the map — let an agent write here instead of the trunk |
innernet_branch_diff | GET /v1/projects/{slug}/branches/{name}/diff | exactly what changed on the branch |
innernet_branch_park | PATCH /v1/projects/{slug}/branches/{name} | park a branch, or wake it |
innernet_branch_merge | POST /v1/projects/{slug}/branches/{name}/merge | merge the branch back — branch wins on conflict |
innernet_handoff_read | GET /v1/projects/{slug}/handoff | where the last session left off — the note one agent leaves the next |
innernet_handoff_write | PUT /v1/projects/{slug}/handoff | leave that note |
tasks
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_task_list | GET /v1/tasks | a project's open work |
innernet_task_create | POST /v1/tasks | put something in flight |
innernet_task_update | PATCH /v1/tasks/{id} | change a task |
innernet_task_complete | POST /v1/tasks/{id}/complete | mark it done |
innernet_task_reorder | POST /v1/tasks/reorder | reorder the list |
artifacts
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_artifact_list | GET /v1/projects/{slug}/artifacts | every living document in this project |
innernet_artifact_start | POST /v1/projects/{slug}/artifacts | open a document that keeps re-organising itself as findings land |
innernet_artifact_status | GET /v1/projects/{slug}/artifacts/active | the document currently open, if any |
innernet_artifact_read | GET /v1/projects/{slug}/artifacts/{id} | read the document as it stands |
innernet_artifact_append | POST /v1/projects/{slug}/artifacts/{id}/fragments | add a finding — the document folds it in and restructures itself |
innernet_artifact_stop | POST /v1/projects/{slug}/artifacts/{id}/stop | close it — folds anything pending first |
personal memory
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_self_facts | GET /v1/self/facts | what innernet knows about the user, gated by disclosure — private never crosses |
innernet_self_capture | POST /v1/self/capture | note something durable about the user themselves |
innernet_self_status | GET /v1/self/status | the state of their Self Map |
innernet_self_sync | POST /v1/self/sync | fold pending captures into facts |
innernet_triage | POST /v1/triage | unsure whether it's about the user or the project? let innernet route it |
session
| MCP tool | REST endpoint | what it does |
|---|---|---|
innernet_session | GET /v1/session | what this session has read and kept so far |
innernet_ambient | POST /v1/ambient | pause or resume ambient capture |
REST-only routes (no tool equivalent) — the flat /v1/memories store, the commit log, and branch-dimension reads and writes — are in the endpoint reference below.
endpoint reference#
GET/v1/contextthe one door — pass an intent, get a budgeted slice: spine, focus, periphery, and what to read next
Mirrors the MCP tool `innernet_context` — same handler, same result. Requires the `read` scope.
GET/v1/projectsList projects
All context maps owned by the caller, most recently updated first.
POST/v1/projects/genesisstart a memory whose shape netti designs from the project itself (what `npx innernet` calls in a repo)
Requires the `write` scope.
GET/v1/projects/{slug}Load a context map
The full map: manifest, every dimension (markdown), every node, recent commits, and the per-project capture protocol.
slug | path · required | string |
include_self | query | Append a disclosure-gated slice of the account owner's Self Map (personal_context) |
GET/v1/projects/{slug}/capture-protocolhow this project asks to be captured into
Mirrors the MCP tool `innernet_get_capture_protocol` — same handler, same result. Requires the `read` scope.
slug | path · required | string |
PUT/v1/projects/{slug}/capture-protocolchange what gets captured here, and how
Mirrors the MCP tool `innernet_set_capture_protocol` — same handler, same result. Requires the `write` scope.
slug | path · required | string |
POST/v1/capturesland a note without naming a project — innernet routes it and folds it in
Mirrors the MCP tool `innernet_capture` — same handler, same result. Requires the `write` scope.
GET/v1/fetchone map flattened to a single readable document
Mirrors the MCP tool `fetch` — same handler, same result. Requires the `read` scope.
GET/v1/projects/{slug}/handoffwhere the last session left off — the note one agent leaves the next
Mirrors the MCP tool `innernet_handoff_read` — same handler, same result. Requires the `read` scope.
slug | path · required | string |
PUT/v1/projects/{slug}/handoffleave that note
Mirrors the MCP tool `innernet_handoff_write` — same handler, same result. Requires the `write` scope.
slug | path · required | string |
GET/v1/tasksa project's open work
Mirrors the MCP tool `innernet_task_list` — same handler, same result. Requires the `read` scope.
POST/v1/tasksput something in flight
Mirrors the MCP tool `innernet_task_create` — same handler, same result. Requires the `write` scope.
PATCH/v1/tasks/{id}change a task
Mirrors the MCP tool `innernet_task_update` — same handler, same result. Requires the `write` scope.
id | path · required | string |
POST/v1/tasks/{id}/completemark it done
Mirrors the MCP tool `innernet_task_complete` — same handler, same result. Requires the `write` scope.
id | path · required | string |
POST/v1/tasks/reorderreorder the list
Mirrors the MCP tool `innernet_task_reorder` — same handler, same result. Requires the `write` scope.
GET/v1/projects/{slug}/artifactsList artifacts
The project's live auto-maintained documents.
slug | path · required | string |
GET/v1/projects/{slug}/artifacts/activethe document currently open, if any
Mirrors the MCP tool `innernet_artifact_status` — same handler, same result. Requires the `read` scope.
slug | path · required | string |
POST/v1/projects/{slug}/artifacts/{id}/fragmentsadd a finding — the document folds it in and restructures itself
Mirrors the MCP tool `innernet_artifact_append` — same handler, same result. Requires the `write` scope.
slug | path · required | string |
id | path · required | string |
POST/v1/projects/{slug}/artifacts/{id}/stopclose it — folds anything pending first
Mirrors the MCP tool `innernet_artifact_stop` — same handler, same result. Requires the `write` scope.
slug | path · required | string |
id | path · required | string |
POST/v1/self/syncfold pending captures into facts
Mirrors the MCP tool `innernet_self_sync` — same handler, same result. Requires the `write` scope.
POST/v1/self/importbring existing memory in — Claude Code files, a ChatGPT export, notes (what `innernet import` calls)
Requires the `write` scope.
POST/v1/triageunsure whether it's about the user or the project? let innernet route it
Mirrors the MCP tool `innernet_triage` — same handler, same result. Requires the `write` scope.
GET/v1/sessionwhat this session has read and kept so far
Mirrors the MCP tool `innernet_session` — same handler, same result. Requires the `read` scope.
POST/v1/ambientpause or resume ambient capture
Mirrors the MCP tool `innernet_ambient` — same handler, same result. Requires the `write` scope.
GET/v1/projects/{slug}/dimensions/{name}Read a dimension
slug | path · required | string |
name | path · required | string |
PUT/v1/projects/{slug}/dimensions/{name}Create or replace a dimension
Replaces the dimension body and writes a commit to the project history.
slug | path · required | string |
name | path · required | string |
content | string · required | Full markdown body |
commit_message | string |
DELETE/v1/projects/{slug}/dimensions/{name}Delete a dimension
Removes the dimension and records the deletion in the commit log.
slug | path · required | string |
name | path · required | string |
POST/v1/projects/{slug}/capturesCapture into a project
Append a note/decision/insight to the project commit log. The background consolidator folds captures into dimensions on the next sync.
slug | path · required | string |
content | string · required | |
tags | array |
GET/v1/memoriesList memories
user_id | query | string |
agent_id | query | string |
run_id | query | string |
project | query | string |
tag | query | string |
limit | query | integer |
offset | query | integer |
POST/v1/memoriesAdd a memory
Store a memory scoped to your application. Namespace it with user_id / agent_id / run_id to keep each of your end-users’ memories separate.
content | string · required | |
user_id | string | Your end-user id |
agent_id | string | |
run_id | string | |
project | string | Optional innernet project slug to associate |
metadata | object | |
tags | array |
GET/v1/memories/{id}Get a memory
id | path · required | string |
PATCH/v1/memories/{id}Update a memory
id | path · required | string |
content | string | |
metadata | object | |
tags | array |
DELETE/v1/memories/{id}Delete a memory
id | path · required | string |
GET/v1/projects/{slug}/commitsList commits
The project's append-only history, newest first — every save, capture, sync, and merge.
slug | path · required | string |
limit | query | integer |
offset | query | integer |
GET/v1/projects/{slug}/commits/{hash}Get a commit
One commit with its full diff payload (capture content, merge diffs).
slug | path · required | string |
hash | path · required | string |
GET/v1/projects/{slug}/branchesList branches
slug | path · required | string |
POST/v1/projects/{slug}/branchesFork a branch
Fork the context map at its current head. The branch gets a full snapshot (overlay) of trunk dimensions + nodes; trunk stays untouched until merge.
slug | path · required | string |
name | string · required | Branch name (slug-like) |
summary | string |
GET/v1/projects/{slug}/branches/{name}Get a branch
slug | path · required | string |
name | path · required | string |
PATCH/v1/projects/{slug}/branches/{name}Park / unpark a branch
status "parked" archives without merging (overlay preserved); "active" revives.
slug | path · required | string |
name | path · required | string |
status | string · required |
GET/v1/projects/{slug}/branches/{name}/diffDiff branch vs trunk
added / modified / removed / unchanged for dimensions and nodes.
slug | path · required | string |
name | path · required | string |
POST/v1/projects/{slug}/branches/{name}/mergeMerge a branch
Apply the branch to trunk (branch wins; removed-in-branch deletes from trunk), record a merge commit, bump the head, mark the branch merged.
slug | path · required | string |
name | path · required | string |
GET/v1/projects/{slug}/branches/{name}/dimensions/{dim}Read a branch dimension
slug | path · required | string |
name | path · required | string |
dim | path · required | string |
PUT/v1/projects/{slug}/branches/{name}/dimensions/{dim}Write a dimension into a branch
Edits the branch overlay only — trunk is untouched until merge.
slug | path · required | string |
name | path · required | string |
dim | path · required | string |
content | string · required | Full markdown body |
DELETE/v1/projects/{slug}/branches/{name}/dimensions/{dim}Remove a dimension from a branch
Merging afterwards deletes it from trunk.
slug | path · required | string |
name | path · required | string |
dim | path · required | string |
GET/v1/projects/{slug}/artifacts/{id}Read an artifact
slug | path · required | string |
id | path · required | string |
GET/v1/self/factsRead Self Map facts
The account owner's Personal Memory, gated by disclosure ceiling. `private` never crosses the API regardless of the requested ceiling.
dimension | query | string |
max_disclosure | query | string |
POST/v1/self/captureCapture a Self candidate
Queue a fact-candidate about the account owner; the consolidator distills it on next sync.
content | string · required | |
dimension_hint | string | |
project_context | string |
GET/v1/self/statusSelf Map status
GET/v1/searchSearch everything
Ranked full-text search across dimensions, nodes, captures, projects, and memories, with highlighted snippets.
q | query · required | string |
project | query | Limit to one project slug |
limit | query | integer |