Skip to content

REST API Reference

The MemoryLayer server exposes a RESTful API at http://localhost:61001 by default. All endpoints accept and return JSON.

Authentication

For local development, no authentication is required. For production deployments, include an API key in the Authorization header:

Authorization: Bearer your-api-key

Many endpoints also accept an X-Session-ID header to provide session context for workspace resolution.


Memory Operations

POST /v1/memories

Store a new memory with automatic embedding and classification.

Request Body:

FieldTypeRequiredDefaultDescription
contentstringyes—Memory content to store
workspace_idstringnofrom session or _defaultWorkspace override
typestringnoauto-classifiedCognitive type: episodic, semantic, procedural, working
subtypestringnonullDomain-specific classification
importancefloatno0.5Memory importance (0.0-1.0)
tagsstring[]no[]Tags for categorization
metadataobjectno{}Arbitrary metadata
associationsstring[]no[]Memory IDs to associate with
context_idstringnofrom sessionTarget memory context
observer_idstringnonullEntity doing the observing (agent ID, user ID)
subject_idstringnonullEntity this memory is about
user_idstringnofrom authUser scope for this memory

Response: 201 Created

{
"memory": {
"id": "mem_abc123",
"content": "User prefers Python for backend development",
"type": "semantic",
"subtype": "preference",
"importance": 0.8,
"tags": ["preferences", "programming"],
"created_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories \
-H "Content-Type: application/json" \
-d '{
"content": "User prefers Python for backend development",
"type": "semantic",
"importance": 0.8,
"tags": ["preferences", "programming"]
}'

GET /v1/memories/{memory_id}

Retrieve a single memory by ID.

Path Parameters:

ParameterTypeDescription
memory_idstringMemory identifier

Response: 200 OK

{
"memory": {
"id": "mem_abc123",
"content": "User prefers Python for backend development",
"type": "semantic",
"importance": 0.8,
"tags": ["preferences", "programming"],
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl http://localhost:61001/v1/memories/mem_abc123

PUT /v1/memories/{memory_id}

Update an existing memory. Only provided fields are updated.

Path Parameters:

ParameterTypeDescription
memory_idstringMemory identifier

Request Body:

FieldTypeRequiredDescription
contentstringnoUpdated content
typestringnoUpdated cognitive type
subtypestringnoUpdated domain classification
importancefloatnoUpdated importance (0.0-1.0)
tagsstring[]noUpdated tags
metadataobjectnoUpdated metadata
pinnedbooleannoPin/unpin memory (pinned memories are exempt from decay)

Response: 200 OK

{
"memory": {
"id": "mem_abc123",
"content": "User strongly prefers Python for backend development",
"importance": 0.9,
"pinned": true
}
}

curl example:

Terminal window
curl -X PUT http://localhost:61001/v1/memories/mem_abc123 \
-H "Content-Type: application/json" \
-d '{
"importance": 0.9,
"pinned": true
}'

DELETE /v1/memories/{memory_id}

Delete a memory (soft delete by default).

Path Parameters:

ParameterTypeDescription
memory_idstringMemory identifier

Query Parameters:

ParameterTypeDefaultDescription
hardbooleanfalsePermanently delete instead of archiving

Response: 204 No Content

curl example:

Terminal window
# Soft delete (archive)
curl -X DELETE http://localhost:61001/v1/memories/mem_abc123
# Hard delete (permanent)
curl -X DELETE "http://localhost:61001/v1/memories/mem_abc123?hard=true"

POST /v1/memories/recall

Search memories by semantic query. Supports multiple retrieval modes.

Request Body:

FieldTypeRequiredDefaultDescription
querystringyes—Natural language query
workspace_idstringnofrom sessionWorkspace override
typesstring[]no[]Filter by cognitive types
subtypesstring[]no[]Filter by domain subtypes
tagsstring[]no[]Filter by tags (AND logic)
context_idstringnofrom sessionFilter by memory context
observer_idstringnonullFilter by observer entity
subject_idstringnonullFilter by subject entity
user_idstringnofrom authFilter by user
modestringnoragRetrieval strategy. rag is the active mode; llm and hybrid are deprecated (use the Context Environment + RLM for LLM-driven analysis).
tolerancestringnoserver defaultSearch precision
limitintegerno10Maximum memories to return (1-100)
min_relevancefloatnoserver defaultMinimum relevance score (0.0-1.0)
recency_weightfloatnoserver defaultWeight for recency boosting (0.0-1.0)
include_associationsbooleannoserver defaultInclude linked memories
traverse_depthintegernoserver defaultMulti-hop graph traversal depth (0-5)
max_expansionintegernoserver defaultMax memories via graph expansion (1-500)
created_afterdatetimenonullFilter memories created after this time
created_beforedatetimenonullFilter memories created before this time
contextobject[]no[]Recent conversation context
rag_thresholdfloatno0.8Use LLM if RAG confidence < threshold
detail_levelstringnoserver defaultabstract, overview, or full
include_archivedbooleannofalseInclude archived memories
exclude_idsstring[]no[]Memory IDs to exclude from results

Retrieval Modes:

ModeDescriptionStatus
ragVector similarity search + graph traversalActive
llmQuery rewriting + enhanced searchDeprecated
hybridRAG first, LLM if insufficientDeprecated

The llm and hybrid modes are being phased out. Use rag for recall and the Context Environment with RLM when you need LLM-driven analysis over memories.

Response: 200 OK

{
"memories": [
{
"id": "mem_abc123",
"content": "User prefers Python for backend development",
"type": "semantic",
"importance": 0.8,
"relevance": 0.92,
"tags": ["preferences", "programming"]
}
],
"total_count": 1,
"mode_used": "rag",
"search_latency_ms": 42.5
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/recall \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"query": "What programming languages does the user prefer?",
"limit": 10,
"mode": "hybrid",
"types": ["semantic"],
"tags": ["preferences"]
}'

POST /v1/memories/reflect

Synthesize insights across memories using LLM reflection.

Request Body:

FieldTypeRequiredDefaultDescription
querystringyes—What to reflect on
workspace_idstringnofrom sessionWorkspace override
detail_levelstringnoserver defaultLevel of detail: abstract, overview, full
include_sourcesbooleannotrueInclude source memory references
depthintegerno2Association traversal depth (1-5)
typesstring[]no[]Filter by types
subtypesstring[]no[]Filter by subtypes
tagsstring[]no[]Filter by tags
context_idstringnofrom sessionFilter by memory context
observer_idstringnonullFilter by observer entity
subject_idstringnonullFilter by subject entity

Response: 200 OK

{
"reflection": "Based on stored memories, the user prefers...",
"source_memories": ["mem_abc123", "mem_def456"],
"confidence": 0.85
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/reflect \
-H "Content-Type: application/json" \
-d '{
"query": "Summarize user technology preferences",
"detail_level": "overview",
"include_sources": true,
"depth": 2
}'

POST /v1/memories/{memory_id}/decay

Apply decay to reduce a memory’s importance over time. Pinned memories are exempt from decay.

Path Parameters:

ParameterTypeDescription
memory_idstringMemory identifier

Request Body:

FieldTypeRequiredDefaultDescription
decay_ratefloatno0.1Decay rate to apply (0.0-1.0)

Response: 200 OK — returns the updated memory with decayed importance.

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/mem_abc123/decay \
-H "Content-Type: application/json" \
-d '{"decay_rate": 0.1}'

POST /v1/memories/batch

Perform multiple memory operations in a single request. Supports create, update, and delete operations.

Request Body:

FieldTypeRequiredDescription
operationsobject[]yesList of typed batch operations

Each operation must include an op field set to "create", "update", or "delete".

Create operation fields:

FieldTypeRequiredDefaultDescription
opstringyes—Must be "create"
contentstringyes—Memory content
typestringnoauto-classifiedCognitive type
subtypestringnonullDomain classification
importancefloatno0.5Importance (0.0-1.0)
tagsstring[]no[]Tags
metadataobjectno{}Metadata
observer_idstringnonullObserver entity
subject_idstringnonullSubject entity

Update operation fields:

FieldTypeRequiredDescription
opstringyesMust be "update"
memory_idstringyesMemory ID to update
contentstringnoUpdated content
typestringnoUpdated type
subtypestringnoUpdated subtype
importancefloatnoUpdated importance
tagsstring[]noUpdated tags
metadataobjectnoUpdated metadata
pinnedbooleannoPin/unpin memory

Delete operation fields:

FieldTypeRequiredDefaultDescription
opstringyes—Must be "delete"
memory_idstringyes—Memory ID to delete
hardbooleannofalseHard delete (permanent)

Response: 200 OK

{
"total_operations": 3,
"successful": 2,
"failed": 1,
"results": [
{"index": 0, "type": "create", "status": "success", "memory_id": "mem_new1"},
{"index": 1, "type": "create", "status": "success", "memory_id": "mem_new2"},
{"index": 2, "type": "delete", "status": "error", "error": "Memory not found: mem_old"}
]
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/batch \
-H "Content-Type: application/json" \
-d '{
"operations": [
{"op": "create", "content": "Memory 1", "importance": 0.7},
{"op": "create", "content": "Memory 2", "importance": 0.8},
{"op": "delete", "memory_id": "mem_old", "hard": false}
]
}'

Associations

POST /v1/memories/{memory_id}/associate

Create a typed relationship between two memories.

Path Parameters:

ParameterTypeDescription
memory_idstringSource memory ID

Request Body:

FieldTypeRequiredDefaultDescription
target_idstringyes—Target memory ID
relationshipstringyes—Relationship type (e.g., SIMILAR_TO, CAUSES, SOLVES)
strengthfloatno0.5Relationship strength (0.0-1.0)
metadataobjectno{}Arbitrary metadata
workspace_idstringnofrom sessionWorkspace override

Response: 201 Created

{
"association": {
"id": "assoc_xyz789",
"source_id": "mem_problem_123",
"target_id": "mem_solution_456",
"relationship": "SOLVES",
"strength": 0.9,
"created_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/mem_problem_123/associate \
-H "Content-Type: application/json" \
-d '{
"target_id": "mem_solution_456",
"relationship": "SOLVES",
"strength": 0.9
}'

GET /v1/memories/{memory_id}/associations

Get all associations for a memory.

Path Parameters:

ParameterTypeDescription
memory_idstringMemory identifier

Query Parameters:

ParameterTypeDefaultDescription
relationshipsstringnullComma-separated relationship types to filter by
directionstringbothoutgoing, incoming, or both

Response: 200 OK

{
"associations": [
{
"id": "assoc_xyz789",
"source_id": "mem_problem_123",
"target_id": "mem_solution_456",
"relationship": "SOLVES",
"strength": 0.9
}
],
"total_count": 1
}

curl example:

Terminal window
# All associations
curl http://localhost:61001/v1/memories/mem_abc123/associations
# Filter by relationship type and direction
curl "http://localhost:61001/v1/memories/mem_abc123/associations?relationships=CAUSES,SOLVES&direction=outgoing"

POST /v1/memories/{memory_id}/traverse

Multi-hop graph traversal starting from a specific memory.

Path Parameters:

ParameterTypeDescription
memory_idstringStarting memory for traversal

Request Body:

FieldTypeRequiredDefaultDescription
workspace_idstringnofrom sessionWorkspace override
max_depthintegerno2Maximum traversal depth (1-5)
relationship_typesstring[]no[]Filter by relationship types (empty = all)
directionstringnobothoutgoing, incoming, or both
min_strengthfloatno0.0Minimum edge strength (0.0-1.0)

Response: 200 OK

{
"paths": [
{
"nodes": ["mem_a", "mem_b", "mem_c"],
"edges": [
{"source": "mem_a", "target": "mem_b", "relationship": "CAUSES"},
{"source": "mem_b", "target": "mem_c", "relationship": "LEADS_TO"}
]
}
],
"unique_nodes": ["mem_a", "mem_b", "mem_c"],
"total_paths": 1
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/memories/mem_abc123/traverse \
-H "Content-Type: application/json" \
-d '{
"relationship_types": ["CAUSES", "LEADS_TO"],
"max_depth": 3,
"direction": "both",
"min_strength": 0.5
}'

Sessions

POST /v1/sessions

Create a new working memory session. Workspaces and contexts are auto-created if they do not exist.

Request Body:

FieldTypeRequiredDefaultDescription
session_idstringnoauto-generatedClient-provided session ID
workspace_idstringno_defaultWorkspace ID (auto-created if absent)
ttl_secondsintegerno3600Session TTL in seconds (60-86400)
metadataobjectno{}Session metadata
context_idstringno_defaultContext to bind session to
working_memoryobjectnonullInitial working memory key-value pairs
briefingbooleannofalseInclude briefing with relevant memories
briefing_optionsobjectnonullBriefing options: lookback_hours, detail_level, limit

Response: 201 Created

{
"session": {
"id": "sess_abc123",
"workspace_id": "my-workspace",
"context_id": "_default",
"expires_at": "2026-01-15T11:30:00Z",
"metadata": {"task": "debugging"}
},
"briefing": null
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/sessions \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "my-workspace",
"ttl_seconds": 3600,
"metadata": {"task": "debugging"},
"briefing": true
}'

GET /v1/sessions

List sessions in a workspace.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace to list sessions for
context_idstringnullFilter by context
include_expiredbooleanfalseInclude expired sessions

Response: 200 OK

{
"sessions": [
{
"id": "sess_abc123",
"workspace_id": "my-workspace",
"expires_at": "2026-01-15T11:30:00Z"
}
],
"total_count": 1
}

curl example:

Terminal window
curl "http://localhost:61001/v1/sessions?workspace_id=my-workspace&include_expired=false"

GET /v1/sessions/briefing

Get a briefing of recent workspace activity and context. Includes workspace summary, recent sessions, open threads, and detected contradictions.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace to get briefing for
lookback_minutesinteger60How far back to look for activity
detail_levelstringabstractDetail level for memory content
limitinteger10Maximum items to include
include_memoriesbooleantrueInclude recent memories
include_contradictionsbooleantrueInclude detected contradictions

Response: 200 OK

{
"briefing": {
"workspace_id": "my-workspace",
"summary": "Workspace has 142 memories. 3 sessions active.",
"recent_memories": [],
"contradictions": []
}
}

curl example:

Terminal window
curl "http://localhost:61001/v1/sessions/briefing?workspace_id=my-workspace&lookback_minutes=120"

GET /v1/sessions/{session_id}

Retrieve a session by ID.

Path Parameters:

ParameterTypeDescription
session_idstringSession identifier

Response: 200 OK

{
"session": {
"id": "sess_abc123",
"workspace_id": "my-workspace",
"expires_at": "2026-01-15T11:30:00Z",
"metadata": {"task": "debugging"}
}
}

curl example:

Terminal window
curl http://localhost:61001/v1/sessions/sess_abc123

DELETE /v1/sessions/{session_id}

Delete a session and all its context data.

Response: 204 No Content

curl example:

Terminal window
curl -X DELETE http://localhost:61001/v1/sessions/sess_abc123

POST /v1/sessions/{session_id}/memory

Store a key-value pair in session working memory.

Path Parameters:

ParameterTypeDescription
session_idstringSession identifier

Request Body:

FieldTypeRequiredDefaultDescription
keystringyes—Working memory key
valueanyyes—Working memory value (JSON-serializable)
ttl_secondsintegernonullOptional TTL override for this entry

Response: 201 Created

{
"key": "current_task",
"value": {"description": "Debugging auth", "file": "auth.py"},
"ttl_seconds": null,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-15T10:30:00Z"
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/sessions/sess_abc123/memory \
-H "Content-Type: application/json" \
-d '{
"key": "current_task",
"value": {"description": "Debugging auth", "file": "auth.py"}
}'

GET /v1/sessions/{session_id}/memory

Retrieve working memory from a session. Returns a single entry if key is specified, or all entries otherwise.

Path Parameters:

ParameterTypeDescription
session_idstringSession identifier

Query Parameters:

ParameterTypeDefaultDescription
keystringnullSpecific key to retrieve (returns all if omitted)

Response: 200 OK

{
"current_task": {"description": "Debugging auth", "file": "auth.py"},
"findings": ["Issue in token validation"]
}

curl example:

Terminal window
# Get all working memory
curl http://localhost:61001/v1/sessions/sess_abc123/memory
# Get specific key
curl "http://localhost:61001/v1/sessions/sess_abc123/memory?key=current_task"

POST /v1/sessions/{session_id}/commit

Commit session working memory to long-term storage. Working memories are persisted via write-behind as they are written during the session, so this operation is lightweight.

Path Parameters:

ParameterTypeDescription
session_idstringSession identifier

Request Body (optional):

FieldTypeRequiredDefaultDescription
min_importancefloatno0.5Minimum importance threshold (0.0-1.0)
deduplicatebooleannotrueEnable deduplication of extracted memories
categoriesstring[]nonullCategory names to commit (null for all)
max_memoriesintegerno50Maximum memories to extract (1-500)

Response: 200 OK

{
"session_id": "sess_abc123",
"memories_extracted": 5,
"memories_deduplicated": 1,
"memories_created": 4,
"breakdown": {"task": 2, "findings": 2},
"extraction_time_ms": 150
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/sessions/sess_abc123/commit \
-H "Content-Type: application/json" \
-d '{
"min_importance": 0.5,
"deduplicate": true,
"max_memories": 50
}'

POST /v1/sessions/{session_id}/touch

Extend session TTL using sliding window. Resets the session’s expires_at to now + TTL.

Path Parameters:

ParameterTypeDescription
session_idstringSession identifier

Query Parameters:

ParameterTypeDefaultDescription
extend_secondsintegerserver defaultSeconds to extend TTL (60-86400)

Response: 200 OK

{
"expires_at": "2026-01-15T12:30:00Z"
}

curl example:

Terminal window
# Extend with default TTL
curl -X POST http://localhost:61001/v1/sessions/sess_abc123/touch
# Extend by 2 hours
curl -X POST "http://localhost:61001/v1/sessions/sess_abc123/touch?extend_seconds=7200"

Workspaces

POST /v1/workspaces

Create a new workspace. Workspaces provide memory isolation.

Request Body:

FieldTypeRequiredDefaultDescription
namestringyes—Workspace name
settingsobjectno{}Workspace-level settings

Response: 201 Created

{
"workspace": {
"id": "ws_a1b2c3d4e5f6g7h8",
"name": "My Project",
"settings": {},
"created_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/workspaces \
-H "Content-Type: application/json" \
-d '{"name": "My Project", "settings": {}}'

GET /v1/workspaces

List all workspaces.

Response: 200 OK

{
"workspaces": [
{"id": "ws_abc123", "name": "Project Alpha"},
{"id": "_default", "name": "Default"}
]
}

curl example:

Terminal window
curl http://localhost:61001/v1/workspaces

GET /v1/workspaces/{workspace_id}

Get workspace details.

Response: 200 OK

{
"workspace": {
"id": "ws_abc123",
"name": "Project Alpha",
"settings": {},
"created_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl http://localhost:61001/v1/workspaces/ws_abc123

PUT /v1/workspaces/{workspace_id}

Update workspace name or settings.

Request Body:

FieldTypeRequiredDescription
namestringnoUpdated workspace name
settingsobjectnoUpdated settings

Response: 200 OK — returns the updated workspace.

curl example:

Terminal window
curl -X PUT http://localhost:61001/v1/workspaces/ws_abc123 \
-H "Content-Type: application/json" \
-d '{"name": "Project Alpha v2"}'

DELETE /v1/workspaces/{workspace_id}

Delete a workspace and all associated data.

Response: 204 No Content

curl example:

Terminal window
curl -X DELETE http://localhost:61001/v1/workspaces/ws_abc123

GET /v1/workspaces/{workspace_id}/schema

Get workspace schema including available relationship types and memory subtypes.

Response: 200 OK

{
"relationship_types": ["SIMILAR_TO", "CAUSES", "SOLVES", "LEADS_TO", "PART_OF"],
"memory_subtypes": ["preference", "fact", "opinion", "goal", "plan"],
"can_customize": false
}

curl example:

Terminal window
curl http://localhost:61001/v1/workspaces/ws_abc123/schema

GET /v1/workspaces/{workspace_id}/export

Export workspace memories and associations as streaming NDJSON.

Query Parameters:

ParameterTypeDefaultDescription
offsetinteger0Skip first N memories
limitinteger0Max memories to export (0 = unlimited)
include_associationsbooleantrueInclude memory associations

Response: 200 OK with Content-Type: application/x-ndjson

The stream contains lines of JSON objects with these types:

Line typeDescription
headerExport metadata (version, workspace, counts)
memoryIndividual memory with index
associationIndividual association
footerSummary counts

curl example:

Terminal window
# Export all memories to file
curl http://localhost:61001/v1/workspaces/ws_abc123/export -o export.ndjson
# Export first 100 memories without associations
curl "http://localhost:61001/v1/workspaces/ws_abc123/export?limit=100&include_associations=false"

POST /v1/workspaces/{workspace_id}/import

Import memories and associations from JSON or NDJSON export. Supports both application/json and application/x-ndjson content types. Duplicate memories (by content hash) are automatically skipped.

Request Body (JSON format):

{
"data": {
"version": "1.0",
"workspace_id": "source-workspace",
"exported_at": "2026-01-15T10:30:00Z",
"memories": [
{"id": "mem_1", "content": "...", "content_hash": "...", "type": "semantic"}
],
"associations": [
{"source_id": "mem_1", "target_id": "mem_2", "relationship_type": "SIMILAR_TO", "strength": 0.8}
]
}
}

Response: 200 OK

{
"imported": 10,
"skipped_duplicates": 2,
"errors": 0,
"details": ["Imported 5 associations"]
}

curl example:

Terminal window
# Import from NDJSON file
curl -X POST http://localhost:61001/v1/workspaces/ws_abc123/import \
-H "Content-Type: application/x-ndjson" \
--data-binary @export.ndjson
# Import from JSON
curl -X POST http://localhost:61001/v1/workspaces/ws_abc123/import \
-H "Content-Type: application/json" \
-d @import.json

Contradictions

GET /v1/workspaces/{workspace_id}/contradictions

List unresolved contradictions in a workspace.

Path Parameters:

ParameterTypeDescription
workspace_idstringWorkspace identifier

Query Parameters:

ParameterTypeDefaultDescription
limitinteger10Maximum contradictions to return

Response: 200 OK

{
"contradictions": [
{
"id": "ctr_abc123",
"workspace_id": "my-workspace",
"memory_a_id": "mem_1",
"memory_b_id": "mem_2",
"contradiction_type": "value_conflict",
"confidence": 0.85,
"detection_method": "semantic",
"detected_at": "2026-01-15T10:30:00Z",
"resolved_at": null,
"resolution": null
}
],
"count": 1
}

curl example:

Terminal window
curl "http://localhost:61001/v1/workspaces/my-workspace/contradictions?limit=20"

POST /v1/contradictions/{contradiction_id}/resolve

Resolve a contradiction with a chosen strategy.

Path Parameters:

ParameterTypeDescription
contradiction_idstringContradiction identifier

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace override

Request Body:

FieldTypeRequiredDescription
resolutionstringyesStrategy: keep_a, keep_b, keep_both, or merge
merged_contentstringwhen mergeMerged content (required when resolution is merge)

Response: 200 OK — returns the resolved contradiction.

curl example:

Terminal window
# Keep one memory
curl -X POST http://localhost:61001/v1/contradictions/ctr_abc123/resolve \
-H "Content-Type: application/json" \
-d '{"resolution": "keep_a"}'
# Merge conflicting memories
curl -X POST http://localhost:61001/v1/contradictions/ctr_abc123/resolve \
-H "Content-Type: application/json" \
-d '{"resolution": "merge", "merged_content": "User prefers Python 3.11+ for backend work"}'

POST /v1/workspaces/{workspace_id}/contradictions/scan

Trigger a workspace-wide scan for contradictions among stored memories.

Path Parameters:

ParameterTypeDescription
workspace_idstringWorkspace identifier

Request Body (optional):

FieldTypeRequiredDefaultDescription
batch_sizeintegernoserver defaultMemories to process per batch (1-500)

Response: 200 OK

{
"workspace_id": "my-workspace",
"contradictions_found": 2,
"contradictions": [
{
"id": "ctr_new1",
"memory_a_id": "mem_1",
"memory_b_id": "mem_5",
"contradiction_type": "negation",
"confidence": 0.92
}
]
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/workspaces/my-workspace/contradictions/scan \
-H "Content-Type: application/json" \
-d '{"batch_size": 100}'

Entities

POST /v1/entities/{entity_id}/derive

Trigger inference derivation for an entity. Analyzes all memories about the entity and derives higher-order insights (patterns, preferences, tendencies) stored as INFERENCE-subtype memories.

Path Parameters:

ParameterTypeDescription
entity_idstringEntity identifier (agent ID, user ID, etc.)

Request Body:

FieldTypeRequiredDefaultDescription
workspace_idstringnofrom sessionWorkspace override
observer_idstringnonullOptional observer perspective filter
forcebooleannofalseForce re-derivation even if recent insights exist

Response: 200 OK

{
"subject_id": "user_123",
"workspace_id": "my-workspace",
"insights_created": 3,
"insights_updated": 1,
"source_memory_count": 25,
"insights": []
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/entities/user_123/derive \
-H "Content-Type: application/json" \
-d '{"force": true}'

GET /v1/entities/{entity_id}/card

Get a cached entity profile card — a synthesized view combining reflection and derived insights. Results are cached and lazily recalculated.

Path Parameters:

ParameterTypeDescription
entity_idstringEntity identifier

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace override
force_refreshbooleanfalseTrigger immediate recalculation

Response: 200 OK

{
"entity_id": "user_123",
"workspace_id": "my-workspace",
"reflection": "This user is a senior Python developer who...",
"insights": [],
"source_memories": ["mem_1", "mem_2", "mem_3"],
"confidence": 0.85,
"cached": true,
"generated_at": "2026-01-15T10:30:00Z"
}

curl example:

Terminal window
# Get cached card
curl "http://localhost:61001/v1/entities/user_123/card?workspace_id=my-workspace"
# Force refresh
curl "http://localhost:61001/v1/entities/user_123/card?force_refresh=true"

GET /v1/entities/{entity_id}/insights

Get derived insights for an entity. Returns existing INFERENCE-subtype memories without triggering new derivation.

Path Parameters:

ParameterTypeDescription
entity_idstringEntity identifier

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace override
observer_idstringnullFilter by observer perspective
limitinteger20Maximum insights to return

Response: 200 OK

{
"entity_id": "user_123",
"workspace_id": "my-workspace",
"insights": [],
"total_count": 0
}

curl example:

Terminal window
curl "http://localhost:61001/v1/entities/user_123/insights?workspace_id=my-workspace&limit=10"

Chat Threads

POST /v1/threads

Create a new chat thread for conversation history storage.

Request Body:

FieldTypeRequiredDefaultDescription
thread_idstringnoauto-generatedClient-provided thread ID
workspace_idstringnofrom sessionWorkspace override
user_idstringnonullUser scope for this thread
context_idstringno_defaultContext within workspace
observer_idstringnonullObserver entity ID (typically the AI agent)
subject_idstringnonullSubject entity ID (typically the human user)
titlestringnonullOptional display title
metadataobjectno{}Arbitrary metadata
expires_atdatetimenonullOptional expiration (null = permanent)

Response: 201 Created

{
"thread": {
"thread_id": "thread_abc123",
"workspace_id": "my-workspace",
"title": "Debugging session",
"message_count": 0,
"created_at": "2026-01-15T10:30:00Z"
}
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/threads \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "my-workspace",
"title": "Debugging session",
"observer_id": "agent_1",
"subject_id": "user_123"
}'

GET /v1/threads

List chat threads, optionally filtered by workspace and user.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter
user_idstringnullUser filter
limitinteger50Max threads to return (1-200)
offsetinteger0Pagination offset

Response: 200 OK

{
"threads": [
{
"thread_id": "thread_abc123",
"title": "Debugging session",
"message_count": 12
}
],
"total_count": 1
}

curl example:

Terminal window
curl "http://localhost:61001/v1/threads?workspace_id=my-workspace&limit=20"

GET /v1/threads/{thread_id}

Get thread metadata by ID.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter

Response: 200 OK — returns the thread object.

curl example:

Terminal window
curl "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace"

PUT /v1/threads/{thread_id}

Update a thread (e.g., rename).

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter

Request Body:

FieldTypeRequiredDescription
titlestringnoUpdated display title
metadataobjectnoUpdated metadata

Response: 200 OK — returns the updated thread.

curl example:

Terminal window
curl -X PUT "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace" \
-H "Content-Type: application/json" \
-d '{"title": "Auth debugging session"}'

GET /v1/threads/{thread_id}/full

Get thread with all messages inlined (paginated).

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter
limitinteger100Max messages to return (1-1000)
offsetinteger0Message pagination offset
orderstringascMessage order: asc or desc

Response: 200 OK

{
"thread": {
"thread_id": "thread_abc123",
"title": "Debugging session"
},
"messages": [
{
"message_id": "msg_1",
"role": "user",
"content": "Help me debug this auth issue",
"index": 0
}
],
"total_messages": 12
}

curl example:

Terminal window
curl "http://localhost:61001/v1/threads/thread_abc123/full?limit=50&order=asc"

DELETE /v1/threads/{thread_id}

Delete a thread and all its messages.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter

Response: 204 No Content

curl example:

Terminal window
curl -X DELETE "http://localhost:61001/v1/threads/thread_abc123?workspace_id=my-workspace"

POST /v1/threads/{thread_id}/messages

Append messages to a chat thread.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter

Request Body:

FieldTypeRequiredDescription
messagesobject[]yesMessages to append (minimum 1)

Each message object:

FieldTypeRequiredDefaultDescription
rolestringyes—Message role: user, assistant, system, tool
contentanyyes—Message content (string or structured content blocks)
metadataobjectno{}Arbitrary metadata

Response: 201 Created

{
"messages": [
{
"message_id": "msg_new1",
"role": "user",
"content": "What caused the auth failure?",
"index": 12
}
],
"thread_id": "thread_abc123",
"new_message_count": 13
}

curl example:

Terminal window
curl -X POST "http://localhost:61001/v1/threads/thread_abc123/messages?workspace_id=my-workspace" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "What caused the auth failure?"},
{"role": "assistant", "content": "The token was expired."}
]
}'

GET /v1/threads/{thread_id}/messages

Get messages from a chat thread with pagination.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter
limitinteger100Max messages to return (1-1000)
offsetinteger0Pagination offset
after_indexintegernullGet messages after this index
orderstringascMessage order: asc or desc

Response: 200 OK

{
"messages": [],
"thread_id": "thread_abc123",
"total_count": 12
}

curl example:

Terminal window
# Get latest messages
curl "http://localhost:61001/v1/threads/thread_abc123/messages?order=desc&limit=10"
# Get messages after index 5
curl "http://localhost:61001/v1/threads/thread_abc123/messages?after_index=5"

DELETE /v1/threads/{thread_id}/messages/{message_id}

Delete a single message from a thread without deleting the thread itself.

Path Parameters:

ParameterTypeDescription
thread_idstringThread to delete from
message_idstringMessage to delete

Response: 204 No Content


POST /v1/threads/{thread_id}/decompose

Trigger on-demand memory decomposition for unprocessed messages in a thread. Extracts memories from conversation content.

Query Parameters:

ParameterTypeDefaultDescription
workspace_idstringfrom auth contextWorkspace filter

Response: 200 OK

{
"thread_id": "thread_abc123",
"workspace_id": "my-workspace",
"messages_processed": 8,
"memories_created": 5,
"from_index": 4,
"to_index": 12
}

curl example:

Terminal window
curl -X POST "http://localhost:61001/v1/threads/thread_abc123/decompose?workspace_id=my-workspace"

Context Environment

All context endpoints require an X-Session-ID header to identify the session sandbox. The context environment provides a server-side Python sandbox for programmatic memory analysis.

POST /v1/context/execute

Execute Python code in the session sandbox. State persists across calls within the same session.

Headers: X-Session-ID (required)

Request Body:

FieldTypeRequiredDefaultDescription
codestringyes—Python code to execute
result_varstringnonullStore expression result in this variable
return_resultbooleannotrueInclude result value in response
max_return_charsintegerno10000Maximum chars for result serialization (100-100000)

Response: 200 OK

{
"output": "",
"result": "4.2",
"error": null,
"variables_changed": ["result", "total_importance"]
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/execute \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"code": "result = sum(x[\"importance\"] for x in memories)",
"result_var": "total_importance",
"return_result": true
}'

POST /v1/context/inspect

Inspect sandbox variables. Omit variable for an overview of all variables.

Headers: X-Session-ID (required)

Query Parameters:

ParameterTypeDefaultDescription
variablestringnullSpecific variable to inspect (omit for overview)
preview_charsinteger200Characters to include in value previews

Response (specific variable): 200 OK

{
"variable": "memories",
"type": "list",
"preview": "[{'id': 'mem_abc', 'content': 'User prefers...'}]",
"size_bytes": 4096
}

Response (all variables): 200 OK

{
"variable_count": 3,
"variables": {"memories": "list (50 items)", "summary": "str", "total": "float"},
"total_size_bytes": 8192
}

curl example:

Terminal window
# Overview of all variables
curl -X POST http://localhost:61001/v1/context/inspect \
-H "X-Session-ID: sess_abc123"
# Inspect specific variable
curl -X POST "http://localhost:61001/v1/context/inspect?variable=memories&preview_chars=500" \
-H "X-Session-ID: sess_abc123"

POST /v1/context/load

Load memories into the sandbox via semantic search.

Headers: X-Session-ID (required)

Request Body:

FieldTypeRequiredDefaultDescription
varstringyes—Variable name to store results in
querystringyes—Memory recall query
limitintegerno50Maximum memories to recall (1-500)
typesstring[]nonullFilter by memory types
tagsstring[]nonullFilter by tags
min_relevancefloatnonullMinimum relevance score (0.0-1.0)
include_embeddingsbooleannofalseInclude embedding vectors

Response: 200 OK

{
"count": 12,
"variable": "auth_memories",
"query": "authentication patterns",
"total_available": 25
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/load \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"var": "auth_memories",
"query": "authentication patterns",
"limit": 50,
"types": ["semantic", "procedural"]
}'

POST /v1/context/inject

Inject a value directly into the sandbox.

Headers: X-Session-ID (required)

Request Body:

FieldTypeRequiredDefaultDescription
keystringyes—Variable name
valueanyyes—Value to inject (JSON-serializable)
parse_jsonbooleannofalseParse value string as JSON

Response: 200 OK

{
"variable": "config",
"type": "dict",
"preview": "{'threshold': 0.7, 'max_items': 100}"
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/inject \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"key": "config",
"value": "{\"threshold\": 0.7, \"max_items\": 100}",
"parse_json": true
}'

POST /v1/context/query

Query the server-side LLM with sandbox variables as context.

Headers: X-Session-ID (required)

Request Body:

FieldTypeRequiredDefaultDescription
promptstringyes—Prompt for the LLM
variablesstring[]no[]Variable names to include as context
max_context_charsintegernonullMaximum chars for variable context (100-500000)
result_varstringnonullStore LLM response in this variable

Response: 200 OK

{
"response": "Based on the error memories, there are three common patterns...",
"variables_used": ["error_memories"],
"result_var": "analysis"
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/query \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"prompt": "What are the common error patterns in this data?",
"variables": ["error_memories"],
"result_var": "analysis"
}'

POST /v1/context/rlm

Run a Recursive Language Model reasoning loop. The server iteratively generates code, executes it, evaluates results, and continues until the goal is achieved or max iterations are reached.

Headers: X-Session-ID (required)

Request Body:

FieldTypeRequiredDefaultDescription
goalstringyes—Natural language description of the goal
memory_querystringnonullOptional memory query to load initial data
memory_limitintegerno100Maximum memories to load (1-500)
max_iterationsintegerno10Maximum reasoning iterations (1-50)
variablesstring[]nonullVariable names to include in context
result_varstringnonullStore final result in this variable
detail_levelstringnostandardDetail level: minimal, standard, verbose

Response: 200 OK

{
"result": "Analysis found 3 recurring error patterns...",
"iterations": 4,
"goal_achieved": true,
"trace": [
{
"iteration": 1,
"generated_code": "...",
"exec_output": "...",
"variables_changed": ["grouped_errors"],
"evaluation": "CONTINUE",
"action": "continue"
}
]
}

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/rlm \
-H "Content-Type: application/json" \
-H "X-Session-ID: sess_abc123" \
-d '{
"goal": "Identify the most common error patterns and their resolutions",
"memory_query": "errors and fixes",
"memory_limit": 100,
"max_iterations": 10,
"result_var": "findings"
}'

GET /v1/context/status

Get sandbox status for the current session.

Headers: X-Session-ID (required)

Response: 200 OK

{
"exists": true,
"variable_count": 5,
"variables": ["memories", "summary", "config"],
"total_size_bytes": 16384,
"memory_limit_bytes": 268435456,
"metadata": {
"created_at": "2026-01-15T10:30:00Z",
"exec_count": 12,
"total_operations": 20,
"last_exec_at": "2026-01-15T10:45:00Z"
}
}

curl example:

Terminal window
curl http://localhost:61001/v1/context/status \
-H "X-Session-ID: sess_abc123"

POST /v1/context/checkpoint

Checkpoint sandbox state for persistence. Fires persistence hooks for enterprise deployments.

Headers: X-Session-ID (required)

Response: 204 No Content

curl example:

Terminal window
curl -X POST http://localhost:61001/v1/context/checkpoint \
-H "X-Session-ID: sess_abc123"

DELETE /v1/context/cleanup

Remove session sandbox and free resources.

Headers: X-Session-ID (required)

Response: 204 No Content

curl example:

Terminal window
curl -X DELETE http://localhost:61001/v1/context/cleanup \
-H "X-Session-ID: sess_abc123"

Skills

Skills are named bundles (a SKILL.md manifest + arbitrary files) that LLM agents can list, fetch, and execute against. Resolution follows the 4-tier scope precedence (user > workspace > tenant > global) described in Skills & MCP Server Registry. Routes are mounted under /v1/skills.

EndpointPurpose
POST /v1/skillsCreate a skill (manifest + initial files in one request)
GET /v1/skillsList skills visible to the caller; ?include_shadowed=true to keep losers; `?scope=user
POST /v1/skills/resolveResolve a name (or list of names) to precedence-winning skills
GET /v1/skills/{skill_id}Get one skill (metadata)
GET /v1/skills/{skill_id}/manifestGet just the SKILL.md content
GET /v1/skills/{skill_id}/filesList all files in the bundle
GET /v1/skills/{skill_id}/bundleStream the full bundle as a single payload
GET /v1/skills/{skill_id}/files/{file_path:path}Fetch a single file by path
PUT /v1/skills/{skill_id}Update metadata (manifest, scope, etc.)
PUT /v1/skills/{skill_id}/files/{file_path:path}Upsert one file (idempotent)
DELETE /v1/skills/{skill_id}Delete a skill
POST /v1/skills/{skill_id}/syncTwo-way sync against a client-provided manifest+files snapshot (used by memorylayer skills sync / watch)

Skill records carry id, name, version, workspace_id, user_id (when LOCAL/USER-scoped), source_mode (server / mirrored / filesystem), manifest, description, created_at, updated_at. The MCP server exposes skills_list, skills_get, skills_get_file, skills_search (cc profile) and skills_save (full profile) on top of these endpoints.


MCP Server Registry

Workspace-scoped registry of MCP server entries (the same shape as .mcp.json / Claude Code’s ~/.claude.json). Resolution uses the 4-tier scope precedence LOCAL > PROJECT > USER > GLOBAL. Routes are mounted under /v1/mcp-servers.

EndpointPurpose
POST /v1/mcp-serversCreate an entry
GET /v1/mcp-serversList entries (?include_shadowed, ?scope); pulls precedence winners by default
POST /v1/mcp-servers/resolveResolve names; returns the winning entry per name including decrypted env (if authorized)
POST /v1/mcp-servers/importBulk import from a Claude Code or .mcp.json blob
GET /v1/mcp-servers/exportExport the workspace’s entries to .mcp.json shape (?reveal_secrets=true to include decrypted env values)
GET /v1/mcp-servers/{server_id}Get one entry
PUT /v1/mcp-servers/{server_id}Update an entry
DELETE /v1/mcp-servers/{server_id}Delete an entry
POST /v1/mcp-servers/{server_id}/syncTwo-way sync against a client-provided snapshot

Entries carry id, name, transport (stdio / http / sse / streamable-http), command, args, env (encrypted at rest), headers, workspace_id, user_id, source_mode, enabled. The MCP server exposes mcp_servers_list/get/save/delete/import in the full profile.


Documents

Document ingestion (upload, parse, derive memories, page-level retrieval). All endpoints live under /v1/documents.

EndpointPurpose
POST /v1/documentsUpload a document via multipart/form-data. Form fields: file (the binary), target_context_id, importance, tags, metadata, extraction_options, retain_original
GET /v1/documentsList documents; supports status, document_type, limit, offset query params
GET /v1/documents/jobsList ingestion jobs; ?status filter, paginated
GET /v1/documents/jobs/{job_id}Get a single ingestion job with progress + error info
POST /v1/documents/jobs/{job_id}/cancelCancel a running ingestion job
POST /v1/documents/searchColPali MaxSim page search (see Document Ingestion -> Search Document Pages)
GET /v1/documents/{document_id}Get a single document with status, page count, derived memory IDs
GET /v1/documents/{document_id}/memoriesGet the memories extracted from a document
GET /v1/documents/{document_id}/pagesList pages (page_no, transcript, transcript_model)
GET /v1/documents/{document_id}/pages/{page_id}Get a single page
POST /v1/documents/{document_id}/reprocessRe-run extraction with optional new extraction_options (creates a new ingestion job)
DELETE /v1/documents/{document_id}Delete a document; ?delete_memories=true to cascade to derived memories

Page search request body (POST /v1/documents/search):

FieldTypeRequiredDefaultDescription
querystringyes—Natural-language search query
limitintegerno10Max results (1-100)
doc_idsstring[]no—Restrict search to specific document IDs

Returns PageSearchResponse with pages: DocumentPageResponse[] (each carrying a relevance_score), total_count, and the original query. The OSS SQLite backend scores in Python after a filtered fetch; the Enterprise PostgreSQL backend pushes MaxSim into the database. Returns 501 if the active storage backend does not implement search_pages_by_maxsim.


Data Providers

Registry / metadata surface for external ingestion sources. The OSS server only ships the local connector type and POST /v1/data-providers/{provider_id}/sync is a no-op there — see Data Providers and the enterprise connector pack for the full picture. Routes live under /v1/data-providers.

EndpointPurpose
POST /v1/data-providersCreate a provider record (name, provider_type, connection_args, encrypted_args, schedule, metadata)
GET /v1/data-providersList providers in the workspace; ?limit, ?offset
GET /v1/data-providers/{provider_id}Get one provider (encrypted_args is never returned in the response)
PUT /v1/data-providers/{provider_id}Update fields (partial — only provided fields are touched)
DELETE /v1/data-providers/{provider_id}Delete the provider (does not affect previously-ingested documents)
POST /v1/data-providers/{provider_id}/syncTrigger a one-off sync. OSS: no-op, returns empty list. Enterprise: invokes the connector to discover and queue new/updated documents

Knowledgebase

Knowledgebase generation, article browsing, and graph community export. Endpoints under /v1/knowledgebase.

EndpointPurpose
POST /v1/knowledgebase/generateTrigger knowledgebase generation for the workspace (sync or async); body accepts context_id, since, force, etc.
GET /v1/knowledgebaseGet the workspace knowledgebase index / metadata
GET /v1/knowledgebase/articlesList articles (paginated)
GET /v1/knowledgebase/articles/{article_id:path}Get an article by path (path-style IDs supported)
GET /v1/knowledgebase/exportExport the workspace knowledgebase as JSON
GET /v1/knowledgebase/graphGet the knowledgebase graph (supports include_rpg=true to merge in RPG nodes; see Repository Planning Graph)
GET /v1/knowledgebase/graph/communities/{community_id}Drill into a specific graph community (cluster of related memories)

Knowledgebase articles are LLM-synthesized topic summaries assembled from clusters of related memories.


Graph Analysis

Workspace-wide graph analysis primitives. Endpoints under /v1/graph.

EndpointPurpose
GET /v1/graph/snapshotMaterialized workspace graph snapshot (nodes + edges). Supports context_id, include_rpg, node_types, relationship_types
GET /v1/graph/communitiesDetected communities (Louvain / Leiden); ?algorithm, ?resolution, ?min_size
GET /v1/graph/centralityPer-node centrality scores (betweenness, degree, eigenvector, pagerank)
GET /v1/graph/bridgesBridge nodes / edges (high-betweenness connectors between communities)
GET /v1/graph/statsAggregate stats: node/edge counts, density, average degree, connected components
POST /v1/graph/analyzeRun a composite analysis pass; body controls which subreports to include and applies include_rpg, filters, etc.

The include_rpg query/body flag pulls Repository Planning Graph nodes into the snapshot when a Forge-equipped deployment has populated them.


Audit

Audit log surfacing. The audit service is OSS-pluggable; in the OSS default no audit events are emitted, so these endpoints return empty results unless a custom audit plugin is configured (enterprise ships a backed implementation). Routes live under /v1/audit.

EndpointPurpose
GET /v1/audit/eventsList audit events; supports workspace_id, actor_id, resource_type, action, since, until, limit, offset
GET /v1/audit/events/summaryAggregated counts grouped by resource_type / action / actor_id over a time window

Each event record carries id, tenant_id, workspace_id, actor_id, resource_type, resource_id, action, metadata, created_at.


Tokens

API token issuance and revocation. Routes live under /v1/tokens. In the OSS server the tokens plugin ships disabled by default (is_enabled=False); when enabled, it proxies to the Aether gRPC token service rather than minting tokens locally. See Server -> Aether Transport for the rationale and Administration -> API Keys for the enterprise-facing semantics.

EndpointPurpose
GET /v1/tokensList tokens visible to the caller (paginated)
POST /v1/tokensCreate a new token (name, principal_type, workspace_patterns, scopes, expires_in_days); returns the secret once at creation time
GET /v1/tokens/{token_id}Get token metadata (never returns the secret)
DELETE /v1/tokens/{token_id}Delete a token (hard remove)
POST /v1/tokens/{token_id}/revokeRevoke without deleting (audit-preserving)

Calls return 503 Service Unavailable when the plugin is disabled and no Aether connection is configured.


Health

GET /health

Health check endpoint.

Response: 200 OK

curl example:

Terminal window
curl http://localhost:61001/health

GET /health/ready

Readiness check with service status.

Response: 200 OK

curl example:

Terminal window
curl http://localhost:61001/health/ready