---
title: API Complete Reference
description: **Version**: 1.0.0 **Base URL**: `http://localhost:9090/api` **WebSocket**: `ws://localhost:9090/ws`
type: reference
status: stable
---
Version: 1.0.0
Base URL: http://localhost:9090/api
WebSocket: ws://localhost:9090/ws
Last Updated: 2025-11-04
Status: Production Reference
- REST API Reference
- Request/Response Formats
- Error Responses
- Rate Limiting
- Pagination
- Bulk Operations
- Webhooks
- API Versioning
- Examples
VisionFlow supports three authentication methods:
- JWT Tokens (Session-based)
- API Keys (Programmatic access)
- OAuth 2.0 (Third-party integrations)
Login Endpoint: POST /api/auth/login
Request:
{
"email": "user@example.com",
"password": "password123"
}Response (200 OK):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 86400,
"user": {
"id": "uuid-123",
"email": "user@example.com",
"role": "user",
"permissions": ["read:graph", "write:graph"]
}
}
}Token Usage:
curl -H "Authorization: Bearer YOUR-JWT-TOKEN" \
http://localhost:9090/api/graph/dataToken Expiration:
- Access tokens: 24 hours
- Refresh tokens: 30 days
- Sliding expiration on activity
Endpoint: POST /api/auth/refresh
Request:
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Response (200 OK):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 86400
}
}Generate API Key: POST /api/auth/api-keys
Request:
{
"name": "Production API Key",
"scopes": ["read:graph", "write:graph", "read:ontology"],
"expiresIn": 31536000
}Response (201 Created):
{
"success": true,
"data": {
"id": "key-uuid-123",
"key": "vf_live_a1b2c3d4e5f6g7h8i9j0",
"name": "Production API Key",
"scopes": ["read:graph", "write:graph", "read:ontology"],
"createdAt": "2025-11-04T12:00:00Z",
"expiresAt": "2026-11-04T12:00:00Z"
}
}API Key Usage:
curl -H "X-API-Key: vf_live_a1b2c3d4e5f6g7h8i9j0" \
http://localhost:9090/api/graph/dataAPI Key Management:
- List keys:
GET /api/auth/api-keys - Revoke key:
DELETE /api/auth/api-keys/:id - Rotate key:
POST /api/auth/api-keys/:id/rotate
Supported Providers:
- GitHub
- Microsoft
Authorization Flow:
-
Initiate OAuth:
GET /api/auth/oauth/:providerGET /api/auth/oauth/github?redirect_uri=https://myapp.com/callback -
Callback:
GET /api/auth/oauth/:provider/callback- Receives authorization code
- Exchanges for access token
- Returns JWT
-
Use JWT: Include in Authorization header
| Scope | Description |
|---|---|
read:graph |
Read graph data and metadata |
write:graph |
Create/update/delete nodes and edges |
read:ontology |
Read ontology classes and properties |
write:ontology |
Load and validate ontologies |
admin:physics |
Control physics simulation |
admin:system |
System administration |
read:analytics |
Access analytics endpoints |
write:workspace |
Manage workspaces |
GET /api/health
Returns system health status.
Response (200 OK):
{
"status": "ok",
"version": "0.1.0",
"timestamp": "2025-11-04T12:00:00Z",
"services": {
"database": "healthy",
"physics": "running",
"gpu": "available"
}
}GET /api/config
Returns complete application configuration.
Response (200 OK):
{
"version": "0.1.0",
"features": {
"ragflow": true,
"perplexity": false,
"openai": true,
"whisper": true
},
"websocket": {
"minUpdateRate": 16,
"maxUpdateRate": 60,
"motionThreshold": 0.001,
"motionDamping": 0.95
},
"rendering": {
"ambientLightIntensity": 0.5,
"enableAmbientOcclusion": true,
"backgroundColor": "#1a1a1a"
},
"xr": {
"enabled": true,
"roomScale": 5.0,
"spaceType": "unbounded"
}
}GET /api/graph/data
Returns complete graph with nodes, edges, physics positions, and metadata.
Query Parameters:
format(optional): Response format (json|graphml|cytoscape)include-metadata(optional): Include full metadata (default:true)include-positions(optional): Include physics positions (default:true)
Response (200 OK):
{
"nodes": [
{
"id": 1,
"metadataId": "node-uuid-123",
"label": "Example Node",
"position": {"x": 0.0, "y": 0.0, "z": 0.0},
"velocity": {"x": 0.0, "y": 0.0, "z": 0.0},
"metadata": {
"owl-class-iri": "http://example.org/Class",
"file-source": "example.md"
},
"type": "concept",
"size": 1.0,
"color": "#3498db",
"weight": 1.0,
"group": "category1"
}
],
"edges": [
{
"source": 1,
"target": 2,
"relationshipType": "related-to",
"weight": 1.0,
"metadata": {}
}
],
"metadata": {
"node-uuid-123": {
"id": "node-uuid-123",
"fileName": "example.md",
"title": "Example",
"sha1": "abc123",
"properties": {}
}
},
"settlementState": {
"isSettled": false,
"stableFrameCount": 45,
"kineticEnergy": 12.5
},
"statistics": {
"nodeCount": 150,
"edgeCount": 320,
"density": 0.028
}
}cURL Example:
curl -H "Authorization: Bearer YOUR-JWT" \
"http://localhost:9090/api/graph/data?format=json&include-metadata=true"GET /api/graph/data/paginated
Returns paginated graph data for large graphs.
Query Parameters:
page(required): Page number (1-indexed)page-size(optional): Items per page (default: 100, max: 1000)sort-by(optional): Sort field (id|label|weight)sort-order(optional): Sort direction (asc|desc)
Response (200 OK):
{
"nodes": [...],
"edges": [...],
"metadata": {...},
"pagination": {
"currentPage": 1,
"totalPages": 10,
"pageSize": 100,
"totalItems": 1000,
"hasNext": true,
"hasPrevious": false
}
}cURL Example:
curl "http://localhost:9090/api/graph/data/paginated?page=1&page-size=50&sort-by=label"POST /api/graph/update
Triggers graph update by fetching new files from GitHub.
Request Body (optional):
{
"forceFull": false,
"filterPaths": ["docs/", "concepts/"],
"maxFiles": 100
}Response (200 OK):
{
"success": true,
"message": "Graph updated with 5 new files",
"data": {
"filesProcessed": 5,
"nodesCreated": 12,
"edgesCreated": 8,
"duration": "2.5s"
}
}POST /api/graph/refresh
Returns current graph state without modification.
Response (200 OK):
{
"success": true,
"message": "Graph data retrieved successfully",
"data": {
"nodes": [...],
"edges": [...],
"metadata": {...}
}
}GET /api/ontology/hierarchy
Returns complete class hierarchy.
Query Parameters:
ontology-id(optional): Specific ontology (default: "default")max-depth(optional): Maximum traversal depthinclude-annotations(optional): Include class annotations
Response (200 OK):
{
"rootClasses": [
"http://example.org/Person"
],
"hierarchy": {
"http://example.org/Person": {
"iri": "http://example.org/Person",
"label": "Person",
"parentIri": null,
"childrenIris": [
"http://example.org/Student"
],
"nodeCount": 5,
"depth": 0,
"annotations": {
"rdfs:comment": "A human being",
"dc:creator": "System"
}
}
}
}POST /api/ontology/load
Loads ontology from file, URL, or inline content.
Request Body:
{
"source": "https://example.org/ontology.owl",
"format": "rdf/xml",
"validateImmediately": true,
"options": {
"enableReasoning": true,
"enableInference": true,
"maxInferenceDepth": 5
}
}Supported Formats:
rdf/xml- RDF/XML formatturtle- Turtle formatjson-ld- JSON-LD formatowl/xml- OWL/XML formatfunctional- OWL Functional Syntax
Response (201 Created):
{
"ontologyId": "ont-uuid-123",
"loadedAt": "2025-11-04T12:00:00Z",
"axiomCount": 150,
"classCount": 45,
"propertyCount": 30,
"loadingTimeMs": 450,
"validationJobId": "job-uuid-456"
}POST /api/ontology/validate
Triggers ontology validation.
Request Body:
{
"ontologyId": "ont-123",
"mode": "full",
"priority": 5,
"enableWebsocketUpdates": true,
"clientId": "client-abc",
"options": {
"validateCardinality": true,
"validateDomainsRanges": true,
"validateDisjointClasses": true,
"reasoningTimeout": 60
}
}Validation Modes:
quick: Structural checks only (5-10 seconds)full: Complete validation with reasoning (30-60 seconds)incremental: Only validates changes (5-15 seconds)
Response (202 Accepted):
{
"jobId": "job-uuid-789",
"status": "queued",
"estimatedCompletion": "2025-11-04T12:01:00Z",
"queuePosition": 1,
"websocketUrl": "/api/ontology/ws?client-id=client-abc"
}GET /api/ontology/reports/:id
Retrieves validation report.
Path Parameters:
id: Report ID
Response (200 OK):
{
"id": "report-123",
"ontologyId": "ont-123",
"timestamp": "2025-11-04T12:00:30Z",
"status": "completed",
"duration": "15.5s",
"violations": [
{
"type": "cardinality",
"severity": "error",
"message": "Person class violates cardinality constraint",
"location": "http://example.org/Person",
"details": {
"property": "hasAge",
"expected": "exactly 1",
"found": "0"
}
}
],
"inferredTriples": [
{
"subject": "http://example.org/john",
"predicate": "rdf:type",
"object": "http://example.org/Agent"
}
],
"statistics": {
"totalClasses": 50,
"totalProperties": 30,
"totalIndividuals": 100,
"totalViolations": 2,
"errorCount": 1,
"warningCount": 1
}
}POST /api/physics/start
Starts physics simulation.
Request Body (optional):
{
"parameters": {
"gravity": 0.1,
"charge": -30.0,
"linkStrength": 0.5,
"friction": 0.9
}
}Response (200 OK):
{
"status": "running",
"timestamp": "2025-11-04T12:00:00Z",
"parameters": {
"gravity": 0.1,
"charge": -30.0
}
}GET /api/physics/status
Returns simulation status.
Response (200 OK):
{
"isRunning": true,
"isSettled": false,
"stableFrameCount": 45,
"kineticEnergy": 12.5,
"fps": 60,
"nodeCount": 150,
"parameters": {
"gravity": 0.1,
"charge": -30.0,
"linkStrength": 0.5
}
}All POST/PUT requests should use JSON:
Headers:
Content-Type: application/json
Authorization: Bearer YOUR-JWT-TOKEN
Accept: application/json
Body:
{
"field1": "value1",
"field2": "value2"
}All responses follow this structure:
Success Response:
{
"success": true,
"data": {
// Response data
},
"meta": {
"timestamp": "2025-11-04T12:00:00Z",
"requestId": "req-uuid-123"
}
}Error Response:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"message": "Email is required"
}
]
},
"meta": {
"timestamp": "2025-11-04T12:00:00Z",
"requestId": "req-uuid-123"
}
}All endpoints validate requests against JSON schemas.
Example Schema (Node Creation):
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"label": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"type": {
"type": "string",
"enum": ["concept", "entity", "relationship"]
},
"position": {
"type": "object",
"properties": {
"x": {"type": "number"},
"y": {"type": "number"},
"z": {"type": "number"}
},
"required": ["x", "y", "z"]
}
},
"required": ["label", "type"]
}Format: [SYSTEM]-[SEVERITY]-[NUMBER]
Systems:
AP: API/Application LayerDB: Database LayerGR: Graph/Ontology ReasoningGP: GPU/Physics ComputingWS: WebSocket/NetworkAU: Authentication/AuthorizationST: Storage/File Management
Severity Levels:
E: Error (recoverable)F: Fatal (requires restart)W: Warning (degraded performance)I: Info (informational)
| Code | HTTP Status | Message | Resolution |
|---|---|---|---|
AP-E-001 |
400 | Invalid Request Format | Verify JSON syntax |
AP-E-002 |
400 | Missing Required Field | Add missing field |
AP-E-101 |
401 | Missing Auth Token | Provide JWT token |
AP-E-102 |
401 | Invalid Token | Refresh token |
AP-E-104 |
403 | Insufficient Permissions | Request elevated permissions |
AP-E-201 |
404 | Resource Not Found | Verify resource ID |
AP-E-305 |
429 | Rate Limit Exceeded | Slow down requests |
DB-E-001 |
503 | Connection Failed | Check database connectivity |
GR-E-102 |
400 | Inconsistent Ontology | Fix logical contradictions |
GP-E-001 |
503 | No GPU Found | Use CPU fallback |
Validation Error (400):
{
"success": false,
"error": {
"code": "AP-E-002",
"message": "Missing required field 'label'",
"details": [
{
"field": "label",
"constraint": "required",
"message": "Label field is required"
}
]
},
"meta": {
"timestamp": "2025-11-04T12:00:00Z",
"requestId": "req-uuid-123"
}
}Authentication Error (401):
{
"success": false,
"error": {
"code": "AP-E-101",
"message": "Authorization header missing",
"details": {
"expectedHeader": "Authorization: Bearer <token>"
}
},
"meta": {
"timestamp": "2025-11-04T12:00:00Z"
}
}Rate Limit Error (429):
{
"success": false,
"error": {
"code": "AP-E-305",
"message": "Rate limit exceeded, retry after 60s",
"details": {
"limit": 100,
"used": 100,
"reset": "2025-11-04T12:01:00Z"
}
},
"meta": {
"timestamp": "2025-11-04T12:00:00Z"
}
}| User Type | Requests/Minute | Requests/Hour | Requests/Day |
|---|---|---|---|
| Anonymous | 20 | 100 | 500 |
| Authenticated | 100 | 1000 | 10000 |
| Premium | 500 | 5000 | 50000 |
| Enterprise | Unlimited | Unlimited | Unlimited |
All responses include rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1730736000
X-RateLimit-Policy: per-user
When rate limited, use exponential backoff:
Algorithm:
def retry_with_backoff(request_func, max_retries=5):
for attempt in range(max_retries):
response = request_func()
if response.status == 429:
reset_time = response.headers['X-RateLimit-Reset']
wait_seconds = min(2 ** attempt, reset_time - time.now())
time.sleep(wait_seconds)
else:
return response
raise RateLimitException()For large datasets (>1000 items):
Request:
GET /api/graph/nodes?cursor=eyJpZCI6MTIzfQ&limit=50
Response:
{
"data": [...],
"pagination": {
"cursor": "eyJpZCI6MTczfQ",
"hasNext": true,
"limit": 50
}
}For smaller datasets:
Request:
GET /api/graph/nodes?page=2&page-size=25
Response:
{
"data": [...],
"pagination": {
"currentPage": 2,
"totalPages": 10,
"pageSize": 25,
"totalItems": 250,
"hasNext": true,
"hasPrevious": true
}
}Query Parameters:
sort-by: Field to sort bysort-order:ascordesc
Example:
GET /api/graph/nodes?sort-by=label&sort-order=asc
| Operator | Description | Example |
|---|---|---|
eq |
Equals | ?type[eq]=concept |
ne |
Not equals | ?type[ne]=relationship |
gt |
Greater than | ?weight[gt]=0.5 |
gte |
Greater or equal | ?weight[gte]=0.5 |
lt |
Less than | ?weight[lt]=2.0 |
lte |
Less or equal | ?weight[lte]=2.0 |
in |
In array | ?type[in]=concept,entity |
nin |
Not in array | ?type[nin]=relationship |
contains |
String contains | ?label[contains]=test |
startsWith |
String starts with | ?label[startsWith]=node |
Example: Find all concept nodes with weight > 0.5:
GET /api/graph/nodes?type[eq]=concept&weight[gt]=0.5
Endpoint: GET /api/graph/search
Query Parameters:
q: Search queryfields: Fields to search (comma-separated)fuzzy: Enable fuzzy matching
Example:
curl "http://localhost:9090/api/graph/search?q=quantum&fields=label,description&fuzzy=true"Response:
{
"results": [
{
"id": 123,
"label": "Quantum Computing",
"score": 0.95,
"highlights": {
"label": "<em>Quantum</em> Computing"
}
}
],
"total": 5,
"took": "12ms"
}POST /api/graph/nodes/batch
Request:
{
"nodes": [
{
"label": "Node 1",
"type": "concept",
"position": {"x": 0, "y": 0, "z": 0}
},
{
"label": "Node 2",
"type": "entity",
"position": {"x": 1, "y": 0, "z": 0}
}
]
}Response:
{
"success": true,
"data": {
"created": 2,
"failed": 0,
"results": [
{"id": 1, "status": "created"},
{"id": 2, "status": "created"}
]
}
}PUT /api/graph/nodes/batch
Request:
{
"updates": [
{"id": 1, "label": "Updated Node 1"},
{"id": 2, "label": "Updated Node 2"}
]
}DELETE /api/graph/nodes/batch
Request:
{
"ids": [1, 2, 3, 4, 5]
}POST /api/webhooks
Request:
{
"url": "https://myapp.com/webhook",
"events": ["node.created", "node.updated", "graph.updated"],
"secret": "your-webhook-secret",
"active": true
}Response:
{
"id": "webhook-uuid-123",
"url": "https://myapp.com/webhook",
"events": ["node.created", "node.updated"],
"createdAt": "2025-11-04T12:00:00Z"
}| Event | Description | Payload |
|---|---|---|
node.created |
Node created | {node: {...}} |
node.updated |
Node updated | {node: {...}, changes: {...}} |
node.deleted |
Node deleted | {nodeId: 123} |
edge.created |
Edge created | {edge: {...}} |
edge.deleted |
Edge deleted | {edgeId: 456} |
graph.updated |
Graph updated | {nodesChanged: 10, edgesChanged: 5} |
validation.completed |
Validation done | {reportId: "report-123"} |
Headers:
X-Webhook-Signature: sha256=...
X-Webhook-Event: node.created
X-Webhook-Delivery: delivery-uuid-123
Content-Type: application/json
Body:
{
"event": "node.created",
"timestamp": "2025-11-04T12:00:00Z",
"data": {
"node": {
"id": 123,
"label": "New Node"
}
}
}Algorithm (HMAC-SHA256):
import hmac
import hashlib
def verify_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)- Retry on failure: 5 attempts
- Backoff: exponential (1s, 2s, 4s, 8s, 16s)
- Timeout: 30 seconds per attempt
Recommended: Use Accept header:
Accept: application/vnd.visionflow.v1+json
Alternative: Include version in URL:
GET /api/v1/graph/data
| Version | Status | Deprecation | End of Life |
|---|---|---|---|
| v1.0 | Current | - | - |
| v0.9 | Deprecated | 2025-12-01 | 2026-06-01 |
Migrating from v0.9 to v1.0:
- Update authentication to JWT (API keys still supported)
- Replace
/graph/getwith/graph/data - Update WebSocket binary protocol from 32 to 36 bytes
- Use new error code format (
AP-E-001vsERR-001)
Get Graph Data:
curl -X GET \
-H "Authorization: Bearer YOUR-JWT" \
-H "Accept: application/json" \
http://localhost:9090/api/graph/dataCreate Node:
curl -X POST \
-H "Authorization: Bearer YOUR-JWT" \
-H "Content-Type: application/json" \
-d '{"label":"New Node","type":"concept","position":{"x":0,"y":0,"z":0}}' \
http://localhost:9090/api/graph/nodesSearch Nodes:
curl -X GET \
-H "Authorization: Bearer YOUR-JWT" \
"http://localhost:9090/api/graph/search?q=quantum&fuzzy=true"Fetch Graph Data:
async function fetchGraphData() {
const response = await fetch('http://localhost:9090/api/graph/data', {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
return response.json();
}Create Node with Error Handling:
async function createNode(label, type, position) {
try {
const response = await fetch('http://localhost:9090/api/graph/nodes', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ label, type, position })
});
const data = await response.json();
if (!data.success) {
console.error('Error:', data.error.code, data.error.message);
return null;
}
return data.data;
} catch (error) {
console.error('Network error:', error);
return null;
}
}Get Graph Data:
import requests
def get_graph_data(token):
headers = {
'Authorization': f'Bearer {token}',
'Accept': 'application/json'
}
response = requests.get(
'http://localhost:9090/api/graph/data',
headers=headers
)
response.raise_for_status()
return response.json()Create Node:
def create_node(token, label, node_type, position):
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
data = {
'label': label,
'type': node_type,
'position': position
}
response = requests.post(
'http://localhost:9090/api/graph/nodes',
headers=headers,
json=data
)
result = response.json()
if not result['success']:
raise Exception(f"Error: {result['error']['message']}")
return result['data']Batch Operations:
def batch_create_nodes(token, nodes):
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
response = requests.post(
'http://localhost:9090/api/graph/nodes/batch',
headers=headers,
json={'nodes': nodes}
)
return response.json()
# Usage
nodes = [
{'label': 'Node 1', 'type': 'concept', 'position': {'x': 0, 'y': 0, 'z': 0}},
{'label': 'Node 2', 'type': 'entity', 'position': {'x': 1, 'y': 0, 'z': 0}}
]
result = batch_create_nodes(token, nodes)
print(f"Created {result['data']['created']} nodes")- Error Codes Reference - Complete error code catalog
- WebSocket Protocol - Binary WebSocket specification
-
- All configuration options
- Architecture Overview - System design
- Getting Started - Installation guide
Last Updated: 2025-11-04 Version: 1.0.0 Status: Production Reference Maintainer: VisionFlow API Team