Skip to content

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=acme

Update 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=acme

List nodes

http
GET /v1/nodes?label=Person&limit=100&offset=0&tenant_id=acme

Response 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" }
  ]
}

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}/audit

List journeys

http
GET /v1/journeys?journey_type=onboarding&status=active&limit=50&offset=0

KMS admin

Requires ADMIN permission.

MethodPathDescription
GET/admin/kms/statusActive provider, sealed/initialized, key count
GET/admin/kms/keysList all key IDs
GET/admin/kms/keys/{key_id}Describe a key
POST/admin/kms/keys/{key_id}/rotateTrigger key rotation
POST/admin/kms/keys/{key_id}/disableDisable key
POST/admin/kms/keys/{key_id}/enableRe-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 metrics

Error responses

All errors return:

json
{ "detail": "Human-readable error message" }
StatusMeaning
400Bad request / validation error
401Missing or invalid token
403Insufficient permissions
404Resource not found
409Conflict (e.g. duplicate node ID)
429Rate limit exceeded — Retry-After header included
500Internal server error

Purple8 Graph is proprietary software. All rights reserved.