Skip to content
Wednesday, 4 November 2026
Inspire.News

Unveiling truth, one story at a time

Build with Inspire News

A read-only REST API, signed webhooks and a Model Context Protocol (MCP) server so other apps and AI agents can use our news and trend insights.

Authentication

Every request needs an API key. Keys are issued by an Inspire News administrator under Admin › Integrations. Send the key in either header:

Authorization: Bearer ink_your_key
X-Api-Key: ink_your_key

Each key may make 120 requests per minute (REST and MCP combined). Over the limit you get 429 Too Many Requests with a Retry-After header. A missing or invalid key returns 401.

REST API

Base URL: https://www.inspirenews.xyz/api/v1. All responses are JSON (camelCase). Lists are paged with page (from 1) and pageSize (1–50).

EndpointDescription
GET /categoriesAll sections with their ids.
GET /news?category=&page=&pageSize=Latest stories, newest first. category is an id or a section name.
GET /news/{id}One story with its plain-text body. Archived stories have archived: true.
GET /search?q=&page=&pageSize=Search headlines and keywords.
GET /trending/news?hours=24&count=10&category=Stories with the highest trend score.
GET /trending/topics?hours=24&count=20Trending keywords with frequency and velocity.
GET /insights?category=Latest AI trend insight per section (or one section).
GET /meChecks your key.

Example

curl -H "Authorization: Bearer ink_your_key" "https://www.inspirenews.xyz/api/v1/search?q=oil&pageSize=5"
{
  "items": [
    {
      "id": "6720c1…",
      "title": "Oil climbs as …",
      "summary": "…",
      "url": "https://www.inspirenews.xyz/Home/News_detail_improved?newsID=6720c1…",
      "sourceUrl": "https://publisher.example/story",
      "imageUrl": "https://…",
      "categoryId": "65f…",
      "category": "Business",
      "source": "Publisher name",
      "publishedUtc": "2026-10-30T08:15:00Z",
      "sentiment": "Neutral",
      "trendScore": 71.4,
      "keywords": ["oil", "opec"]
    }
  ],
  "page": 1, "pageSize": 5, "total": 128
}

Please show the publisher name and link to sourceUrl when you display a story.

Webhooks

An administrator registers your HTTPS endpoint. We then send a POST with a JSON body:

{
  "id": "evt_9f0c…",
  "type": "news.published",
  "created": "2026-10-30T08:20:11Z",
  "data": { "categoryId": "65f…", "category": "Business", "count": 7, "items": [ /* stories, same shape as the API */ ] }
}
EventWhen
news.publishedNew stories were added to a section (one event per section per fetch, up to 25 stories).
insight.generatedA trend insight was written for a section. data has the same shape as /api/v1/insights.
webhook.testSent when an administrator presses “Send test”.

Verifying the signature

Each request carries X-Inspire-Signature: t=<unix time>,v1=<hex>, where v1 is HMAC-SHA256(secret, t + "." + rawBody). Recompute it over the raw body, compare in constant time, and reject requests older than 5 minutes. X-Inspire-Delivery is the event id; use it to ignore duplicates. Answer with any 2xx within 15 seconds — otherwise we retry after 5 s and 30 s.

// Node.js (Express)
const crypto = require("crypto");
app.post("/webhooks/inspire", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("X-Inspire-Signature") || "";
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  const expected = crypto.createHmac("sha256", process.env.INSPIRE_WEBHOOK_SECRET)
    .update(parts.t + "." + req.body).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  const ok = fresh && parts.v1 && expected.length === parts.v1.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
  if (!ok) return res.sendStatus(401);
  const event = JSON.parse(req.body);
  // … handle event.type …
  res.sendStatus(204);
});
# Python (Flask)
import hmac, hashlib, time
@app.post("/webhooks/inspire")
def inspire():
    parts = dict(p.split("=", 1) for p in request.headers.get("X-Inspire-Signature", "").split(","))
    body = request.get_data()
    expected = hmac.new(SECRET.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest()
    if abs(time.time() - int(parts["t"])) > 300 or not hmac.compare_digest(expected, parts.get("v1", "")):
        abort(401)
    return "", 204

MCP server for AI agents

Endpoint: https://www.inspirenews.xyz/mcp (Streamable HTTP, stateless, protocol versions 2025-06-18 / 2025-03-26 / 2024-11-05). Add it to any MCP client that supports remote servers:

{
  "mcpServers": {
    "inspire-news": {
      "type": "http",
      "url": "https://www.inspirenews.xyz/mcp",
      "headers": { "Authorization": "Bearer ink_your_key" }
    }
  }
}

Clients that only support local (stdio) servers can use the mcp-remote bridge:

{
  "mcpServers": {
    "inspire-news": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://www.inspirenews.xyz/mcp", "--header", "Authorization:Bearer ${INSPIRE_KEY}"],
      "env": { "INSPIRE_KEY": "ink_your_key" }
    }
  }
}
ToolArguments
search_newsquery (required), page, page_size
get_latest_newscategory, page, page_size
get_articleid (required)
list_categories—
get_trending_newshours, count, category
get_trending_topicshours, count
get_trend_insightscategory

All tools are read-only. Results include structuredContent plus the same JSON as text.