API and OpenAPI specification

The Neotoma REST API is defined in the OpenAPI spec. The table below lists each endpoint and the capability it provides.

The API is designed around deterministic state operations: store structured observations, retrieve snapshots with provenance, and manage typed relationships explicitly.

Base URL

  • Development: http://localhost:3080
  • Production: http://localhost:3180 (local) or your deployed host

Authentication

All endpoints except /health and /openapi.yaml require a Bearer token:

Authorization: Bearer <NEOTOMA_BEARER_TOKEN>
  • Set via NEOTOMA_BEARER_TOKEN environment variable
  • When encryption is enabled, use the key-derived MCP token instead: neotoma auth mcp-token
  • MCP OAuth endpoints (/mcp/oauth/*) have their own auth flow - see the MCP reference

Request examples

# Store structured entities
curl -X POST http://localhost:3080/store \
  -H "Authorization: Bearer $NEOTOMA_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entities":[{"entity_type":"task","title":"Review schema changes","status":"open"}]}'

# Query entities
curl -X POST http://localhost:3080/entities/query \
  -H "Authorization: Bearer $NEOTOMA_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"filters":{"entity_type":"task"},"limit":10}'

# Retrieve snapshot with provenance
curl -X POST http://localhost:3080/get_entity_snapshot \
  -H "Authorization: Bearer $NEOTOMA_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id":"<entity_id>"}'

# Upload a file
curl -X POST http://localhost:3080/upload_file \
  -H "Authorization: Bearer $NEOTOMA_BEARER_TOKEN" \
  -F "file=@document.pdf"

# Health check (no auth required)
curl http://localhost:3080/health
MethodEndpointDescriptionParameters
GET/meGet the current user.
POST/mcp/oauth/initiateInitiate the OAuth flow.body: auth_provider, redirect_uri
GET/mcp/oauth/authorizeHandle the OAuth authorize redirect.query: code, state
POST/mcp/oauth/tokenExchange the OAuth code for a token.body: code, code_verifier
GET/mcp/oauth/statusGet OAuth connection status.
GET/mcp/oauth/connectionsList OAuth connections.
DELETE/mcp/oauth/connections/{id}Remove an OAuth connection.path: id
POST/entities/queryQuery entities with filters.body: filters, limit, offset
GET/entities/{id}Get an entity by ID.path: id
POST/get_entity_snapshotGet an entity snapshot with provenance.body: entity_id, at?
GET/entities/{id}/observationsList observations for an entity.path: id
POST/list_observationsList observations by query.body: filters
POST/get_field_provenanceGet provenance for a field.body: entity_id, field
GET/entities/{id}/relationshipsList relationships for an entity.path: id
POST/list_relationshipsList relationships by query.body: filters
POST/retrieve_entity_by_identifierSearch for an entity by identifier or semantic.body: identifier, entity_type?
POST/retrieve_related_entitiesRetrieve related entities.body: entity_id, relationship_types?, depth?
POST/retrieve_graph_neighborhoodRetrieve the graph neighborhood.body: node_id, node_type
POST/entities/mergeMerge two entities.body: source_entity_id, target_entity_id
POST/delete_entityDelete an entity.body: entity_id
POST/restore_entityRestore an entity.body: entity_id
GET/sourcesList sources.query: limit?, offset?
GET/sources/{id}Get a source by ID.path: id
GET/observationsList observations.query: limit?, offset?
POST/observations/queryQuery observations.body: filters
POST/observations/createCreate an observation.body: entity_id, fields
GET/relationshipsList relationships.query: limit?, offset?
GET/relationships/{id}Get a relationship by ID.path: id
POST/relationships/snapshotGet a relationship snapshot.body: relationship_key or ids
POST/create_relationshipCreate a relationship.body: relationship_type, source_entity_id, target_entity_id
POST/delete_relationshipDelete a relationship.body: relationship_key
POST/restore_relationshipRestore a relationship.body: relationship_key
GET/timelineList timeline events.query: type?, from?, to?
GET/timeline/{id}Get a timeline event by ID.path: id
GET/schemasList schema types.
GET/schemas/{entity_type}Get a schema for an entity type.path: entity_type
POST/analyze_schema_candidatesAnalyze schema candidates.body: entity_type, entity_id?
POST/get_schema_recommendationsGet schema recommendations.body: entity_type
POST/update_schema_incrementalUpdate a schema incrementally.body: entity_type, new_fields
POST/register_schemaRegister a schema.body: schema
POST/storeStore structured entities.body: entities, idempotency_key?, relationships?
POST/store/unstructuredStore an unstructured file.body: file_path or file_content, mime_type
POST/correctSubmit a correction.body: entity_id, field, value
POST/reinterpretReinterpret a source.body: source_id
GET/interpretationsList interpretations.query: limit?, offset?
GET/statsGet server stats.
GET/server-infoGet server info.
POST/health_check_snapshotsRun health check snapshots.
GET/get_file_url (internal path)Get a signed file URL (internal).query: path
Parse a file into agent-readable text without storing.-
Check for a newer npm package version.-
GET/healthCheck if server is running.
GET/openapi.yamlGet OpenAPI spec for API documentation.
Initialize Neotoma (data dirs, DB, encryption, .env).-
Reset local Neotoma state to clean slate.-
Start, stop, or manage the API server.-
Configure or check MCP server entries in IDE configs.-
Check or install CLI agent instructions for IDEs.-
Stream record changes in real time.-
Show or change storage paths and merge databases.-
Create or restore a backup.-
Read persistent log files.-
Interactive session with persistent prompt.-
Run npm scripts from the repo.-
Interpret uninterpreted sources (backfill).-
Log out or get MCP auth token.-

Error responses

All errors use a structured envelope:

{
  "error_code": "INGESTION_FILE_TOO_LARGE",
  "message": "File exceeds maximum size of 50MB",
  "details": { "file_size": 52428800, "max_size": 52428800 },
  "trace_id": "trace-uuid",
  "timestamp": "2024-01-01T12:00:00Z"
}

Standard HTTP status codes: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 413 Payload Too Large, 429 Rate Limited, 500 Internal Server Error, 503 Service Unavailable. Check error_code for programmatic handling, not just the HTTP status.

Pagination

List endpoints accept limit and offset parameters. Use include_total_count: true when building pagination UI. Recommended: keep limit at 100 or below for performance.

{
  "filters": { "entity_type": "task" },
  "limit": 20,
  "offset": 0,
  "include_total_count": true
}

File operations

Upload files via POST /upload_file (multipart/form-data) or the unified POST /store with structured entities. File size limit: 50 MB. Retrieve signed URLs via GET /get_file_url?file_path=... (default expiry: 1 hour).

Continue with MCP reference, CLI reference, schema management, and architecture.