API Documentation

Complete guide to Turboline's REST API and WebSocket streaming. Built for developers, understandable by everyone.

Backend Setup

Before using the API, you need to set up and run the TurboStream backend server. Follow these steps to configure your environment.

Prerequisites

  • Go 1.21 or higher
  • MongoDB (local or cloud instance)
  • At least one LLM provider API key (OpenAI, Anthropic, Azure, etc.)

Environment Configuration

Create a .env.local file in your TurboStream project root with the following variables:

.env.local
# Server Configuration
BACKEND_HOST=0.0.0.0
BACKEND_PORT=7210
# Note: Port is customizable - change to any available port
CORS_ORIGIN=http://localhost:7200
REQUEST_TIMEOUT_MS=15000

# Authentication & Security
JWT_SECRET=your-secure-jwt-secret-change-me
ENCRYPTION_KEY=your-secure-encryption-key-change-me

# MongoDB
MONGODB_URI=mongodb://localhost:27017
MONGODB_DB_NAME=turbostream

# ============================================
# LLM Provider Configuration (BYOM)
# ============================================
# Set DEFAULT_AI_PROVIDER to: azure-openai, openai, anthropic, gemini, mistral, grok, or ollama
DEFAULT_AI_PROVIDER=openai

# OpenAI (Recommended for getting started)
OPENAI_API_KEY=sk-your-openai-api-key
OPENAI_MODEL=gpt-4o

# Azure OpenAI (Enterprise)
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
AZURE_OPENAI_API_KEY=your-azure-api-key
AZURE_OPENAI_API_VERSION=2024-02-15-preview
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o

# Anthropic (Claude)
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022

# Google AI (Gemini)
GOOGLE_API_KEY=your-google-api-key
GOOGLE_MODEL=gemini-1.5-flash

# Mistral
MISTRAL_API_KEY=your-mistral-api-key
MISTRAL_MODEL=mistral-large-latest

# xAI (Grok)
XAI_API_KEY=xai-your-grok-api-key
XAI_MODEL=grok-beta

# Ollama (Local LLM - no API key needed)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2

# LLM Settings
LLM_MAX_TOKENS=1024
LLM_TEMPERATURE=0.7
LLM_CONTEXT_LIMIT=50

# Token Limits (optional)
TOKEN_QUOTA_PER_MONTH=1000000

💡 Bring Your Own Model (BYOM):

TurboStream supports multiple LLM providers. You only need to configure ONE provider to get started. Set your DEFAULT_AI_PROVIDER and provide the corresponding API key.

Starting the Server

Build and Run
# Navigate to TurboStream directory
cd /path/to/turbostream

# Build the server
go build -o turbostream ./cmd/server

# Run the server
./turbostream
Expected Output
✓ MongoDB connected
✓ OpenAI enabled (model: gpt-4o)
✓ 1 LLM provider(s) available: [openai]
✓ Started topic LLM scheduler for feed 65f789...
🚀 Go backend listening on 0.0.0.0:7210 (CORS: http://localhost:7200)

⚠️ Port Configuration: The default port is 7210 but you can change it in your .env.local file by updating BACKEND_PORT. Make sure to update the base URL in all API requests if you change the port.

Verify Installation

Test that your server is running correctly:

Health Check
curl http://localhost:7210/health
Expected Response
{
  "status": "ok",
  "timestamp": "2026-01-30T12:00:00Z"
}

Getting Started

Now that your backend is running, let's create an account and start using the API.

Step 1: Create an Account

POST
/api/auth/register

Create a new user account

Request Body
{
  "email": "[email protected]",
  "password": "SecurePassword123!",
  "name": "Your Name"
}
Response (201 Created)
{
  "message": "User registered successfully",
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsIn....",
  "user": {
    "_id": "65f123abc456def789ghijkl",
    "email": "[email protected]",
    "name": "Your Name",
    "createdAt": "2026-01-30T19:54:10.63Z",
    "tokenUsage": {
      "currentMonth": "2026-01",
      "tokensUsed": 0,
      "limit": 1000000,
      "lastResetDate": "2026-01-30T19:54:10.63Z",
      "overdraftAllowed": true
    },
    "twoFactorEnabled": false
  }
}

💡 Tip: Save the token from the response. You'll need it for all authenticated API requests.

What You Can Do

Connect to Feeds

Stream real-time data from any WebSocket source or create your own custom feeds.

LLM Intelligence

Get AI-powered analysis and insights on your streaming data automatically or on-demand.

Topic Routing

Separate intelligence by topic (e.g., BTC-USD, ETH-USD) with isolated context and memory.

Real-Time WebSocket

Consume data and intelligence via WebSocket for instant updates with zero polling.

Authentication

Turboline uses JWT (JSON Web Tokens) for authentication. Include your token in the Authorization header for all protected endpoints.

Login to Get Your Token

POST
/api/auth/login

Authenticate and receive a JWT token

Request Body
{
  "email": "[email protected]",
  "password": "SecurePassword123!"
}
Response (200 OK)
{
  "message": "Login successful",
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsIn....",
  "user": {
    "_id": "65f123abc456def789ghijkl",
    "email": "[email protected]",
    "name": "Your Name",
    "createdAt": "2026-01-30T19:54:10.63Z",
    "tokenUsage": {
      "currentMonth": "2026-01",
      "tokensUsed": 0,
      "limit": 1000000,
      "lastResetDate": "2026-01-30T19:54:10.63Z",
      "overdraftAllowed": true
    },
    "twoFactorEnabled": false
  }
}

💡 Tip: Save the token from the response. You'll need it for all authenticated API requests.

Using Your Token

Add your JWT token to the Authorization header with the Bearer prefix:

cURL Example
curl -X GET "http://localhost:7210/api/auth/me" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Usage Examples
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

fetch('http://localhost:7210/api/auth/me', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
})
.then(res => res.json())
.then(data => console.log(data));

Get Your Profile

GET
/api/auth/me

Get authenticated user's profile and token usage

🔒 Requires Authentication
Response
{
  "success": true,
  "user": {
    "_id": "65f123abc456def789ghijkl",
    "email": "[email protected]",
    "name": "Your Name",
    "createdAt": "2026-01-30T19:54:10.63Z",
    "lastLogin": "2026-01-30T20:59:32.192Z",
    "tokenUsage": {
      "currentMonth": "2026-01",
      "tokensUsed": 15234,
      "limit": 1000000,
      "lastResetDate": "2026-01-30T19:54:10.63Z",
      "overdraftAllowed": true
    },
    "twoFactorEnabled": false
  }
}

⚠️ Security: Never expose your JWT token in client-side code or commit it to version control. Tokens expire after 7 days and must be refreshed by logging in again.

Feed Management

Feeds are WebSocket data sources that stream real-time information. Create custom feeds or subscribe to public marketplace feeds.

Browse Public Feeds

GET
/api/marketplace/feeds

List all public feeds (no auth required)

GET
/api/marketplace/feeds/popular?limit=10

Get most subscribed feeds

GET
/api/marketplace/feeds/search?q=crypto&category=finance

Search feeds by keyword and category

Example Response
{
  "count": 1,
  "data": [
    {
      "_id": "697d10f5824ee2ba77fcad87",
      "name": "Coinbase",
      "description": "Real-time price updates for Coinbase Pro trading pairs. Track price, volume, and 24h statistics.",
      "url": "wss://ws-feed.exchange.coinbase.com",
      "category": "finance",
      "isActive": true,
      "isVerified": false,
      "isPublic": true,
      "feedType": "user",
      "userId": "697d0c62824ee2ba77fcad84",
      "ownerName": "Manas Mudbari",
      "connectionType": "websocket",
      "connectionMessages": [
        "{ \"type\": \"subscribe\", \"product_ids\": [ \"BTC-USD\", \"ETH-USD\", \"SOL-USD\"], \"channels\": [ \"ticker\" ] }"
      ],
      "reconnectionEnabled": true,
      "subscriberCount": 2,
      "tags": null,
      "enableTopicRouting": false,
      "createdAt": "2026-01-30T20:13:41.199Z",
      "updatedAt": "2026-01-30T20:13:41.199Z"
    }
  ],
  "success": true
}

Create a Custom Feed

POST
/api/marketplace/feeds

Create a new feed

🔒 Requires Authentication
Request Body (Basic Feed)
{
  "name": "My Custom Feed",
  "description": "Description of what this feed provides",
  "url": "wss://example.com/stream",
  "category": "technology",
  "isPublic": false,
  "connectionType": "websocket"
}

💡 Need WebSocket Examples?

Check out our WebSocket Examples Directory for ready-to-use feed configurations including Binance, Coinbase, Kraken, and more.

Request Body (Multi-Topic Feed)
{
  "name": "Multi-Instrument Market Data",
  "description": "Real-time prices for multiple trading pairs",
  "url": "wss://stream.binance.com:9443/ws/!ticker@arr",
  "category": "finance",
  "isPublic": true,
  "connectionType": "websocket",
  "enableTopicRouting": true,
  "topicField": "s",
  "connectionMessages": [
    "{\"method\":\"SUBSCRIBE\",\"params\":[\"btcusdt@ticker\",\"ethusdt@ticker\"],\"id\":1}"
  ]
}

💡 Topic Routing:

  • enableTopicRouting: true - Activates per-topic intelligence mode
  • topicField: "s" - Replace "s" with the actual field name from your feed data that contains the topic identifier
  • connectionMessages - Use \\" to escape quotes in JSON strings (as shown in the Request Body above)
  • Each topic gets: Isolated LLM context + memory + continuous analysis

ConnectionMessages Converter

Struggling with escaping quotes? Paste your WebSocket subscription message and we'll convert it to the correct format for connectionMessages.

Enter the JSON message your WebSocket provider expects for subscription

Response (201 Created)
{
  "data": {
    "_id": "65f789abc123...",
    "name": "My Custom Feed",
    "description": "Description of what this feed provides",
    "url": "wss://example.com/stream",
    "category": "technology",
    "isActive": true,
    "isVerified": false,
    "isPublic": false,
    "feedType": "user",
    "userId": "65f123def456...",
    "ownerName": "Your Name",
    "connectionType": "websocket",
    "connectionMessages": [],
    "reconnectionEnabled": true,
    "subscriberCount": 0,
    "tags": null,
    "enableTopicRouting": false,
    "createdAt": "2026-01-30T10:00:00Z",
    "updatedAt": "2026-01-30T10:00:00Z"
  },
  "success": true
}

Subscribe to a Feed

POST
/api/marketplace/subscribe/:feedId

Subscribe to receive data from a feed

🔒 Requires Authentication
Example Request
curl -X POST "http://localhost:7210/api/marketplace/subscribe/65f789..." \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "message": "Subscribed",
  "subscription": {
    "_id": "65f999abc123...",
    "userId": "65f123def456...",
    "feedId": "65f789abc123...",
    "subscribedAt": "2026-01-30T10:05:00Z",
    "isActive": true
  },
  "success": true
}

Manage Your Subscriptions

GET
/api/marketplace/subscriptions

List all your active subscriptions

🔒 Requires Authentication
POST
/api/marketplace/unsubscribe/:feedId

Unsubscribe from a feed

🔒 Requires Authentication

Manage Topic Prompts

PUT
/api/marketplace/feeds/:id

Update feed properties including topic-specific prompts

🔒 Requires Authentication
Request Body (Update Topic Prompts)
{
  "topicPrompts": {
    "BTCUSDT": {
      "systemPrompt": "You are a Bitcoin market analyst.",
      "question": "What are the key price movements?"
    },
    "ETHUSDT": {
      "systemPrompt": "You are an Ethereum market analyst.",
      "question": "Analyze the current trend."
    }
  }
}
Response
{
  "success": true,
  "data": {
    "_id": "65f789abc123...",
    "name": "Binance Crypto Prices",
    "topicPrompts": {
      "BTCUSDT": {
        "systemPrompt": "You are a Bitcoin market analyst.",
        "question": "What are the key price movements?"
      },
      "ETHUSDT": {
        "systemPrompt": "You are an Ethereum market analyst.",
        "question": "Analyze the current trend."
      }
    }
  }
}
PUT
/api/marketplace/feeds/:id/ai-prompt

Update the default AI prompt for a feed

🔒 Requires Authentication
Request Body
{
  "defaultAIPrompt": "You are a financial analyst specializing in cryptocurrency markets."
}
Response
{
  "success": true,
  "data": {
    "_id": "65f789abc123...",
    "name": "My Feed",
    "defaultAIPrompt": "You are a financial analyst specializing in cryptocurrency markets."
  }
}

Topic Routing

Split a single data feed into multiple intelligence streams. Each topic (e.g., BTC-USD, ETH-USD) gets its own AI analysis, memory, and subscribers.

Two Independent Settings

1. Connection Messages

What you send TO the feed provider to subscribe

Controls what data you receive

2. Topic Field

What you extract FROM incoming messages to organize data

Controls how data is routed and analyzed

💡 Key Insight: Connection messages and topic field are separate. The connection message tells the provider what to send you. The topic field tells TurboStream how to organize what you receive.

Topic Field Syntax

The topicField extracts a routing key from incoming data. Use TurboStream's simple syntax to navigate your data structure.

PatternWhat It DoesUse When
"symbol"Gets a top-level fieldField is at root of data
"data.origin"Gets a nested fieldField is inside an object
"[3]"Gets item at position 3Data is an array (4th item)
"path[0]"Gets first item in arrayField contains an array
"path[-1]"Gets last item in arrayArray length varies
"data.path[-1]"Gets last item of nested arrayCombining nested + array access

📌 Note: This is TurboStream's custom syntax (similar to Python/jq). Array positions start at 0. Only [-1] is supported for negative indexing (last element).

TopicField Generator

Not sure what pattern to use? Paste your WebSocket JSON response and the value you want to extract, and we'll generate the topicField pattern for you.

Enter a field name (like "path" or "symbol") or an exact value to find

Example 1: Simple Field (Cryptocurrency)

Feed Configuration
{
  "name": "Coinbase Crypto Prices",
  "url": "wss://ws-feed.exchange.coinbase.com",
  "enableTopicRouting": true,
  "topicField": "product_id",  // Extract the "product_id" field from each message
  "connectionMessages": [
    "{\"type\":\"subscribe\",\"product_ids\":[\"BTC-USD\",\"ETH-USD\"],\"channels\":[\"ticker\"]}"
  ]
}
What Coinbase Sends You
{
  "type": "ticker",
  "sequence": 93483876225,
  "product_id": "BTC-USD",  // ← This becomes the topic
  "price": "42150.50",
  "open_24h": "41500.00",
  "volume_24h": "25643.12345678",
  "low_24h": "41200.00",
  "high_24h": "42500.00",
  "best_bid": "42150.49",
  "best_ask": "42150.51",
  "side": "buy",
  "time": "2026-02-09T15:33:13.483677Z",
  "trade_id": 769630264,
  "last_size": "0.001"
}

{
  "type": "ticker",
  "sequence": 93483876226,
  "product_id": "ETH-USD",  // ← This becomes a different topic
  "price": "2035.8",
  "open_24h": "2107.39",
  "volume_24h": "174471.54258318",
  "low_24h": "2006.88",
  "high_24h": "2150",
  "best_bid": "2035.79",
  "best_ask": "2035.96",
  "side": "buy",
  "time": "2026-02-09T15:33:13.483677Z",
  "trade_id": 769630264,
  "last_size": "0.001"
}

✅ What Happens:

  • • TurboStream extracts "BTC-USD" and "ETH-USD" from the "product_id" field
  • • Creates separate AI analysis for Bitcoin and Ethereum
  • • Clients can subscribe to just the topics they care about

Example 2: Nested Array (Internet Routing)

Feed Configuration
{
  "name": "BGP Route Updates",
  "url": "wss://ris-live.ripe.net/v1/ws/",
  "enableTopicRouting": true,
  "topicField": "data.path[-1]",  // Get last item from nested array
  "connectionMessages": [
    "{\"type\":\"ris_subscribe\",\"data\":{\"origin\":\"2856\"}}"
  ]
}
What RIPE Sends You
{
  "data": {
    "path": [41722, 12389, 1299, 174, 40138],
    //                                  ↑ Last element = origin network
    "type": "UPDATE"
  }
}

// TurboStream extracts: 40138

Example 3: Root Array (Trading Data)

Feed Configuration
{
  "name": "Kraken Trades",
  "url": "wss://ws.kraken.com",
  "enableTopicRouting": true,
  "topicField": "[3]",  // Get item at position 3 from root array
  "connectionMessages": [
    "{\"event\":\"subscribe\",\"pair\":[\"XBT/USD\"],\"subscription\":{\"name\":\"trade\"}}"
  ]
}
What Kraken Sends You (Array Format)
[
  119930881,      // [0] Channel ID
  [[...]],        // [1] Trade data
  "trade",        // [2] Event type
  "XBT/USD"       // [3] ← Trading pair (topic)
]

// TurboStream extracts: "XBT/USD"

💡 Summary: The topic field can extract data from anywhere in the message structure. Each provider formats data differently - just tell TurboStream where to look.

LLM Intelligence

Get AI-powered insights on your streaming data. Choose between manual queries or continuous automatic analysis.

Output Modes

Manual Mode

Query the LLM on-demand via API. You control when to ask questions.

  • ✓ Full control over prompts
  • ✓ Cost-efficient (pay per query)
  • ✓ Custom system prompts

Auto Mode (Topic Routing)

Continuous LLM analysis for each topic. Automated intelligence streaming.

  • ✓ Real-time insights every 10s
  • ✓ Per-topic intelligence
  • ✓ No manual queries needed

Manual Query (REST API)

POST
/api/llm/query

Ask a question about feed data

🔒 Requires Authentication
Request Body
{
  "feedId": "65f789...",
  "question": "What are the main trends in the data?",
  "provider": "openai",
  "systemPrompt": "You are a financial analyst..."
}
Response
{
  "answer": "Based on the recent data, I observe three main trends:\n\n1. **Upward Price Movement**: Bitcoin has increased 3.5% over the last 50 entries...\n\n2. **Increased Volatility**: The price range has widened...\n\n3. **Volume Surge**: Trading volume spiked by 25%...",
  "provider": "openai",
  "feedId": "65f789...",
  "tokensUsed": 450,
  "durationMs": 1250
}

Streaming Query

POST
/api/llm/query/stream

Stream LLM response token-by-token

🔒 Requires Authentication
Streaming Examples
const response = await fetch('/api/llm/query/stream', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    feedId: '65f789...',
    question: 'Analyze the recent price action'
  })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value);
  process.stdout.write(chunk);
}

Auto Mode Configuration

When you enable enableTopicRouting on a feed, automatic LLM analysis is activated for each topic.

Analysis Intervals

Default Interval10 seconds
Context Buffer Size50 entries
Analysis MemoryLast 3 Q&A pairs
Default Question"Provide a brief analysis..."

Configuring Analysis Interval

You can customize the analysis interval for topic-routed feeds via environment variables or by modifying feed settings.

Environment Variable (Global Default)
# In your .env.local file
LLM_QUERY_INTERVAL_SECONDS=10

# Options: 5, 10, 30, 60 (seconds)
# This sets the default for all topic-routed feeds
PUT
/api/marketplace/feeds/:feedId

Update feed settings including custom interval

🔒 Requires Authentication
Update Feed Interval via API
curl -X PUT "http://localhost:7210/api/marketplace/feeds/65f789..." \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queryInterval": 30
  }'

# queryInterval: Analysis interval in seconds (5, 10, 30, 60)
# This overrides the global default for this specific feed

⚠️ Note: Shorter intervals (5-10s) provide faster insights but consume more LLM tokens. Longer intervals (30-60s) are more cost-effective but updates are less frequent. Choose based on your use case and token budget.

Available LLM Providers

GET
/api/llm/providers

Get list of configured LLM providers

Response
{
  "enabled": true,
  "providers": ["openai", "anthropic", "gemini", "azure-openai"]
}
OpenAI
OpenAI
GPT-4, GPT-4o
Anthropic
Anthropic
Claude 3.5
Gemini
Google
Gemini Pro
Azure
Azure
OpenAI

API Keys for Third Party App Integration

API keys allow your applications, scripts, and services to connect to TurboStream's WebSocket API without user login credentials. Perfect for third party integrations, automated systems, backend services, and IoT devices.

💡

What's the Difference?

JWT Tokens - For user accounts. Used with the web dashboard and REST API. Requires login with email/password.

API Keys - For automated systems. No login needed. Each key has specific permissions (scopes) to control what it can do.

What are Scopes?

Scopes control what an API key can do. This keeps your system secure by giving each key only the permissions it needs.

websocket:subscribe

Access raw feed data streams. Can subscribe to feeds and receive data updates.

Use for: Data ingestion pipelines, monitoring dashboards

websocket:llm

Access AI-powered analysis. Can query the LLM and receive intelligent insights.

Use for: AI chatbots, automated trading analysis

websocket:topic

Subscribe to topic-specific intelligence. Perfect for multi-instrument data.

Use for: Per-asset analysis, multi-channel monitoring

websocket:*

Full access to all WebSocket operations. Has all permissions above.

Use for: Admin tools, full-featured applications

💡 Best Practice: Only grant the scopes your application needs. For example, if you only need to read data, use websocket:subscribe instead of websocket:*. This follows the principle of least privilege.

Creating an API Key

First, you need to be logged in with your JWT token (from login). API keys can only be created by authenticated users.

POST
/api/auth/api-keys

Create a new API key with specific scopes

🔒 Requires Authentication
Request Body
{
  "name": "My Trading Bot",
  "scopes": ["websocket:subscribe", "websocket:llm"]
}

📝 Naming Tips:

  • Use descriptive names like "Production Trading Bot" or "Dev Dashboard"
  • Include environment: "Staging API Key" vs "Production API Key"
  • Names must be unique for each user
Create API Key Examples
const response = await fetch('http://localhost:7210/api/auth/api-keys', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_JWT_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'My Trading Bot',
    scopes: ['websocket:subscribe', 'websocket:llm']
  })
});

const data = await response.json();
console.log('API Key:', data.key);
// SAVE THIS KEY! You won't see it again
Response (201 Created) - SAVE THE KEY!
{
  "success": true,
  "message": "API key created successfully. Store this key securely - it will not be shown again.",
  "apiKey": {
    "_id": "65f999abc123...",
    "name": "My Trading Bot",
    "prefix": "ts_live_",
    "lastChars": "8dF2aC9b",
    "scopes": ["websocket:subscribe", "websocket:llm"],
    "createdAt": "2026-02-02T10:00:00Z"
  },
  "key": "ts_live_a7Kx9mP2nQ5wR8yT4vB6cD1eF3gH0jL5_8dF2aC9b"
}

⚠️ CRITICAL: Save Your Key Immediately!

The full API key (starting with ts_live_) is shown ONLY ONCE when created. If you lose it, you'll need to revoke and create a new one. Store it in a secure location like a password manager or environment variable.

List Your API Keys

See all your active API keys. The full key value is never shown, only the last 8 characters for identification.

GET
/api/auth/api-keys

List all your active API keys

🔒 Requires Authentication
Response
{
  "success": true,
  "apiKeys": [
    {
      "_id": "65f999abc123...",
      "name": "My Trading Bot",
      "prefix": "ts_live_",
      "lastChars": "8dF2aC9b",
      "scopes": ["websocket:subscribe", "websocket:llm"],
      "isActive": true,
      "createdAt": "2026-02-02T10:00:00Z",
      "lastUsedAt": "2026-02-02T15:30:00Z"
    },
    {
      "_id": "65f888def456...",
      "name": "Dashboard Monitor",
      "prefix": "ts_live_",
      "lastChars": "xY9zAb3c",
      "scopes": ["websocket:subscribe"],
      "isActive": true,
      "createdAt": "2026-01-28T08:00:00Z",
      "lastUsedAt": "2026-02-02T16:00:00Z"
    }
  ]
}

💡 What You See: The lastChars field shows the last 8 characters of your key. Use this to identify which key is which. The lastUsedAt field shows when the key was last used to authenticate.

Revoke an API Key

If an API key is compromised or no longer needed, revoke it immediately. Revoked keys cannot authenticate.

DELETE
/api/auth/api-keys/:id

Revoke an API key by its ID

🔒 Requires Authentication
Example Request
curl -X DELETE "http://localhost:7210/api/auth/api-keys/65f999abc123..." \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response
{
  "success": true,
  "message": "API key revoked successfully"
}

⚠️ Instant Effect: When you revoke a key, it stops working immediately. Any application using that key will be unable to authenticate. Make sure to update your applications with a new key before revoking the old one.

WebSocket API

Consume real-time data and LLM intelligence via WebSocket. Zero polling, instant updates.

Authentication with API Keys

For third party app integration, you can authenticate using an API key instead of a JWT token. This is perfect for automated systems, backend services, and IoT devices.

WebSocket Endpoint
ws://localhost:7210/ws

# For production
wss://api.turboline.ai/ws

💡 Note: You must first create an API key through the REST API (see API Keys section above). The key will start with ts_live_.

WebSocket Authentication with API Key
const ws = new WebSocket('ws://localhost:7210/ws');

ws.onopen = () => {
  console.log('✓ Connected to TurboStream');

  // Authenticate with API key
  ws.send(JSON.stringify({
    type: 'authenticate',
    payload: {
      apiKey: 'ts_live_a7Kx9mP2nQ5wR8yT4vB6cD1eF3gH0jL5_8dF2aC9b'
    }
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === 'authenticated') {
    console.log('✓ Authenticated with API key');
    console.log('Auth type:', msg.payload.authType); // "apikey"
    console.log('User ID:', msg.payload.userId);

    // Now you can subscribe to feeds
    ws.send(JSON.stringify({
      type: 'subscribe-feed',
      payload: {
        userId: msg.payload.userId,
        feedId: 'YOUR_FEED_ID'
      }
    }));
  } else if (msg.type === 'auth_error') {
    console.error('Authentication failed:', msg.payload.error);
  }
};

⚠️ Scope Restrictions: API keys are limited to the scopes they were created with. If your key doesn't have the required scope (e.g., trying to subscribe to LLM without websocket:llm), you'll receive an error: "insufficient permissions"

Subscribe to Topic Intelligence

For multi-topic feeds, subscribe to specific topics to receive their LLM analysis.

Subscribe to Topic
// Subscribe to BTC-USD intelligence
ws.send(JSON.stringify({
  type: 'subscribe-topic',
  payload: {
    userId: 'user-123',
    feedId: '65f789...',
    topic: 'BTCUSDT'
  }
}));
Subscription Success Response
{
  "type": "subscription-success",
  "payload": {
    "feedId": "65f789...",
    "topic": "BTCUSDT",
    "type": "topic"
  }
}

Receive LLM Intelligence

Intelligence Message (Every 10s)
{
  "type": "llm-intelligence",
  "payload": {
    "feedId": "65f789...",
    "topic": "BTCUSDT",
    "analysis": "Bitcoin is showing strong bullish momentum with a 2.1% price increase over the last 10 minutes. Volume has increased by 35%, indicating strong buying pressure. Key resistance at $42,500 is being tested. The trend appears sustainable based on current market depth.",
    "provider": "openai",
    "timestamp": "2026-01-30T15:45:30.123Z"
  }
}
Handle Intelligence Messages
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === 'llm-intelligence') {
    const { topic, analysis, provider, timestamp } = msg.payload;

    console.log('[' + topic + '] ' + analysis);

    // Update your UI
    updateDashboard(topic, analysis);
  }
};

Subscribe to Raw Feed Data

For non-topic feeds, subscribe to receive raw streaming data.

Subscribe to Feed Data
ws.send(JSON.stringify({
  type: 'subscribe-feed',
  payload: {
    userId: 'user-123',
    feedId: '65f456...'
  }
}));
Feed Data Message
{
  "type": "feed-data",
  "payload": {
    "feedId": "65f456...",
    "feedName": "Weather Updates",
    "eventName": "weather",
    "data": {
      "temperature": 72.5,
      "humidity": 65,
      "conditions": "Partly Cloudy"
    },
    "timestamp": "2026-01-30T15:45:31.456Z"
  }
}

Message Types Reference

register-user→ Client

Register your connection

subscribe-topic→ Client

Subscribe to topic intelligence

subscribe-feed→ Client

Subscribe to raw feed data

llm-intelligence← Server

Receive LLM analysis for a topic

feed-data← Server

Receive raw feed data

subscription-success← Server

Confirmation of subscription

⚠️ Important: Topic-routed feeds do NOT broadcast raw data. You'll only receive llm-intelligence messages for topics you've subscribed to.

Complete Examples

End-to-end examples putting it all together.

Cryptocurrency Price Intelligence - Complete Example

Complete WebSocket Client Implementation
const WebSocket = require('ws');

// Connect to WebSocket
const ws = new WebSocket('ws://localhost:7210/ws');

ws.on('open', () => {
  console.log('✓ Connected');

  // Register
  ws.send(JSON.stringify({
    type: 'register-user',
    payload: { userId: 'trader-123' }
  }));

  // Subscribe to BTC intelligence
  ws.send(JSON.stringify({
    type: 'subscribe-topic',
    payload: {
      userId: 'trader-123',
      feedId: 'YOUR_FEED_ID',
      topic: 'BTCUSDT'
    }
  }));

  // Subscribe to ETH intelligence
  ws.send(JSON.stringify({
    type: 'subscribe-topic',
    payload: {
      userId: 'trader-123',
      feedId: 'YOUR_FEED_ID',
      topic: 'ETHUSDT'
    }
  }));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data);

  if (msg.type === 'llm-intelligence') {
    console.log('[' + msg.payload.topic + ']');
    console.log(msg.payload.analysis);
    console.log('---');
  }
});

✅ Expected Output:

✓ Connected

[BTCUSDT]
Bitcoin is showing strong bullish momentum with a 2.1% price increase...
---

[ETHUSDT]
Ethereum is tracking Bitcoin's movement with a 1.8% gain. Volume indicates...
---

[BTCUSDT]
Continued upward pressure on Bitcoin. The $42,500 resistance level...
---

🎯 Need Help?

For support, reach out to [email protected]