# API Integration

The Gloria Data Platform provides three ways to access curated crypto news and market intelligence:

* **REST API** — Query historical and recent news, recaps, narratives, and articles
* **WebSocket API** — Stream real-time news as it's published
* **x402 API** — Pay-per-request access via micropayments (no account needed) — see [x402 Integration](https://gloriaai.gitbook.io/gloria/docs/gloria-data-platform/x402-integration)

**Base URL:** `https://ai-hub.cryptobriefing.com`

***

## Authentication

### API Token (Recommended)

Generate tokens at [itsgloria.ai/api-keys-new](https://www.itsgloria.ai/api-keys-new). Each token is scoped to specific feed categories selected during creation.

Pass your token in one of two ways:

```bash
# Query parameter
curl "https://ai-hub.cryptobriefing.com/news?token=YOUR_TOKEN&feed_categories=crypto"

# Authorization header
curl -H "Authorization: Bearer YOUR_TOKEN" "https://ai-hub.cryptobriefing.com/news?feed_categories=crypto"
```

### Wallet Authentication

For programmatic access, authenticate with an Ethereum wallet using SIWE (Sign-In with Ethereum):

1. **Get nonce:** `GET /auth/nonce` → returns `{"nonce": "..."}`
2. **Sign & verify:** `POST /auth/verify` with `{"message": "<SIWE message>", "signature": "<hex>"}` → returns `{"access_token": "...", "is_admin": false}`
3. Use the returned JWT as your token.

### Public Token

For anonymous read-only access: `GET /auth/public-token` → returns `{"access_token": "..."}`.

### Feed Permissions

Each token is associated with permissions for specific feed categories. If you request a feed category not in your allowed list, the request will fail with a `403 Forbidden` response.

***

## News API

### GET /news

Retrieve news items with filtering and pagination.

#### Query Parameters

| Parameter         | Type     | Description                                                                                                                                 |
| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `token`           | `string` | Authorization token (alternative to `Authorization` header).                                                                                |
| `feed_categories` | `string` | Comma-separated category codes (e.g. `crypto,ai_agents`). Use `token_listings` for exchange listings only. If omitted, returns all sources. |
| `from_date`       | `string` | Optional. Start date in `YYYY-MM-DD` format.                                                                                                |
| `to_date`         | `string` | Optional. End date in `YYYY-MM-DD` format.                                                                                                  |
| `keyword`         | `string` | Optional. Text search filter.                                                                                                               |
| `page`            | `number` | Optional. Page number for pagination. Defaults to `1`.                                                                                      |
| `limit`           | `number` | Optional. Number of items per page. Defaults to `20`.                                                                                       |

#### Response Format

The API returns an array of feed items in JSON format:

```json
[
    {
        "id": "3eb6c79c-6295-48e5-95ab-710b7ed66812",
        "signal": "BlackRock plans to launch Bitcoin ETF in Australia",
        "sentiment": "bullish",
        "sentiment_value": 0.95,
        "timestamp": 1762247231.193328,
        "feed_categories": [
            "crypto",
            "bitcoin",
            "macro"
        ],
        "short_context": "BlackRock has launched a spot Bitcoin ETF in Australia, giving local investors regulated access to cryptocurrency through a product listed on the country's main stock exchange.",
        "long_context": "Entities mentioned or implied in the tweet\n- BlackRock\n- BTC (Bitcoin)\n- ETF (Exchange-Traded Fund)\n- Australia\n\nExternal facts or contextual insights\nAdoption\n- BlackRock's Bitcoin ETF launch provides local Australian investors with regulated access to cryptocurrency.\n\nMarket Context\n- The move marks a historic step for Australia's financial markets, aligning with global trends in cryptocurrency legitimacy and liquidity.",
        "sources": [
            "https://x.com/LLuciano_BTC/status/1859147055840538632",
            "https://x.com/DeItaone/status/1784729756543402332",
            "https://x.com/EricBalchunas/status/1523659326396985344"
        ],
        "author": "solidintel_x",
        "tokens": [
            "$BTC"
        ],
        "tweet_url": "https://x.com/solidintel_x/status/1985634552664985964",
        "narrative_id": "32a92ee7-0dc1-47b6-a095-d27e830bdd5d"
    }
]
```

#### Response Fields

| Field             | Type             | Description                                                              |
| ----------------- | ---------------- | ------------------------------------------------------------------------ |
| `id`              | `string`         | Unique identifier for the news item.                                     |
| `signal`          | `string`         | Processed headline of the news item.                                     |
| `sentiment`       | `string`         | Tone of the news: `bullish`, `bearish`, or `neutral`.                    |
| `sentiment_value` | `number`         | Sentiment confidence score (0.0 to 1.0).                                 |
| `timestamp`       | `number`         | Unix timestamp (seconds) of when the item was processed.                 |
| `feed_categories` | `string[]`       | Feed categories the news item belongs to.                                |
| `short_context`   | `string`         | One-line summary of the broader context.                                 |
| `long_context`    | `string`         | Expanded context including related events, background, and significance. |
| `sources`         | `string[]`       | Source URLs and citations used for context enrichment.                   |
| `author`          | `string`         | The primary source (X/Twitter handle).                                   |
| `tokens`          | `string[]`       | Mentioned token symbols (e.g. `$BTC`, `$ETH`).                           |
| `tweet_url`       | `string`         | Direct link to the original post on X.                                   |
| `narrative_id`    | `string \| null` | ID of the narrative (story arc) this item belongs to, if any.            |

#### Status Codes

| Status Code | Description                                                       |
| ----------- | ----------------------------------------------------------------- |
| `200`       | Success                                                           |
| `400`       | Bad Request (invalid parameters)                                  |
| `401`       | Unauthorized (missing or invalid token)                           |
| `403`       | Forbidden (token does not have permission for the requested feed) |
| `404`       | Not Found (no data found for the specified parameters)            |

#### Example Requests

**cURL**

```bash
curl -X GET "https://ai-hub.cryptobriefing.com/news?token=YOUR_TOKEN&feed_categories=crypto,ai_agents&page=1&limit=40&from_date=2025-05-10&to_date=2025-05-15"
```

**JavaScript**

```javascript
const fetchNews = async () => {
  const response = await fetch(
    'https://ai-hub.cryptobriefing.com/news?feed_categories=crypto,ai_agents&page=1&limit=40',
    { headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
  );

  if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
  return response.json();
};

const newsItems = await fetchNews();
console.log(`Received ${newsItems.length} news items`);
newsItems.forEach(item => {
  console.log(`${new Date(item.timestamp * 1000).toLocaleString()}: ${item.signal}`);
});
```

***

### GET /news/{id}

Retrieve a single news item by its unique ID.

```bash
curl "https://ai-hub.cryptobriefing.com/news/3eb6c79c-6295-48e5-95ab-710b7ed66812?token=YOUR_TOKEN"
```

Returns a single object with the same fields as the `/news` response.

***

### GET /news-ticker-summary

Generate an AI-powered 24-hour summary for a specific token or project.

#### Query Parameters

| Parameter | Type     | Description                                                          |
| --------- | -------- | -------------------------------------------------------------------- |
| `token`   | `string` | Authorization token.                                                 |
| `ticker`  | `string` | **Required.** Token symbol or name (e.g. `SOL`, `LayerZero`, `ZRO`). |

#### Example

```bash
curl "https://ai-hub.cryptobriefing.com/news-ticker-summary?token=YOUR_TOKEN&ticker=SOL"
```

#### Response

```json
{
    "summary": "Solana saw increased network activity over the past 24 hours, with total value locked rising 3.2% to $8.1B. The Solana Foundation announced a new grant program targeting DePIN projects, while validator count reached an all-time high of 2,100 active nodes..."
}
```

***

## Recaps API

### GET /recaps

Retrieve an AI-generated summary of the most significant news from a given time window.

#### Query Parameters

| Parameter       | Type     | Description                                                                                                                                      |
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `token`         | `string` | Authorization token.                                                                                                                             |
| `feed_category` | `string` | Category code to get the recap for (e.g. `crypto`, `macro`).                                                                                     |
| `timeframe`     | `string` | News collection window. Available options: `12h`, `24h`. High-frequency categories (crypto, macro) use `12h`; others use `24h`. See table below. |

#### Recap Timeframes by Category

| Timeframe | Categories                                                                                                 |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| `12h`     | `ai`, `ai_agents`, `crypto`, `defi`, `machine_learning`, `macro`, `tech`, `virtuals`                       |
| `24h`     | `base`, `bitcoin`, `dats`, `ethereum`, `hyperliquid`, `on_chain_whale`, `perps`, `ripple`, `rwa`, `solana` |

#### Response Format

```json
{
    "feed_category": "crypto",
    "timeframe": "12h",
    "recap": "Bitcoin ETFs recorded $1.7 billion in net purchases this week, a pace that points to renewed institutional demand...",
    "created_at": "2026-02-16T14:50:18.849965Z"
}
```

#### Response Fields

| Field           | Type     | Description                                         |
| --------------- | -------- | --------------------------------------------------- |
| `feed_category` | `string` | The category the recap was generated for.           |
| `timeframe`     | `string` | The news collection window.                         |
| `recap`         | `string` | The recap content.                                  |
| `created_at`    | `string` | ISO 8601 timestamp of when the recap was generated. |

#### Example Requests

**cURL**

```bash
curl -X GET "https://ai-hub.cryptobriefing.com/recaps?token=YOUR_TOKEN&feed_category=crypto&timeframe=12h"
```

**JavaScript**

```javascript
const fetchRecap = async (category, timeframe = '12h') => {
  const response = await fetch(
    `https://ai-hub.cryptobriefing.com/recaps?feed_category=${category}&timeframe=${timeframe}`,
    { headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
  );

  if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
  return response.json();
};

const recap = await fetchRecap('crypto', '12h');
console.log(recap.recap);
```

***

## Narratives API

Narratives group related news items into story arcs — for example, all coverage of a single developing story across multiple sources and timeframes.

### GET /narratives

Retrieve all active narratives.

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" "https://ai-hub.cryptobriefing.com/narratives"
```

#### Response Format

```json
[
    {
        "narrative_id": "32a92ee7-0dc1-47b6-a095-d27e830bdd5d",
        "updated_at": "2026-02-16T14:30:00Z",
        "tag": "BlackRock Expands Bitcoin ETF to Australia",
        "summary": "BlackRock continues its global expansion of Bitcoin ETF offerings, with the latest launch targeting Australian investors...",
        "content": [
            {
                "id": "3eb6c79c-6295-48e5-95ab-710b7ed66812",
                "signal": "BlackRock plans to launch Bitcoin ETF in Australia",
                "sentiment": "bullish",
                "...": "same fields as /news response"
            }
        ]
    }
]
```

#### Response Fields

| Field          | Type     | Description                                                              |
| -------------- | -------- | ------------------------------------------------------------------------ |
| `narrative_id` | `string` | Unique identifier for the narrative.                                     |
| `updated_at`   | `string` | ISO 8601 timestamp of the last update.                                   |
| `tag`          | `string` | Short descriptive headline for the narrative.                            |
| `summary`      | `string` | Prose summary of the narrative arc.                                      |
| `content`      | `array`  | Array of news items in this narrative (same schema as `/news` response). |

### GET /narratives/{id}

Retrieve a single narrative by ID.

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" "https://ai-hub.cryptobriefing.com/narratives/32a92ee7-0dc1-47b6-a095-d27e830bdd5d"
```

***

## Articles API

### GET /articles

Retrieve AI-generated long-form articles with optional filtering.

#### Query Parameters

| Parameter  | Type     | Description                                           |
| ---------- | -------- | ----------------------------------------------------- |
| `token`    | `string` | Authorization token.                                  |
| `limit`    | `number` | Optional. Results per page (1–100). Defaults to `20`. |
| `page`     | `number` | Optional. Page number. Defaults to `1`.               |
| `category` | `string` | Optional. Filter by category.                         |
| `search`   | `string` | Optional. Search in headline and content.             |
| `type`     | `string` | Optional. Filter by article type.                     |

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" "https://ai-hub.cryptobriefing.com/articles?limit=5"
```

#### Response Format

```json
[
    {
        "id": "article-uuid",
        "data": { ... },
        "created_at": "2026-02-16T10:00:00Z"
    }
]
```

### GET /articles/{article\_id}

Retrieve a single article by ID.

***

## Feed Categories

### GET /available-feed-categories

List all available feed categories. **No authentication required.**

```bash
curl "https://ai-hub.cryptobriefing.com/available-feed-categories"
```

#### Response

```json
[
    { "code": "ai", "name": "AI", "recap_timeframe": "12h" },
    { "code": "ai_agents", "name": "AI Agents", "recap_timeframe": "12h" },
    { "code": "base", "name": "Base", "recap_timeframe": "24h" },
    { "code": "bitcoin", "name": "Bitcoin", "recap_timeframe": "24h" },
    { "code": "crypto", "name": "Crypto", "recap_timeframe": "12h" },
    { "code": "dats", "name": "DATs", "recap_timeframe": "24h" },
    { "code": "defi", "name": "DeFi", "recap_timeframe": "12h" },
    { "code": "ethereum", "name": "Ethereum", "recap_timeframe": "24h" },
    { "code": "hyperliquid", "name": "Hyperliquid", "recap_timeframe": "24h" },
    { "code": "machine_learning", "name": "Machine Learning", "recap_timeframe": "12h" },
    { "code": "macro", "name": "Macro", "recap_timeframe": "12h" },
    { "code": "on_chain_whale", "name": "On-Chain Whale Wallet Movements", "recap_timeframe": "24h" },
    { "code": "perps", "name": "Perp DEXs", "recap_timeframe": "24h" },
    { "code": "ripple", "name": "Ripple", "recap_timeframe": "24h" },
    { "code": "rwa", "name": "RWA", "recap_timeframe": "24h" },
    { "code": "solana", "name": "Solana", "recap_timeframe": "24h" },
    { "code": "tech", "name": "Tech", "recap_timeframe": "12h" },
    { "code": "token_listings", "name": "Token Listings", "recap_timeframe": null },
    { "code": "virtuals", "name": "Virtuals", "recap_timeframe": "12h" }
]
```

For detailed category descriptions, see [Categories](https://gloriaai.gitbook.io/gloria/docs/gloria-data-platform/categories).

***

## News WebSocket API

### Overview

The WebSocket API provides real-time news updates. Subscribe to specific feed categories and receive items as they are published.

### Connection

```
wss://ai-hub.cryptobriefing.com/ws/feed?token=YOUR_TOKEN
```

### Client to Server Messages

#### Subscribe to a Feed

```json
{
    "type": "subscribe",
    "feed_category": "crypto"
}
```

The server responds with a confirmation:

```json
{
    "type": "subscribed",
    "feed_category": "crypto"
}
```

#### Unsubscribe from a Feed

```json
{
    "type": "unsubscribe",
    "feed_category": "crypto"
}
```

### Server to Client Messages

#### Welcome Message

Upon successful connection:

```json
{
    "type": "connected",
    "message": "Connection established."
}
```

#### Data Message

When new content is available in a subscribed feed:

```json
{
    "type": "data",
    "content": {
        "id": "49683a70-ce26-46ef-9db8-218b6f9b9748",
        "signal": "Blink Charging to accept crypto payments at EV chargers",
        "sentiment": "neutral",
        "sentiment_value": 0.87,
        "timestamp": 1762247231.0,
        "feed_categories": ["crypto", "tech"],
        "short_context": "Blink Charging has announced that it will begin accepting cryptocurrency payments at its electric vehicle charging stations.",
        "long_context": "...",
        "sources": ["https://x.com/DeItaone/status/1963614452806238544"],
        "author": "DeItaone",
        "tokens": [],
        "tweet_url": "https://x.com/DeItaone/status/1963614452806238544",
        "narrative_id": null
    }
}
```

The `content` object has the same schema as items returned by the `/news` endpoint.

#### Error Message

```json
{
    "type": "error",
    "error": "Permission denied",
    "details": "No permission for crypto feed"
}
```

#### Ping/Pong

The server sends ping messages every 30 seconds. Respond with pong to keep the connection alive:

```json
// Server sends:
{ "type": "ping", "timestamp": 1148216.120805222 }

// Client responds:
{ "type": "pong", "timestamp": 1148216.120805222 }
```

### Message Types

| Type           | Direction       | Description                         |
| -------------- | --------------- | ----------------------------------- |
| `connected`    | Server → Client | Connection established              |
| `subscribe`    | Client → Server | Subscribe to a feed category        |
| `subscribed`   | Server → Client | Subscription confirmed              |
| `unsubscribe`  | Client → Server | Unsubscribe from a feed category    |
| `unsubscribed` | Server → Client | Unsubscription confirmed            |
| `data`         | Server → Client | News item (same schema as REST API) |
| `error`        | Server → Client | Error message                       |
| `ping`         | Server → Client | Keep-alive ping (every 30s)         |
| `pong`         | Client → Server | Keep-alive response                 |

### Connection Lifecycle

1. Connect with a valid token
2. Receive the welcome message
3. Subscribe to desired feeds
4. Receive real-time updates
5. Respond to ping messages to keep the connection alive
6. Unsubscribe when no longer interested
7. Connection auto-closes after 5 minutes of inactivity

### Error Handling

The server may close the connection with the following status codes:

* `1000`: Normal closure (server shutting down or inactive connection)
* `1008`: Policy violation (missing or invalid token)

### Client Example (JavaScript)

```javascript
const socket = new WebSocket('wss://ai-hub.cryptobriefing.com/ws/feed?token=YOUR_TOKEN');

socket.addEventListener('open', () => {
  console.log('Connected');

  // Subscribe to feeds
  socket.send(JSON.stringify({ type: 'subscribe', feed_category: 'crypto' }));
  socket.send(JSON.stringify({ type: 'subscribe', feed_category: 'ai_agents' }));
});

socket.addEventListener('message', (event) => {
  const message = JSON.parse(event.data);

  switch (message.type) {
    case 'data':
      console.log('New item:', message.content.signal);
      break;
    case 'subscribed':
      console.log(`Subscribed to ${message.feed_category}`);
      break;
    case 'error':
      console.error('Error:', message.error);
      break;
    case 'ping':
      socket.send(JSON.stringify({ type: 'pong', timestamp: message.timestamp }));
      break;
  }
});

socket.addEventListener('close', (event) => {
  console.log('Connection closed:', event.code, event.reason);
});
```

***

## Status Codes

| Code  | Description                                           |
| ----- | ----------------------------------------------------- |
| `200` | Success                                               |
| `400` | Bad Request (invalid parameters)                      |
| `401` | Unauthorized (missing or invalid token)               |
| `402` | Payment Required (x402 only)                          |
| `403` | Forbidden (token lacks permission for requested feed) |
| `404` | Not Found (no data for specified parameters)          |
| `500` | Internal Server Error                                 |
