HTTP API
The Traverse HTTP API provides RESTful endpoints for queries, database management, import/export, and Studio integration.
Base URL: http://localhost:7691 (set via --http-listen). The HTTP server is opt-in — you must set TRAVERSE_HTTP_LISTEN or --http-listen to enable it.
API Documentation
Traverse ships with built-in interactive API documentation:
- Scalar API Reference (
GET /api/docs) — interactive UI for exploring and testing all endpoints - OpenAPI 3.1.0 Specification (
GET /api/openapi.json) — machine-readable spec for code generation and tooling
Authentication
Protected endpoints require an API key. The server auto-generates a random key on startup (printed as API key tvs_... in the log) unless you provide one via --api-key. Supply it in requests via one of:
Authorization: Bearer tvs_...headerX-API-Key: tvs_...header?token=tvs_...query parameter (useful for WebSocket)
API keys use the tvs_ prefix followed by 32 hex characters (128-bit random). Comparison uses constant-time XOR to prevent timing attacks.
Public Endpoints (no key required)
/api/health, /api/ready, /api/docs, /api/openapi.json, /metrics, /api/feedback, /api/share-query, /ws (WebSocket auth is per-message).
CORS
The HTTP server allows cross-origin requests from any origin:
- Allowed origins:
* - Allowed methods: GET, POST, PUT, DELETE
- Allowed headers:
*
Health & Status
GET /api/health
Returns server status including uptime, memory usage, database stats, license info, and available updates.
GET /api/ready
Simple readiness probe. Returns 200 OK when the server is ready.
GET /metrics
Prometheus-format metrics: memory usage, uptime, node count and edge count per database.
Query Execution
POST /api/query
Execute a Cypher query.
POST /api/query
Content-Type: application/json
Authorization: Bearer tvs_...
{
"query": "MATCH (n:Person) RETURN n.name LIMIT 10",
"database": "mydb",
"parameters": {"limit": 10}
}
The response includes:
columns— column namesrows— result data (max 10,000 rows;truncated: trueif exceeded)total_rows— total row count before truncationquery_type—"READ","WRITE", or"UNKNOWN"stats— nodes/edges created, properties set, etc.time_ms,parsing_time_ms,planning_time_ms,execution_time_ms— timing breakdown
Add ?async=true to execute asynchronously. Returns a task ID to poll via GET /api/tasks/{id}.
Async Tasks
GET /api/tasks/{id}
Poll the status of an async operation (query, drop, unload, load, save).
{
"id": "...",
"operation": "drop",
"status": "running", // "running", "completed", "failed"
"result": {...}, // present when completed
"error": "...", // present when failed
"createdAt": "...",
"finishedAt": "..."
}
Endpoints that support ?async=true: /api/query, /api/databases/{name} (DELETE), /api/databases/{name}/unload, /api/databases/load, /api/save.
Database Management
GET /api/databases
List all databases. Returns name, default flag, read-only flag, aliases, node/edge counts, and memory usage.
POST /api/databases
Create a new database.
{"name": "analytics"}
DELETE /api/databases/{name}
Drop a database. Requires --allow-drop-database to be set on the server. Supports ?async=true. Returns 403 if not enabled.
POST /api/databases/{name}/rename
Rename a database.
{"name": "analytics_v2"}
POST /api/databases/{name}/unload
Unload a database from memory (keeps the file on disk). Supports ?async=true.
POST /api/databases/load
Load an existing .tvdb file from disk. Supports ?async=true.
{"name": "mydb", "file": "mydb.tvdb"}
Schema
GET /api/schema
Returns labels, relationship types, property keys, indexes, and constraints. Use ?database=name to target a specific database.
Data Import
Body limit: Import endpoints accept up to 512 MB.
POST /api/import
Import Cypher statements (one per line). Supports ?async=true.
{
"cypher": "CREATE (n:Person {name: 'Alice'});\nCREATE (n:Person {name: 'Bob'});",
"database": "mydb"
}
Response:
{
"total_statements": 2,
"executed": 2,
"errors": [],
"stats": {...},
"time_ms": 12.5
}
POST /api/import/csv
Import a CSV file as nodes.
{
"csv": "id,name,age\n1,Alice,30\n2,Bob,25",
"label": "Person",
"columns": [
{"name": "id", "property": "id", "type": "integer"},
{"name": "name"},
{"name": "age", "type": "integer"}
],
"database": "mydb",
"delimiter": ",",
"skip_header": true
}
Supported column types: string (default), integer, float, boolean.
Supported delimiters: , (default), \t / tab, ;, |.
POST /api/import/csv/edges
Import a CSV file as relationships.
{
"csv": "...",
"edge_type": "KNOWS",
"source": {"label": "Person", "column": "from_id", "property": "id"},
"target": {"label": "Person", "column": "to_id", "property": "id"},
"columns": [...],
"database": "mydb"
}
File Management
GET /api/files
List all .tvdb files on disk. Returns name, file path, size in bytes, and whether loaded.
GET /api/files/{name}
Download a .tvdb file (streamed).
PUT /api/files/{name}
Upload a .tvdb file. The first 4 bytes must be the TVDB magic header. Written atomically via a .upload temp file.
DELETE /api/files/{name}
Delete a .tvdb file from disk.
Database Aliases
GET /api/aliases
List all database aliases.
POST /api/aliases
Create an alias.
{"alias": "production", "database": "mydb_v2"}
PUT /api/aliases/{name}
Change the target database of an alias.
{"database": "mydb_v3"}
DELETE /api/aliases/{name}
Delete an alias.
User Management
GET /api/users
List all users with username and role.
POST /api/users
Create a new user.
{"username": "alice", "password": "s3cret", "role": "EDITOR"}
Roles: ADMIN, EDITOR, READER (default). Passwords are hashed with bcrypt (cost factor 12).
PUT /api/users/{username}
Update a user's password or role.
{"password": "new_pass", "role": "ADMIN"}
DELETE /api/users/{username}
Delete a user.
Persistence
POST /api/save
Save all databases to disk immediately. Supports ?async=true. Studio calls this automatically after imports.
Studio Integration
Studio metadata is stored in .studio.json sidecar files next to each .tvdb.
GET /api/studio/queries
List saved queries. Optional: ?database=name.
POST /api/studio/queries
Save a query. Optional: ?database=name.
{"name": "Find all people", "query": "MATCH (n:Person) RETURN n"}
DELETE /api/studio/queries/{name}
Delete a saved query. Optional: ?database=name.
GET /api/studio/styles
Get custom visualization styles. Optional: ?database=name.
PUT /api/studio/styles
Save custom visualization styles. Optional: ?database=name.
WebSocket
GET /ws
WebSocket endpoint for streaming queries. Authenticate via Bearer token or ?token= query parameter.
Request message
{
"type": "query",
"id": "unique-message-id",
"query": "MATCH (n) RETURN n LIMIT 10",
"database": "mydb",
"parameters": {}
}
Response messages
// Row (streamed for each result row)
{"type": "result", "id": "...", "columns": [...], "row": [...]}
// Completion
{"type": "complete", "id": "...", "stats": {"rows": 100, "time_ms": 12.3}}
// Error
{"type": "error", "id": "...", "message": "error description"}
License Management
POST /api/license/activate
Start the license activation flow. Returns an activationId and loginUrl.
POST /api/license/activate/poll/{id}
Poll activation status. Returns "pending" or "completed" with the license key.
POST /api/license/devices
List all devices on the current license.
DELETE /api/license/devices/{id}
Remove a device from the license.
POST /api/license/deactivate
Deactivate the current license and reset to trial.
GET /api/update/download
Download the latest server binary.
Error Responses
All error responses use a consistent format:
{"error": "error message"}
| Status | Meaning |
|---|---|
200 | Success |
202 | Async task created (poll via /api/tasks/{id}) |
400 | Invalid input or missing required fields |
401 | Missing or invalid API key |
403 | Forbidden (read-only database, feature not licensed, DROP disabled) |
404 | Database, file, user, or query not found |
409 | Conflict (database or user already exists) |
500 | Internal server error |