Getting started
Mint a token, open the WebSocket, receive your first event. 0 difficult steps.
TOKEN=$(curl -s -X POST https://fast.corex.gg/v1/token \
-H "Authorization: Bearer sk-corex-..." | jq -r .token)
wscat -c "wss://fast.corex.gg/v1?token=$TOKEN"const r = await fetch("https://fast.corex.gg/v1/token", {
method: "POST",
headers: { Authorization: "Bearer sk-corex-..." },
});
const { token } = await r.json();
const ws = new WebSocket(`wss://fast.corex.gg/v1?token=${token}`);
ws.addEventListener("message", (e) => {
console.log(JSON.parse(e.data));
});import json, httpx
from websockets.sync.client import connect
r = httpx.post(
"https://fast.corex.gg/v1/token",
headers={"Authorization": "Bearer sk-corex-..."},
)
token = r.json()["token"]
with connect(f"wss://fast.corex.gg/v1?token={token}") as ws:
for msg in ws:
print(json.loads(msg))req, _ := http.NewRequest("POST", "https://fast.corex.gg/v1/token", nil)
req.Header.Set("Authorization", "Bearer sk-corex-...")
resp, _ := http.DefaultClient.Do(req)
var body struct{ Token string }
json.NewDecoder(resp.Body).Decode(&body)
resp.Body.Close()
ctx := context.Background()
ws, _, _ := websocket.Dial(ctx, "wss://fast.corex.gg/v1?token="+body.Token, nil)
defer ws.CloseNow()
for {
_, data, err := ws.Read(ctx)
if err != nil {
return
}
fmt.Println(string(data))
}use futures_util::StreamExt;
use tokio_tungstenite::{connect_async, tungstenite::Message};
#[derive(serde::Deserialize)]
struct TokenResponse { token: String }
let TokenResponse { token } = reqwest::Client::new()
.post("https://fast.corex.gg/v1/token")
.bearer_auth("sk-corex-...")
.send().await?.json().await?;
let (mut ws, _) = connect_async(
format!("wss://fast.corex.gg/v1?token={token}")
).await?;
while let Some(Ok(Message::Text(text))) = ws.next().await {
println!("{text}");
}require "net/http"
require "json"
require "async"
require "async/http"
require "async/websocket"
uri = URI("https://fast.corex.gg/v1/token")
req = Net::HTTP::Post.new(uri, "Authorization" => "Bearer sk-corex-...")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
token = JSON.parse(res.body)["token"]
Async do
endpoint = Async::HTTP::Endpoint.parse("wss://fast.corex.gg/v1?token=#{token}")
Async::WebSocket::Client.connect(endpoint) do |connection|
while (message = connection.read)
$stdout.puts message.parse
end
end
endWhat you need
- An API key (Power House gives you 5,000 curated handles)
- Any WebSocket client (Node, Python, Go, Rust, Ruby, or anything else)
Step 1: mint a token
A token is valid for 10 minutes and is used only to open the WebSocket. See Authentication for the full mint flow.
Step 2: open the connection
Connect to wss://fast.corex.gg/v1?token={token}. As soon as the connection is up, you receive a resumed event confirming your setup:
{ "type": "resumed", "maxSubs": 5000 }
maxSubs is the cap on your handle set (5,000 for Power House).
Step 3: receive events
That’s the whole setup. Your handles are configured server-side, so the next time anyone in your set posts, replies, follows, or anything else, you get an event. Here’s a real reply event (Elon replying to Glenn Beck). replyToText is shortened here for the preview; the wire ships the full parent text.
{
"type": "reply",
"id": "2045577165534875928",
"url": "https://x.com/elonmusk/status/2045577165534875928",
"author": {
"id": "44196397",
"username": "elonmusk",
"displayName": "Elon Musk",
"profileUrl": "https://x.com/elonmusk",
"bio": "http://Terafab.ai",
"location": "",
"websiteUrl": "",
"avatarUrl": "https://pbs.twimg.com/profile_images/2053244804520427520/m8mdWZCG_400x400.jpg",
"bannerUrl": "https://pbs.twimg.com/profile_banners/44196397/1774145451",
"verified": true,
"verifiedType": "blue",
"friendsCount": 1352,
"followersCount": 240138235,
"statusesCount": 103741,
"protected": false
},
"text": "@glennbeck @rebeccaperrotto No...",
"createdAtMs": 1776538575000,
"latencyMs": 73,
"media": [],
"article": null,
"poll": null,
"symbols": [],
"replyToAuthor": {
"id": "17454769",
"username": "glennbeck",
"displayName": "Glenn Beck",
"profileUrl": "https://x.com/glennbeck",
"bio": "Digital disruptor. Truth-teller. Narrator of meaning. Philanthropist ($300m+ raised). Founder of TheBlaze, Torch. Empowering the people, not the system.",
"location": "Rockies, Dallas, Florida",
"websiteUrl": "",
"avatarUrl": "https://pbs.twimg.com/profile_images/2022410215065554944/9SgCamFC_400x400.jpg",
"bannerUrl": "https://pbs.twimg.com/profile_banners/17454769/1771019131",
"verified": true,
"verifiedType": "blue",
"friendsCount": 864,
"followersCount": 2256646,
"statusesCount": 30745,
"protected": false
},
"replyToPostId": "2044889292225311088",
"replyToPostUrl": "https://x.com/glennbeck/status/2044889292225311088",
"replyToText": "At 15 years old, Liv Perrotto's biggest dream was to meet @elonmusk. She had even written out a list of questions to ask him...",
"replyToMedia": [
{ "type": "photo", "url": "https://pbs.twimg.com/media/HGDm-O3WYAAqAiP.jpg" },
{ "type": "photo", "url": "https://pbs.twimg.com/media/HGDm_4RW0AABSNM.jpg" }
],
"replyToArticle": null,
"replyToPoll": null,
"replyToSymbols": [],
"replyToQuoteAuthorUsername": null,
"replyToQuotePostUrl": null
}
Branch on type. Each event type carries its own fields. See Events for every shape.
Keepalive
Idle connections close after about 100 seconds. There are two ways to keep one open:
- WebSocket protocol pings (recommended). Most server-side libraries send WebSocket ping frames on a timer. The network edge replies automatically; nothing reaches your application. Python’s
websocketsdoes this by default every 20s. Go (coder/websocket), Rust (tokio-tungstenite), and Ruby (async-websocket) all expose apingmethod you can call from a 30-second timer. - Text fallback. Some clients can’t send protocol pings, including browser
WebSocketand Node’s built-inWebSocket(the WHATWG spec doesn’t expose pings to JavaScript). Send a text frame containing the literal string"ping"every 30 seconds and the server replies with"pong".
Errors
Errors on an open connection arrive as JSON messages with a stable code and a short human-readable message:
{ "type": "error", "code": "bad_request", "message": "invalid message" }
Branch on code in your handler. The message is for logs and humans, not control flow. The full list of codes is in Errors.
Next steps
- Connection: heartbeat, reconnect, and close codes
- Events: every event shape with examples
- Best practices: production patterns