oruk's REST and SSE API delivers corroborated breaking news from 240 live radio, TV, and structured feeds in 7 regions, with stories typically hitting the wire 30–90 seconds after they're spoken on air. The public feed is free; an account-bound key unlocks full filters, deeper history, the SSE stream, the MCP server, and webhooks. Most evaluation work fits inside the free tier (100 calls/month).
Send your API key in the X-API-Key header (or Authorization: Bearer, or the ?api_key= query param for SSE clients that can't set headers). Three read endpoints — /health, /v1/health, and /v1/stories/feed — are public and don't need a key; everything else under /v1/* does.
The full open-vs-keyed surface:
Endpoint
Auth
Notes
GET /health
PUBLIC
Liveness probe.
GET /v1/health
PUBLIC
Detailed health: streams, stories, uptime.
GET /v1/stories/feed
PUBLIC
The latest ~100 stories, no filters.
Everything else under /v1/*
REQUIRES KEY
Full filter surface, story lookups, sources, stats, SSE, webhooks, key management.
Pass your key via any of these:
Method
Header / Param
Example
API Key
X-API-Key
X-API-Key: ork_x9f2...
Bearer Token
Authorization
Authorization: Bearer ork_x9f2...
Query Param
api_key
?api_key=ork_x9f2... (only for SSE / EventSource clients that can't set headers)
Free includes 100 API calls per month and 1 key, with a 5-minute API delay. Pro includes 1,000 calls per month, 2 keys, and real-time API responses. Trader includes 10,000 calls per month, 2 keys, the real-time SSE stream, and a 300 req/min rate limit. Enterprise limits are customized.
How do I get started with the oruk API in 5 minutes?
Sign up with email, generate an API key from the dashboard, and call GET /v1/stories/feed?limit=10 with the X-API-Key header. The Free tier includes 100 calls/month and 1 key — enough to verify the integration before picking a plan.
1. Create an account
Sign up at oruk.ai with your email. You'll receive a 6-digit verification code to confirm your account.
2. Generate an API key
Head to the dashboard and click Generate Key. Free accounts get 1 key with 100 calls/month (5-minute API delay). Upgrade for higher quotas and real-time responses: Pro (1k/mo, real-time), Trader (10k/mo + SSE), or Enterprise (1M+/mo).
3. Pick a plan that fits your usage
Most evaluation work fits on Free. Upgrade from the pricing page when you need higher monthly call quotas, SSE stream access, or more keys.
4. Fetch live events
Pick your stack — the tab choice persists across every snippet on this page. We don't ship official SDKs yet; these are copy-paste templates against the public REST and SSE endpoints.
import httpx
r = httpx.get(
"https://api.oruk.ai/v1/stories/feed",
params={"limit": 10},
headers={"X-API-Key": "ork_xxxxxxxx"},
)
for story in r.json()["stories"]:
print(story["headline"])
SSE access by tier: Free, Pro, and Legacy do not include SSE (403). Trader ($49 first month, then $99/mo) and Enterprise stream in real time with the same wire as the public homepage — one connection, every new or corroborated story.
import httpx, json
with httpx.stream(
"GET",
"https://api.oruk.ai/v1/stream",
headers={"X-API-Key": "ork_xxxxxxxx"},
) as r:
for line in r.iter_lines():
if line.startswith("data:"):
event = json.loads(line[5:].strip())
print(event.get("headline") or event)
const es = new EventSource(
"https://api.oruk.ai/v1/stream?api_key=ork_xxxxxxxx"
);
es.addEventListener("story", (e) => {
const story = JSON.parse(e.data);
console.log(`[${story.urgency}] ${story.headline}`);
});
package main
import (
"bufio"
"fmt"
"net/http"
"strings"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.oruk.ai/v1/stream", nil)
req.Header.Set("X-API-Key", "ork_xxxxxxxx")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
s := bufio.NewScanner(resp.Body)
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "data:") {
fmt.Println(strings.TrimSpace(line[5:]))
}
}
}
require "net/http"
uri = URI("https://api.oruk.ai/v1/stream")
req = Net::HTTP::Get.new(uri,
"X-API-Key" => "ork_xxxxxxxx",
"Accept" => "text/event-stream",
)
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |h|
h.request(req) do |resp|
resp.read_body { |chunk| puts chunk }
end
end
How do I fetch the latest news without an API key?
Call GET /v1/stories/feed — it's open to anyone and returns up to ~100 of the freshest stories with no filters required. Use it as your default endpoint for "what's new right now"; upgrade to /v1/stories with a key when you need filters, full-text search, or pagination.
GET/v1/stories/feedPUBLIC · powers the public wire on oruk.ai and the no-key fallback in oruk-mcp.
The feed returns up to ~100 of the freshest events. For older stories, use
/v1/stories?since=… with an API key.
How do I search and filter stories with full filters?
Call GET /v1/stories with an API key and any combination of category, q, since, region, country, urgency, min_impact, min_confidence, and topics. Results paginate with a stable cursor, and you can switch the response format to csv or jsonl for bulk export.
{
"stories": [{ /* same shape as /v1/stories/feed */ }],
"meta": {"count": 5, "cursor": "evt_7c2a1f", "hasMore": true}
}
How do I fetch a single story with its full timeline?
Call GET /v1/stories/{evt_id} with an API key. The response includes the full body, the developmental timeline, every independent corroborating source with the verbatim quote it used, the multi-category list, and event coordinates — everything you need to audit the story without trusting our judgement on its face.
How do I stream news events in real time over SSE?
Open a long-lived GET /v1/stream connection with your API key — it returns text/event-stream with three event types (story, corroboration, heartbeat) and stays open until your client disconnects. SSE is included on Trader ($49 first month, then $99/mo) and Enterprise. Free, Pro, and Legacy tiers receive HTTP 403 with an upgrade hint.
const es = new EventSource(
"https://api.oruk.ai/v1/stream?api_key=YOUR_KEY"
);
es.addEventListener("story", (e) => {
const story = JSON.parse(e.data);
console.log(`[${story.urgency}] ${story.body.slice(0, 100)}`);
});
Python
import httpx, json
with httpx.stream("GET", "https://api.oruk.ai/v1/stream",
headers={"X-API-Key": "YOUR_KEY"},
params={"category": "conflict"}) as r:
for line in r.iter_lines():
if line.startswith("data:"):
event = json.loads(line[5:].strip())
print(event)
How do I list every monitored broadcast source?
Call GET /v1/sources with an API key. The response is the full station catalogue — currently 240 sources across Europe (116), North America (38), Asia-Pacific (36), South America (27), Global (12), Middle East (7), and Africa (4) — each with city, region, country, language, default category, medium, live status, and polling cadence.
GET/v1/sourcesREQUIRES KEY · same data renders on /sources.
Call GET /v1/stats with an API key for an instantaneous snapshot — at this writing the response shows 215 active sources, 42,000+ total stories, 670,000+ transcriptions processed, ~17 ms last reconciliation cycle, and the top-five categories by published volume. Use it as a heartbeat for monitoring or as a "health-of-the-wire" widget on your own dashboard.
How do I get geographic story counts for map overlays?
Call GET /v1/regions with an API key. The response is the story heatmap — an array of integer-bucketed lat/lon cells with the count of stories in each cell and the dominant category — currently ~1,800 cells globally, ready to drop into Leaflet, Mapbox, or any d3 choropleth.
Generate, label, and revoke keys from the Dashboard — Free accounts get 1 key, Pro and Trader get 2 keys each, and Enterprise up to 100. Each key is independently revocable and bills against the same monthly quota; rotate one without affecting any others.
How does the oruk MCP server work with Claude, Cursor, and Continue.dev?
Install the npm package oruk-mcp with one line — npx -y oruk-mcp — and any Model Context Protocol client (Claude Desktop, Cursor, Continue.dev) gets 12 tools, 6 resources, and 3 slash-prompts for searching corroborated real-time news. Without an API key it falls back to the public feed; set ORUK_API_KEY to lift it to the full filter surface, deeper history, and arbitrary evt_… story lookups.
The official production path today is stdio via npm:
npx -y oruk-mcp. Remote MCP over Streamable HTTP is planned as a
controlled beta after OAuth-compatible connector auth, quotas, origin controls,
and audit logging are in place.
How it fits
The MCP runs locally on your machine (spawned by your IDE). It talks directly to
api.oruk.ai on Railway — the same Python backend that powers
everything else. Azure (oruk.ai) is the public website only; there is no separate dataset
to query.
oruk://stories/latest — live snapshot of the freshest 25 stories
Prompts (slash commands)
/summarize_breaking — short briefing of urgent stories, optional category/region filter
/track_topic — chronological summary of a topic over the past N hours
/morning_briefing — structured "what happened overnight" rundown grouped by category
Without an API key
The public /v1/stories/feed endpoint is open. When ORUK_API_KEY
is unset, the server falls back to a 2-hour window of the freshest 50 stories on the feed
and applies all filters client-side. Good for almost every interactive query but trims
older stories and omits the sources / stats endpoints. Set the env var (free key at the
Dashboard) for the full
filter surface, deeper history, and arbitrary evt_… story lookups.
Quota accounting
Every MCP tool invocation that reaches the backend counts as one API call
against your key — the same quota the REST API uses (see
Rate limits & quotas). The MCP holds an in-process cache for ~3 s
on the public feed, so multi-tool turns inside one session usually collapse to a single
backend hit. If you run into 429 from a tool, the answer is the same as for the
REST API: upgrade or wait
out the month.
Hit the standard discovery URLs first — every public page links to them and they're explicitly allow-listed in robots.txt for AI-search crawlers. Each file gives an agent a different shape of context: a JSON capability manifest, an agent skill card, an operating guide, a Markdown sitemap, and curated/full-context LLM documentation.
/.well-known/ai.json — capability manifest for REST, SSE, webhooks, MCP, auth, story fields, and pricing status.
Does oruk support machine-payable autonomous agent calls?
Not yet — production billing is API-key based through human-managed Stripe subscriptions, and existing REST/SSE endpoints do not return live 402 Payment Required challenges. An opt-in x402 beta on new /v1/x402/* endpoints is in research; existing REST, SSE, webhooks, and MCP behaviour will not change when the beta lands.
Oruk is preparing autonomous payment support as a separate beta so machine clients
can pay for isolated live-data calls without navigating a human checkout page. The
first safe rollout target is new opt-in endpoints such as
/v1/x402/stories/feed and /v1/x402/stories/{id}, leaving existing
REST, SSE, webhooks, and MCP behavior unchanged.
Protocol
Status
Best fit
x402
Planned beta
Pay-per-request API calls, likely USDC on Base through a facilitator.
Stripe Machine Payments Protocol
Access-gated research
Session-based or spending-limit authorization once Stripe machine-payments access is available.
Stripe subscriptions
Live now
Human-managed recurring plans and API keys.
Until Oruk announces a beta, treat 401, 403, and 429 as the
active auth and quota signals. Machine-payment status is also published in
/.well-known/ai.json.
How are oruk API errors structured?
Every error response carries a stable machine-readable error code plus a human-readable message that may change. The HTTP status, the request ID echoed in x-request-id, and (on auth failures) a www-authenticate: Bearer header are everything an agent needs to recover or escalate without parsing English.
{
"error": "unauthorized",
"message": "Valid API key or JWT required."
}
The error field is a stable machine-readable code; the message field
is a human-readable description that may change. 401 responses also include a
www-authenticate: Bearer header, and the request id is exposed via
x-request-id on every response (useful when filing a support ticket).
Status
Code
When
400
invalid_email
Malformed email at signup
400
invalid_request
Malformed query parameters or body (e.g. since=yesterday)
401
unauthorized
Missing or invalid API key / JWT
401
invalid_code
Wrong email verification code
404
not_found
Resource not found (story id, source id, etc.)
409
email_taken
Email already registered
429
rate_limit_exceeded
Monthly call quota exhausted; check Retry-After header (seconds to wait)
How are oruk rate limits and monthly quotas enforced?
oruk meters by monthly call count per API key, not per second — calls reset on the 1st of each month UTC. The MCP server shares the same quota; the public /v1/stories/feed, /health, and /v1/health endpoints don't count toward any quota and don't need a key at all.
Tier
Calls / month
Per-minute rate
Keys
/v1/stream
free
100
30
1
Not included
pro
1,000
60
2
Not included
legacy
1,000
60
2
Not included
trader
10,000
300
2
Real-time
enterprise
1,000,000+
Custom
100
Real-time
What counts as one call?
Each REST request (GET, POST, DELETE) counts once at request-time.
An SSE connection counts once when the connection opens; events delivered while it stays open do not re-bill.
Each MCP tool invocation that reaches the backend counts as one call. Tools with structuredContent.mode: "public" use the same shared call against /v1/stories/feed.
The MCP holds an in-process cache for ~3 s on the public feed, so multi-tool turns inside one MCP session typically collapse to a single backend hit.
/health, /v1/health, and /v1/stories/feed are public; they don't require a key and don't count toward any quota.
What a 429 looks like
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{"error": "rate_limit_exceeded",
"message": "Monthly call quota exhausted on the free tier."}
Upgrade at /pricing to lift the quota,
or wait until the calendar month rolls over.
What broadcasters does oruk cover?
240 monitored sources across 7 regions, with per-source live status and polling cadence available on /v1/sources. The breakdown below counts every catalogued broadcaster, social feed, and structured feed; Europe leads with 116 sources, followed by North America (38), Asia-Pacific (36), and South America (27).
Region
Sources
Sample broadcasters
Europe
116
BBC World Service, LBC, France Info, Deutschlandfunk, NDR, RAI, SER, ERT, Radio Maryja, Times Radio
Sky News Arabia, Iran International, Radio Farda, Al Araby, Radio Orient
Africa
4
SAfm and three regional broadcasters under expansion
Live counts come from /v1/sources; this table updates whenever the catalogue does. The full station list with city, region, language, and default category is on /sources.
What does each oruk plan include?
Four public tiers — Free, Pro ($12/mo), Trader ($49 first month, then $99/mo), Enterprise. The live wire on oruk.ai is real-time for everyone, no signup required. Paid tiers add programmatic REST access; SSE is available on Trader and Enterprise.
Plan
Frontend
Programmatic Access
Free
Real-time wire
100 API calls/month, 1 key, REST, MCP; authenticated /v1/stories ~5 min behind the live wire; /v1/stream not included
Pro ($12/mo)
Real-time wire
1,000 API calls/month, 2 keys, real-time REST, MCP. SSE not included.
Have a referral code? Enter it at Stripe checkout for your first month of Pro free.
Sign Up
Create a free account to use the public wire and manage upgrades later. Free tier: 5-minute delayed frontend, 100 API calls/month, 1 key, no credit card required.
Available on every tier. Structured stories with topics, confidence, and location metadata.
SSE StreamGET /v1/stream
Trader and Enterprise tiers only: real-time story, corroboration, and heartbeat events. Free, Pro, and Legacy plans are not able to open this endpoint.
MCP Servernpx -y oruk-mcp
Drop into Claude Desktop, Cursor, or Continue.dev. 12 tools, 6 resources, 3 prompts. Free tier ready.
WebhooksPOST /v1/webhooks
HMAC-signed delivery to your endpoint. Up to 5 webhooks on Trader; filter by category, country, impact, and topic.
Plans
Free: 100 API calls/mo, 1 key, ~5 min API lag vs. the live wire. Pro $12/mo: 1k calls/mo, 2 keys, real-time API (no SSE). Trader $49 first month, then $99/mo: 10k calls/mo, 2 keys, real-time REST + SSE + webhooks.
Trader carries the Developer surface with intro pricing. Enterprise raises limits and adds custom support. See pricing for the full breakdown.