WebSocket API

Connect to the KITE 2.0 WebSocket for real-time news streaming. News items are pushed to your client the moment they appear, with optional server-side filtering so you only receive what matters.

Connection URL

wss://kite-api.gtdigital.dev/api/ws?key=YOUR_API_KEY

Authentication

WebSocket connections require a valid API key passed as a key query parameter. To get a key, create an account and generate one from your Account → API Keys page.

javascript
const ws = new WebSocket('wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here');

Connections without a valid key are rejected with a 401 HTTP response before the WebSocket upgrade completes.

Connection Lifecycle

1
Connect

Open a WebSocket connection to the endpoint.

2
Receive confirmation

The server sends a connected message.

3
Subscribe with filters

Send a subscribe message with your filter preferences. Without this, you receive all items.

4
Receive news events

The server pushes news messages as items are created, updated, or deleted.

5
Keep alive

Send periodic ping messages to maintain the connection.

Client → Server Messages

subscribe

Set or update your filter preferences. Sending a new subscribe message replaces any previous filters. All filter fields are optional; omitted fields match everything.

json
{
  "type": "subscribe",
  "filters": {
    "sources": ["BBC News", "CNBC"],
    "categories": ["financial_news"],
    "keywords": ["Bitcoin", "Gold"],
    "tickers": ["AAPL"],
    "companies": ["Apple", "Tesla"]
  }
}

unsubscribe

Clear all filters and receive everything.

json
{
  "type": "unsubscribe"
}

ping

Send a keep-alive ping. The server responds with a pong.

json
{
  "type": "ping"
}

Server → Client Messages

connected

Sent immediately after the connection is established.

json
{
  "type": "connected",
  "message": "Connected to KITE 2.0 WebSocket. Send a 'subscribe' message to set filters."
}

subscribed

Confirmation that your filters have been applied.

json
{
  "type": "subscribed",
  "filters": {
    "sources": ["BBC News"],
    "categories": ["financial_news"]
  }
}

news

A news item event. The action field indicates whether the item was created, updated, or deleted.

json
{
  "type": "news",
  "action": "create",
  "item": {
    "id": "abc123xyz",
    "title": "Fed Announces Rate Decision",
    "url": "https://example.com/article",
    "description": "The Federal Reserve...",
    "published": "2025-05-01T14:00:00.000Z",
    "source": "Bloomberg Markets",
    "category": "central_banks",
    "author": "Jane Smith",
    "tags": ["federal reserve", "rates"],
    "tickers": ["SPY"],
    "article_type": "news",
    "image_url": "https://example.com/image.jpg",
    "speaker": "",
    "speaker_title": "",
    "institution": "",
    "event_location": "",
    "base_currency": "",
    "target_currency": "",
    "exchange_rate": "",
    "created": "2025-05-01T14:05:00.000Z",
    "updated": "2025-05-01T14:05:00.000Z"
  }
}

pong

Response to a ping message.

json
{
  "type": "pong"
}

error

Sent when the server cannot process a client message.

json
{
  "type": "error",
  "message": "Invalid JSON"
}

Filter Options

Filters use AND logic between groups and OR logic within each group. For example, setting both sources and keywords means an item must match at least one source AND at least one keyword.

ParameterTypeDefaultDescription
sourcesstring[]--Filter by source names (e.g. ["BBC News", "CNBC"])
categoriesstring[]--Filter by category IDs: financial_news, central_banks, regulators
keywordsstring[]--Match against title, description, tickers, and tags
tickersstring[]--Filter by ticker symbols (e.g. ["AAPL", "BTC"])
companiesstring[]--Match company names against title and description (e.g. ["Apple", "Tesla"])

Code Examples

JavaScript / Node.js

javascript
const ws = new WebSocket('wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here');

ws.onopen = () => {
  console.log('Connected to KITE 2.0');

  // Subscribe to central bank news about interest rates
  ws.send(JSON.stringify({
    type: 'subscribe',
    filters: {
      categories: ['central_banks'],
      keywords: ['interest rates', 'inflation']
    }
  }));
};

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

  switch (data.type) {
    case 'news':
      console.log(`[${data.action}] ${data.item.title}`);
      console.log(`  Source: ${data.item.source}`);
      console.log(`  Tickers: ${data.item.tickers.join(', ')}`);
      break;
    case 'connected':
      console.log(data.message);
      break;
    case 'subscribed':
      console.log('Filters applied:', data.filters);
      break;
    case 'pong':
      break;
  }
};

ws.onerror = (err) => console.error('WebSocket error:', err);
ws.onclose = () => console.log('Disconnected');

// Keep-alive every 30 seconds
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: 'ping' }));
  }
}, 30000);

Python

python
import asyncio
import websockets
import json

async def listen():
    async with websockets.connect('wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here') as ws:
        # Subscribe to crypto news
        await ws.send(json.dumps({
            'type': 'subscribe',
            'filters': {
                'categories': ['financial_news'],
                'keywords': ['Bitcoin', 'Ethereum', 'crypto'],
                'sources': ['CoinDesk', 'CoinTelegraph', 'Decrypt']
            }
        }))

        async for message in ws:
            data = json.loads(message)

            if data['type'] == 'news':
                item = data['item']
                print(f"[{data['action']}] {item['title']}")
                print(f"  Source: {item['source']}")
                if item.get('tickers'):
                    print(f"  Tickers: {', '.join(item['tickers'])}")
                print()

asyncio.run(listen())

curl (WebSocket)

bash
# Using websocat (install: cargo install websocat)
echo '{"type":"subscribe","filters":{"categories":["central_banks"]}}' | \
  websocat 'wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here'

# Using wscat (install: npm install -g wscat)
wscat -c 'wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here'
# Then type: {"type":"subscribe","filters":{"keywords":["Bitcoin"]}}

Updating Filters

You can change your filters at any time by sending a new subscribe message. The new filters completely replace the previous ones.

javascript
// Start with broad filters
ws.send(JSON.stringify({
  type: 'subscribe',
  filters: { categories: ['financial_news'] }
}));

// Later, narrow down to specific sources
ws.send(JSON.stringify({
  type: 'subscribe',
  filters: {
    sources: ['Bloomberg Markets', 'CNBC'],
    tickers: ['AAPL', 'GOOGL', 'MSFT']
  }
}));

// Clear all filters (receive everything)
ws.send(JSON.stringify({ type: 'unsubscribe' }));

Reconnection

The WebSocket server does not implement automatic reconnection. If the connection drops, your client should implement exponential backoff reconnection logic:

javascript
function connect(retryMs = 1000) {
  const ws = new WebSocket('wss://kite-api.gtdigital.dev/api/ws?key=kite_your_key_here');

  ws.onopen = () => {
    console.log('Connected');
    retryMs = 1000; // Reset backoff on success
    // Re-send your subscribe message here
  };

  ws.onclose = () => {
    console.log(`Reconnecting in ${retryMs}ms...`);
    setTimeout(() => connect(Math.min(retryMs * 2, 30000)), retryMs);
  };

  return ws;
}

connect();