REST API Reference
Base URL: http://localhost:8010
OpenAPI schema: GET /openapi.json
Interactive UI: GET /docs
All business endpoints are versioned under /v1/. Unversioned paths that match known prefixes (/nodes, /edges, /search, etc.) receive a 301 redirect to the /v1/ equivalent.
Authentication
All business endpoints require Authorization: Bearer <token>.
Login
http
POST /auth/login
Content-Type: application/json
{ "username": "admin", "password": "secret" }json
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600
}Refresh token
http
POST /auth/refresh
Content-Type: application/json
{ "refresh_token": "eyJ..." }Logout
http
POST /auth/logout
Authorization: Bearer <token>Current user
http
GET /auth/me
Authorization: Bearer <token>Change password
http
POST /auth/change-password
Authorization: Bearer <token>
Content-Type: application/json
{ "current_password": "old", "new_password": "new" }Nodes
Create node
http
POST /v1/nodes
Content-Type: application/json
{
"node_id": "person_001",
"labels": ["Person"],
"properties": { "name": "Alice", "age": 30 },
"embedding": [0.1, 0.2, ...],
"tenant_id": "acme"
}Response 201
json
{
"node_id": "person_001",
"labels": ["Person"],
"properties": { "name": "Alice", "age": 30 },
"created_at": "2026-03-05T10:00:00Z"
}Get node
http
GET /v1/nodes/{node_id}?tenant_id=acmeUpdate node
http
PATCH /v1/nodes/{node_id}
Content-Type: application/json
{
"properties": { "age": 31 },
"labels": ["Person", "Employee"]
}Delete node
http
DELETE /v1/nodes/{node_id}?tenant_id=acmeList nodes
http
GET /v1/nodes?label=Person&limit=100&offset=0&tenant_id=acmeResponse 200
json
{ "nodes": [...], "total": 42 }Bulk create nodes
http
POST /v1/nodes/bulk
Content-Type: application/json
{
"nodes": [
{ "node_id": "p1", "labels": ["Person"], "properties": { "name": "Bob" } },
{ "node_id": "p2", "labels": ["Person"], "properties": { "name": "Carol" } }
],
"tenant_id": "acme"
}Response 200
json
{ "created": 2, "failed": 0 }Edges
Create edge
http
POST /v1/edges
Content-Type: application/json
{
"edge_id": "knows_001",
"edge_type": "KNOWS",
"source_id": "person_001",
"target_id": "person_002",
"properties": { "since": "2024-01-01" }
}Get edge
http
GET /v1/edges/{edge_id}Update edge
http
PATCH /v1/edges/{edge_id}
Content-Type: application/json
{ "properties": { "weight": 0.9 } }Delete edge
http
DELETE /v1/edges/{edge_id}Batch existence check
http
POST /v1/edges/exists
Content-Type: application/json
{
"pairs": [
{ "source_id": "p1", "edge_type": "KNOWS", "target_id": "p2" }
]
}Search
Vector similarity search
http
POST /v1/search/vector
Content-Type: application/json
{
"query_embedding": [0.1, 0.2, ...],
"top_k": 10,
"label_filter": "Person",
"tenant_id": "acme"
}Response 200
json
{
"results": [
{ "node": { "node_id": "p1", ... }, "score": 0.98, "distance": 0.02 }
]
}Hybrid search (vector + graph)
http
POST /v1/search/hybrid
Content-Type: application/json
{
"query_embedding": [0.1, 0.2, ...],
"edge_type": "KNOWS",
"depth": 2,
"top_k": 10
}Graph traversal
http
POST /v1/traverse
Content-Type: application/json
{
"start_node_id": "person_001",
"edge_type": "KNOWS",
"depth": 3,
"direction": "outbound"
}Response 200
json
{
"nodes": [...],
"edges": [...],
"paths": [{ "nodes": [...], "edges": [...] }]
}Cypher query
http
POST /v1/query
Content-Type: application/json
{
"query": "MATCH (n:Person)-[:KNOWS]->(m) WHERE n.node_id = $id RETURN m",
"parameters": { "id": "person_001" }
}Response 200
json
{ "results": [...], "columns": ["m"], "stats": { "rows": 3 } }Journeys
Start a journey
http
POST /v1/journeys
Content-Type: application/json
{
"journey_type": "onboarding",
"entity_id": "user_42",
"metadata": { "referrer": "signup-page" }
}Get journey instance
http
GET /v1/journeys/{instance_id}Advance journey stage
http
POST /v1/journeys/{instance_id}/advance
Content-Type: application/json
{ "to_stage": "email_verified", "actor": "system", "notes": "OTP confirmed" }Cancel journey
http
POST /v1/journeys/{instance_id}/cancel
Content-Type: application/json
{ "actor": "admin", "reason": "user request" }Journey audit trail
http
GET /v1/journeys/{instance_id}/auditList journeys
http
GET /v1/journeys?journey_type=onboarding&status=active&limit=50&offset=0KMS admin
Requires
ADMINpermission.
| Method | Path | Description |
|---|---|---|
GET | /admin/kms/status | Active provider, sealed/initialized, key count |
GET | /admin/kms/keys | List all key IDs |
GET | /admin/kms/keys/{key_id} | Describe a key |
POST | /admin/kms/keys/{key_id}/rotate | Trigger key rotation |
POST | /admin/kms/keys/{key_id}/disable | Disable key |
POST | /admin/kms/keys/{key_id}/enable | Re-enable key |
Health & metrics
http
GET /health/live # liveness probe (always 200 if process is up)
GET /health/ready # readiness probe (200 after DB init completes)
GET /metrics # Prometheus text/plain metricsError responses
All errors return:
json
{ "detail": "Human-readable error message" }| Status | Meaning |
|---|---|
400 | Bad request / validation error |
401 | Missing or invalid token |
403 | Insufficient permissions |
404 | Resource not found |
409 | Conflict (e.g. duplicate node ID) |
429 | Rate limit exceeded — Retry-After header included |
500 | Internal server error |