Use the headlines endpoint for fast access to trending news.
Realtime stream (WebSocket) — Pro
Production URL matches the public API prefix: wss://rhubapi.org/api/ws/everything?apikey=… — path is /api/ws/everything (not the same as HTTP /api/everything). For a bare Go API without an /api reverse-proxy prefix, use ws://host:port/ws/everything?apikey=…
Pro users can subscribe to realtime updates via WebSocket. Authenticate with apikey (query param).
Behavior
Long-lived stream (always):
Optional q (keyword) — If you pass q, only new inserts whose title, authors, content, or tags contain q (case-insensitive) are pushed. The connection stays open so future matching rows are pushed too.
Optional category / source — category and source further narrow matches (AND with q and each other). If you omit q, category, and source, every new article is pushed. Each push is { "type": "article", "data": { ... } }.
The server first sends { "type": "subscribed", "q", "category", "source" }. Use HTTP GET /everything for paginated historical search; WebSocket is for realtime inserts only.
Access control
WebSocket streaming is available to Pro users only.
Free users receive delayed, non‑realtime results via the HTTP endpoint instead.
Params: HTTP GET /api/everything: at least one of q, category, or source is required. WebSocket /api/ws/everything: long-lived; optional q, category, and source use AND semantics; omit all three to receive every new row. WebSocket ignores page and pageSize (those apply to HTTP GET /api/everything only). First WebSocket message is subscribed; then article messages for each matching insert.
JavaScript example
// Long-lived stream: first frame { type: "subscribed", ... }, then { type: "article", data } per matching insert.
// Path must be /api/ws/everything (same /api prefix as HTTP /api/everything). Optional q/category/source (AND); omit all three = every new insert.
// Historical pagination: HTTP GET https://rhubapi.org/api/everything?apikey=...&q=...
const url = new URL("wss://rhubapi.org/api/ws/everything");
url.searchParams.set("apikey", "YOUR_API_KEY");
url.searchParams.set("q", "openai");
url.searchParams.set("category", "technology");
url.searchParams.set("source", "nytimes.com");
let socket;
let attempts = 0;
function connect() {
socket = new WebSocket(url.toString());
socket.onopen = () => {
attempts = 0;
console.log("connected");
};
socket.onmessage = (ev) => {
try {
const msg = JSON.parse(ev.data);
// { type: "subscribed", q, category, source }
// { type: "article", data: {...} }
console.log("message:", msg);
} catch {
console.log("raw:", ev.data);
}
};
socket.onclose = () => {
// simple backoff
const wait = Math.min(30000, 1000 * Math.pow(2, attempts++));
setTimeout(connect, wait);
};
socket.onerror = (e) => console.error("ws error", e);
}
connect();
# Uses System.Net.Http.HttpClient (built-in). No extra install required.
Usage
using System.Net.Http;
using System.Threading.Tasks;
var http = new HttpClient();
var url = "https://rhubapi.org/api/everything?q=openai&apikey=YOUR_API_KEY&page=1&pageSize=10";
var resp = await http.GetStringAsync(url);
System.Console.WriteLine(resp);