Skip to main content

Connection

wss://api.xshot.fun/ws?api_key=YOUR_KEY
On connect, the server sends:
{
  "type": "connected",
  "timestamp": "2026-03-28T13:39:50.995Z"
}

Subscribe to a Channel

Send a JSON message:
{
  "type": "subscribe",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" },
  "interval": 15
}
Server confirms:
{
  "type": "subscribed",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" },
  "interval": 15
}

Receive Events

When data changes, the server pushes an event. Only changed fields are included — no event is sent if nothing changed. Example — tweet gets 2 new views:
{
  "type": "event",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" },
  "data": {
    "view_count": 41836,
    "view_count_delta": 2
  },
  "timestamp": "2026-03-28T13:40:14.239Z"
}

Unsubscribe

{
  "type": "unsubscribe",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" }
}
Server confirms:
{
  "type": "unsubscribed",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" }
}

Available Channels

ChannelRequired ParamsDefault IntervalMin/Max
community:tweetsid30s15-120s
community:membersusername60s30-300s
user:tweetsusername30s15-120s
user:mentionsusername30s15-120s
user:followersusername60s30-300s
tweet:engagementtweet_id15s10-120s
search:tweetsquery30s15-120s

Event Data Formats

community:tweets

New tweets posted in a community.
{
  "type": "event",
  "channel": "community:tweets",
  "params": { "id": "1907801083659038985" },
  "data": {
    "new_tweets": [
      {
        "id": "2037850410535550990",
        "text": "gm everyone, floating islands are beautiful today",
        "created_at": "Fri Mar 28 12:00:00 +0000 2026",
        "author": {
          "id": "1762266425589149696",
          "name": "daumen",
          "username": "daumenxyz",
          "followers_count": 121896
        },
        "like_count": 15,
        "retweet_count": 3,
        "reply_count": 2,
        "view_count": 450
      }
    ]
  },
  "timestamp": "2026-03-28T12:00:30.000Z"
}

community:members

Detects when a user joins or leaves communities.
{
  "type": "event",
  "channel": "community:members",
  "params": { "username": "daumenxyz" },
  "data": {
    "joined": [
      { "id": "1907801083659038985", "name": "Floating Islands Community" }
    ],
    "left": [
      { "id": "2020059771030892626", "name": "$Punch Fan Community" }
    ]
  },
  "timestamp": "2026-03-28T12:01:00.000Z"
}

user:tweets

New tweets from a specific user.
{
  "type": "event",
  "channel": "user:tweets",
  "params": { "username": "elonmusk" },
  "data": {
    "new_tweets": [
      {
        "id": "2037850934274138146",
        "text": "Starship launch window opens tomorrow",
        "created_at": "Fri Mar 28 14:30:00 +0000 2026",
        "author": {
          "id": "44196397",
          "name": "Elon Musk",
          "username": "elonmusk",
          "followers_count": 237614000
        },
        "like_count": 45000,
        "retweet_count": 8200,
        "reply_count": 3100,
        "view_count": 12000000
      }
    ]
  },
  "timestamp": "2026-03-28T14:30:30.000Z"
}

user:mentions

New tweets mentioning a user.
{
  "type": "event",
  "channel": "user:mentions",
  "params": { "username": "elonmusk" },
  "data": {
    "new_mentions": [
      {
        "id": "2037851000000000000",
        "text": "@elonmusk when is the next Starship launch?",
        "created_at": "Fri Mar 28 14:35:00 +0000 2026",
        "author": {
          "id": "999999999",
          "name": "Space Fan",
          "username": "spacefan42",
          "followers_count": 1500
        },
        "like_count": 5,
        "retweet_count": 0,
        "reply_count": 1,
        "view_count": 200
      }
    ]
  },
  "timestamp": "2026-03-28T14:35:30.000Z"
}

user:followers

Follower count changes. Reports the new count, previous count, and delta.
{
  "type": "event",
  "channel": "user:followers",
  "params": { "username": "elonmusk" },
  "data": {
    "followers_count": 237614746,
    "previous_count": 237614000,
    "change": 746
  },
  "timestamp": "2026-03-28T14:31:00.000Z"
}

tweet:engagement

Live engagement metrics. Only changed fields are included, each with its delta.
{
  "type": "event",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" },
  "data": {
    "like_count": 328,
    "like_count_delta": 2,
    "view_count": 41836,
    "view_count_delta": 985,
    "retweet_count": 70,
    "retweet_count_delta": 2
  },
  "timestamp": "2026-03-28T13:40:14.239Z"
}

search:tweets

New tweets matching a search query.
{
  "type": "event",
  "channel": "search:tweets",
  "params": { "query": "bitcoin" },
  "data": {
    "new_tweets": [
      {
        "id": "2037852000000000000",
        "text": "Bitcoin breaking through resistance levels today",
        "created_at": "Fri Mar 28 15:00:00 +0000 2026",
        "author": {
          "id": "888888888",
          "name": "Crypto Analyst",
          "username": "cryptoanalyst",
          "followers_count": 50000
        },
        "like_count": 120,
        "retweet_count": 30,
        "reply_count": 15,
        "view_count": 25000
      }
    ]
  },
  "timestamp": "2026-03-28T15:00:30.000Z"
}

Error Events

Sent when polling fails (e.g. rate limit, account issues):
{
  "type": "error",
  "channel": "tweet:engagement",
  "params": { "tweet_id": "2035548674483273831" },
  "code": "POLL_ERROR",
  "message": "Rate limited (429)"
}
Error codes: INVALID_JSON, INVALID_CHANNEL, SUBSCRIBE_FAILED, POLL_ERROR, UNKNOWN_TYPE

Keepalive

Send periodic pings to keep the connection alive:
{ "type": "ping" }
{ "type": "pong" }
The server also sends WebSocket-level pings every 30 seconds. Unresponsive clients are disconnected after 10 seconds.

Full JavaScript Example

const ws = new WebSocket("wss://api.xshot.fun/ws?api_key=YOUR_KEY");

ws.onopen = () => {
  console.log("Connected to Xshot WebSocket");

  // Monitor tweet engagement in real-time
  ws.send(JSON.stringify({
    type: "subscribe",
    channel: "tweet:engagement",
    params: { tweet_id: "2035548674483273831" },
    interval: 15
  }));

  // Watch for new tweets from a user
  ws.send(JSON.stringify({
    type: "subscribe",
    channel: "user:tweets",
    params: { username: "elonmusk" },
    interval: 30
  }));

  // Monitor community membership changes
  ws.send(JSON.stringify({
    type: "subscribe",
    channel: "community:members",
    params: { username: "daumenxyz" },
    interval: 60
  }));
};

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

  switch (msg.type) {
    case "connected":
      console.log("Server ready:", msg.timestamp);
      break;

    case "subscribed":
      console.log(`Subscribed to ${msg.channel} (polling every ${msg.interval}s)`);
      break;

    case "event":
      console.log(`[${msg.channel}]`, JSON.stringify(msg.data, null, 2));
      break;

    case "error":
      console.error(`Error on ${msg.channel}: ${msg.message}`);
      break;
  }
};

ws.onclose = (event) => {
  if (event.code === 4001) {
    console.error("Authentication failed - check your API key");
  } else {
    console.log("Disconnected:", event.code, event.reason);
  }
};

Full Python Example

import asyncio
import json
import websockets

API_KEY = "YOUR_KEY"

async def main():
    uri = f"wss://api.xshot.fun/ws?api_key={API_KEY}"

    async with websockets.connect(uri) as ws:
        # Subscribe to follower changes
        await ws.send(json.dumps({
            "type": "subscribe",
            "channel": "user:followers",
            "params": {"username": "elonmusk"},
            "interval": 60
        }))

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

            if msg["type"] == "event":
                data = msg["data"]
                print(f"Followers: {data['followers_count']} ({data['change']:+d})")

            elif msg["type"] == "error":
                print(f"Error: {msg['message']}")

asyncio.run(main())

Behavior Details

  • Deduplication: Multiple clients on the same resource share one poll
  • First poll: Captures initial snapshot without emitting events (avoids flood)
  • Auto-cleanup: Polling stops when all clients unsubscribe from a resource
  • Max subscriptions: 100 total across all connected clients
  • Snapshot cap: 500 IDs per subscription to prevent memory growth
  • Error backoff: After 5 consecutive poll failures, an error event is sent to all subscribers