docsbuild on the API
one memory, two doors — the REST API at full parity with the MCP tools.
2 pages

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:

bash
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. private never 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).

bash
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#

bash
# 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#

bash
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#

bash
# 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.

bash
# 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.

bash
# 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:

json
{ "error": { "code": "not_found", "message": "Project not found: my-product" } }
statuscodemeaning
401unauthorizedMissing/invalid bearer token
403insufficient_scopeKey lacks read or write
404not_foundResource doesn't exist (or isn't yours)
400invalid_body / invalid_queryMalformed request
429rate_limitedOver 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 toolREST endpointwhat it does
innernet_contextGET /v1/contextthe one door — pass an intent, get a budgeted slice: spine, focus, periphery, and what to read next
innernet_list_projectsGET /v1/projectsevery context map you own, plus the ones shared into your rooms
innernet_load_projectGET /v1/projects/{slug}one map — lean by default, ?full=1 for every dimension body
innernet_save_contextPOST /v1/projectscreate or update a map from structured content — writes a commit
innernet_get_dimensionGET /v1/projects/{slug}/dimensions/{name}a single dimension's prose, in full
innernet_forget_projectDELETE /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_protocolGET /v1/projects/{slug}/capture-protocolhow this project asks to be captured into
innernet_set_capture_protocolPUT /v1/projects/{slug}/capture-protocolchange what gets captured here, and how

memory

MCP toolREST endpointwhat it does
innernet_capturePOST /v1/capturesland a note without naming a project — innernet routes it and folds it in
searchGET /v1/searchranked full-text across dimensions, nodes, captures, projects and memories
fetchGET /v1/fetchone map flattened to a single readable document

versioning

MCP toolREST endpointwhat it does
innernet_list_branchesGET /v1/projects/{slug}/branchesevery branch of this map
innernet_branch_newPOST /v1/projects/{slug}/branchesfork the map — let an agent write here instead of the trunk
innernet_branch_diffGET /v1/projects/{slug}/branches/{name}/diffexactly what changed on the branch
innernet_branch_parkPATCH /v1/projects/{slug}/branches/{name}park a branch, or wake it
innernet_branch_mergePOST /v1/projects/{slug}/branches/{name}/mergemerge the branch back — branch wins on conflict
innernet_handoff_readGET /v1/projects/{slug}/handoffwhere the last session left off — the note one agent leaves the next
innernet_handoff_writePUT /v1/projects/{slug}/handoffleave that note

tasks

MCP toolREST endpointwhat it does
innernet_task_listGET /v1/tasksa project's open work
innernet_task_createPOST /v1/tasksput something in flight
innernet_task_updatePATCH /v1/tasks/{id}change a task
innernet_task_completePOST /v1/tasks/{id}/completemark it done
innernet_task_reorderPOST /v1/tasks/reorderreorder the list

artifacts

MCP toolREST endpointwhat it does
innernet_artifact_listGET /v1/projects/{slug}/artifactsevery living document in this project
innernet_artifact_startPOST /v1/projects/{slug}/artifactsopen a document that keeps re-organising itself as findings land
innernet_artifact_statusGET /v1/projects/{slug}/artifacts/activethe document currently open, if any
innernet_artifact_readGET /v1/projects/{slug}/artifacts/{id}read the document as it stands
innernet_artifact_appendPOST /v1/projects/{slug}/artifacts/{id}/fragmentsadd a finding — the document folds it in and restructures itself
innernet_artifact_stopPOST /v1/projects/{slug}/artifacts/{id}/stopclose it — folds anything pending first

personal memory

MCP toolREST endpointwhat it does
innernet_self_factsGET /v1/self/factswhat innernet knows about the user, gated by disclosure — private never crosses
innernet_self_capturePOST /v1/self/capturenote something durable about the user themselves
innernet_self_statusGET /v1/self/statusthe state of their Self Map
innernet_self_syncPOST /v1/self/syncfold pending captures into facts
innernet_triagePOST /v1/triageunsure whether it's about the user or the project? let innernet route it

session

MCP toolREST endpointwhat it does
innernet_sessionGET /v1/sessionwhat this session has read and kept so far
innernet_ambientPOST /v1/ambientpause 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.

parameters
slugpath · requiredstring
include_selfqueryAppend 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.

parameters
slugpath · requiredstring
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.

parameters
slugpath · requiredstring
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.

parameters
slugpath · requiredstring
PUT/v1/projects/{slug}/handoffleave that note

Mirrors the MCP tool `innernet_handoff_write` — same handler, same result. Requires the `write` scope.

parameters
slugpath · requiredstring
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.

parameters
idpath · requiredstring
POST/v1/tasks/{id}/completemark it done

Mirrors the MCP tool `innernet_task_complete` — same handler, same result. Requires the `write` scope.

parameters
idpath · requiredstring
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.

parameters
slugpath · requiredstring
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.

parameters
slugpath · requiredstring
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.

parameters
slugpath · requiredstring
idpath · requiredstring
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.

parameters
slugpath · requiredstring
idpath · requiredstring
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
parameters
slugpath · requiredstring
namepath · requiredstring
PUT/v1/projects/{slug}/dimensions/{name}Create or replace a dimension

Replaces the dimension body and writes a commit to the project history.

parameters
slugpath · requiredstring
namepath · requiredstring
body
contentstring · requiredFull markdown body
commit_messagestring
DELETE/v1/projects/{slug}/dimensions/{name}Delete a dimension

Removes the dimension and records the deletion in the commit log.

parameters
slugpath · requiredstring
namepath · requiredstring
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.

parameters
slugpath · requiredstring
body
contentstring · required
tagsarray
GET/v1/memoriesList memories
parameters
user_idquerystring
agent_idquerystring
run_idquerystring
projectquerystring
tagquerystring
limitqueryinteger
offsetqueryinteger
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.

body
contentstring · required
user_idstringYour end-user id
agent_idstring
run_idstring
projectstringOptional innernet project slug to associate
metadataobject
tagsarray
GET/v1/memories/{id}Get a memory
parameters
idpath · requiredstring
PATCH/v1/memories/{id}Update a memory
parameters
idpath · requiredstring
body
contentstring
metadataobject
tagsarray
DELETE/v1/memories/{id}Delete a memory
parameters
idpath · requiredstring
GET/v1/projects/{slug}/commitsList commits

The project's append-only history, newest first — every save, capture, sync, and merge.

parameters
slugpath · requiredstring
limitqueryinteger
offsetqueryinteger
GET/v1/projects/{slug}/commits/{hash}Get a commit

One commit with its full diff payload (capture content, merge diffs).

parameters
slugpath · requiredstring
hashpath · requiredstring
GET/v1/projects/{slug}/branchesList branches
parameters
slugpath · requiredstring
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.

parameters
slugpath · requiredstring
body
namestring · requiredBranch name (slug-like)
summarystring
GET/v1/projects/{slug}/branches/{name}Get a branch
parameters
slugpath · requiredstring
namepath · requiredstring
PATCH/v1/projects/{slug}/branches/{name}Park / unpark a branch

status "parked" archives without merging (overlay preserved); "active" revives.

parameters
slugpath · requiredstring
namepath · requiredstring
body
statusstring · required
GET/v1/projects/{slug}/branches/{name}/diffDiff branch vs trunk

added / modified / removed / unchanged for dimensions and nodes.

parameters
slugpath · requiredstring
namepath · requiredstring
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.

parameters
slugpath · requiredstring
namepath · requiredstring
GET/v1/projects/{slug}/branches/{name}/dimensions/{dim}Read a branch dimension
parameters
slugpath · requiredstring
namepath · requiredstring
dimpath · requiredstring
PUT/v1/projects/{slug}/branches/{name}/dimensions/{dim}Write a dimension into a branch

Edits the branch overlay only — trunk is untouched until merge.

parameters
slugpath · requiredstring
namepath · requiredstring
dimpath · requiredstring
body
contentstring · requiredFull markdown body
DELETE/v1/projects/{slug}/branches/{name}/dimensions/{dim}Remove a dimension from a branch

Merging afterwards deletes it from trunk.

parameters
slugpath · requiredstring
namepath · requiredstring
dimpath · requiredstring
GET/v1/projects/{slug}/artifacts/{id}Read an artifact
parameters
slugpath · requiredstring
idpath · requiredstring
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.

parameters
dimensionquerystring
max_disclosurequerystring
POST/v1/self/captureCapture a Self candidate

Queue a fact-candidate about the account owner; the consolidator distills it on next sync.

body
contentstring · required
dimension_hintstring
project_contextstring
GET/v1/self/statusSelf Map status
GET/v1/searchSearch everything

Ranked full-text search across dimensions, nodes, captures, projects, and memories, with highlighted snippets.

parameters
qquery · requiredstring
projectqueryLimit to one project slug
limitqueryinteger