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_... header
  • X-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 names
  • rows — result data (max 10,000 rows; truncated: true if exceeded)
  • total_rows — total row count before truncation
  • query_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"}
StatusMeaning
200Success
202Async task created (poll via /api/tasks/{id})
400Invalid input or missing required fields
401Missing or invalid API key
403Forbidden (read-only database, feature not licensed, DROP disabled)
404Database, file, user, or query not found
409Conflict (database or user already exists)
500Internal server error