# Endpoint reference

Every path in the API, generated from the [OpenAPI document](/api/v1/openapi.json) so it cannot describe an endpoint that does not exist.

All of them are `GET`, all of them take `Authorization: Bearer nk_live_…`, and all of them answer with the [standard envelope](/developers/docs/quickstart#what-comes-back) or the [standard error](/developers/docs/errors). Shared parameters and the story object are on the [paging and filters](/developers/docs/pagination) page.

## Every endpoint at a glance

| Endpoint | Scope | What it returns |
| --- | --- | --- |
| `GET /api/v1/stories` | stories | List stories |
| `GET /api/v1/stories/{ckey}` | stories | Story detail: members, timeline, framing |
| `GET /api/v1/stories/{ckey}/members` | stories | Every article in a cluster, paged |
| `GET /api/v1/threads` | stories | List running stories |
| `GET /api/v1/threads/{id}` | stories | One running story and its whole arc |
| `GET /api/v1/trending` | stories | Stories picking up speed |
| `GET /api/v1/blindspots` | stories | Coverage gaps, by camp |
| `GET /api/v1/sources` | sources | List newsrooms |
| `GET /api/v1/sources/{key}` | sources | One newsroom, with profile when computed |
| `GET /api/v1/sources/{key}/activity` | sources | Measured newsroom behaviour |
| `GET /api/v1/topics` | sources | The desk register with live volume |
| `GET /api/v1/changes` | stories | Incremental change feed |
| `GET /api/v1/search` | search | Search stories |
| `GET /api/v1/people` | people | People in the last 24 hours |
| `GET /api/v1/people/{id}` | people | One person, with every spelling folded into them |
| `GET /api/v1/brief` | brief | Today in Brief |
| `GET /api/v1/export` | export | Enterprise historical article and cluster export |
| `GET /api/v1/openapi.json` | — | This OpenAPI document |

## Stories

Clustered coverage.

### GET /api/v1/stories

List stories Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `state` | query | `string` | no | Cluster state. Unknown values are ignored. |
| `topic` | query | `string` | no | Desk id. Repeatable. |
| `source` | query | `string` | no | Newsroom key. Repeatable. |
| `since` | query | `integer` (0–30) | no | Jerusalem calendar dates back, 0-30, today inclusive. Non-integer or negative values are 400; values above 30 are clamped to 30. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/stories' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "id": 44,
      "url": "https://news.itsbaba.com/story/44/cabinet-approves",
      "headline": "Cabinet approves the deal",
      "summary": "Ministers voted after midnight.",
      "topic": "politics",
      "lang": "en",
      "publishedAt": "2026-09-01T08:00:00.000Z",
      "latestAt": "2026-09-01T08:00:00.000Z",
      "outlets": 3,
      "sides": {
        "centre": 2,
        "left": 1
      },
      "missingSides": [
        "haredi"
      ],
      "state": "consensus",
      "verdict": null,
      "lean": {
        "left": 1,
        "center": 2,
        "right": 0,
        "unrated": 0
      },
      "sources": [
        "ynet",
        "kan",
        "haaretz_he"
      ],
      "thread": null,
      "updatedAt": null
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid cursor, since, or limit; q belongs on /search; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/stories/{ckey}

Story detail: members, timeline, framing Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `ckey` | path | `integer` (1–) | yes | — |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/stories/123' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "id": 44,
  "url": "https://news.itsbaba.com/story/44/cabinet-approves",
  "headline": "Cabinet approves the deal",
  "summary": "Ministers voted after midnight.",
  "topic": "politics",
  "lang": "en",
  "publishedAt": "2026-09-01T08:00:00.000Z",
  "latestAt": "2026-09-01T08:00:00.000Z",
  "outlets": 0,
  "sides": {
    "centre": 2,
    "left": 1
  },
  "missingSides": [
    "haredi"
  ],
  "state": "consensus",
  "verdict": null,
  "lean": {
    "left": 1,
    "center": 2,
    "right": 0,
    "unrated": 0
  },
  "sources": [
    "ynet",
    "kan",
    "haaretz_he"
  ],
  "thread": null,
  "updatedAt": null,
  "members": [],
  "timeline": null,
  "framingNote": null
}
```

Other responses: `304` Not modified; `400` Invalid story id; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Story not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/stories/{ckey}/members

Every article in a cluster, paged Requires the `stories` scope.

The same member records /v1/stories/{ckey} returns, but paged and filterable by side or lean. side and lean come from the source registry rather than the row, so a filtered page can be shorter than its limit while still issuing a cursor.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `ckey` | path | `integer` (1–) | yes | — |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `side` | query | `left` \| `centre` \| `right` \| `haredi` \| `religious` \| `arab` \| `russian` \| `business` \| `official` | no | Only members from this camp. Unknown values are 400. |
| `lean` | query | `left` \| `center` \| `right` \| `unrated` | no | Only members with this political lean. Unknown values are 400. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/stories/123/members' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "storyId": 44,
  "data": [
    {
      "articleId": 9,
      "source": "ynet",
      "headline": "Cabinet approves the deal",
      "original": "הקבינט אישר",
      "publishedAt": "2026-09-01T08:00:00.000Z",
      "url": "https://www.ynet.co.il/a",
      "language": "he",
      "side": "centre",
      "lean": "center",
      "storyType": "report",
      "framing": {
        "subject": "Cabinet",
        "verb": "approves",
        "actor": null
      },
      "updatedAt": null
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified; `400` Invalid story id, cursor, side, lean, or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Story not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Threads

Running multi-day stories.

### GET /api/v1/threads

List running stories Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `minNodes` | query | `integer` (1–50, default `2`) | no | Smallest number of instalments a thread must have, 1-50. One cluster is not yet a running story, so the default is 2. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/threads' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "id": 7,
      "title": "The hostage deal",
      "nodes": 5,
      "days": 3,
      "firstAt": "2026-09-01T06:00:00.000Z",
      "newestAt": "2026-09-04T09:00:00.000Z",
      "newestStoryId": 44,
      "latest": {
        "id": 44,
        "url": "https://news.itsbaba.com/story/44/cabinet-approves",
        "headline": "Cabinet approves the deal",
        "summary": "Ministers voted after midnight.",
        "topic": "politics",
        "lang": "en",
        "publishedAt": "2026-09-01T08:00:00.000Z",
        "latestAt": "2026-09-01T08:00:00.000Z",
        "outlets": 3,
        "sides": {
          "centre": 2,
          "left": 1
        },
        "missingSides": [
          "haredi"
        ],
        "state": "consensus",
        "verdict": null,
        "lean": {
          "left": 1,
          "center": 2,
          "right": 0,
          "unrated": 0
        },
        "sources": [
          "ynet",
          "kan",
          "haaretz_he"
        ],
        "thread": null,
        "updatedAt": null
      }
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid cursor, minNodes, or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/threads/{id}

One running story and its whole arc Requires the `stories` scope.

Every instalment we still hold, newest first, in the same shape as a story on /v1/stories. The arc is bounded by limit and returned whole rather than paged.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `id` | path | `integer` (1–) | yes | — |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `limit` | query | `integer` (1–100, default `40`) | no | Instalments to return, 1-100. Non-integer or negative values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/threads/123' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "id": 7,
  "title": "The hostage deal",
  "nodes": 5,
  "days": 3,
  "firstAt": "2026-09-01T06:00:00.000Z",
  "newestAt": "2026-09-04T09:00:00.000Z",
  "newestStoryId": 44,
  "lang": "en",
  "arc": [
    {
      "id": 44,
      "url": "https://news.itsbaba.com/story/44/cabinet-approves",
      "headline": "Cabinet approves the deal",
      "summary": "Ministers voted after midnight.",
      "topic": "politics",
      "lang": "en",
      "publishedAt": "2026-09-01T08:00:00.000Z",
      "latestAt": "2026-09-01T08:00:00.000Z",
      "outlets": 3,
      "sides": {
        "centre": 2,
        "left": 1
      },
      "missingSides": [
        "haredi"
      ],
      "state": "consensus",
      "verdict": null,
      "lean": {
        "left": 1,
        "center": 2,
        "right": 0,
        "unrated": 0
      },
      "sources": [
        "ynet",
        "kan",
        "haaretz_he"
      ],
      "thread": null,
      "updatedAt": null
    }
  ]
}
```

Other responses: `304` Not modified; `400` Invalid thread id or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Thread not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Trending and blindspots

What is accelerating right now.

### GET /api/v1/trending

Stories picking up speed Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `metric` | query | `acceleration` \| `velocity` \| `heat` \| `importance` | no | Which computed signal orders the page. Unknown values are 400. |
| `window` | query | `integer` (15–10080) | no | How many minutes back to consider a state row current, 15-10080. Values below 15 are raised to 15; above 10080 are clamped. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Ranked by the same metric, so a cursor is only valid for the metric that produced it. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/trending' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "storyId": 44,
      "state": "breaking",
      "label": null,
      "importance": 8.4,
      "heat": 5.1,
      "velocity": 6,
      "acceleration": 4,
      "significance": 4,
      "sides": {
        "centre": 2,
        "left": 1
      },
      "missingSides": [
        "haredi"
      ],
      "threadId": null,
      "computedAt": "2026-09-04T11:55:00.000Z",
      "rank": 4,
      "story": {
        "id": 44,
        "url": "https://news.itsbaba.com/story/44/cabinet-approves",
        "headline": "Cabinet approves the deal",
        "summary": "Ministers voted after midnight.",
        "topic": "politics",
        "lang": "en",
        "publishedAt": "2026-09-01T08:00:00.000Z",
        "latestAt": "2026-09-01T08:00:00.000Z",
        "outlets": 3,
        "sides": {
          "centre": 2,
          "left": 1
        },
        "missingSides": [
          "haredi"
        ],
        "state": "consensus",
        "verdict": null,
        "lean": {
          "left": 1,
          "center": 2,
          "right": 0,
          "unrated": 0
        },
        "sources": [
          "ynet",
          "kan",
          "haaretz_he"
        ],
        "thread": null,
        "updatedAt": null
      }
    }
  ],
  "nextCursor": null,
  "metric": "acceleration",
  "windowMinutes": 180,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid cursor, metric, window, or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/blindspots

Coverage gaps, by camp Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `state` | query | `blindspot` \| `undercovered` | no | Repeatable. Unknown values are 400, unlike on /v1/stories, because this resource is only about these two. |
| `side` | query | `left` \| `centre` \| `right` \| `haredi` \| `religious` \| `arab` \| `russian` \| `business` \| `official` | no | Return only stories the named camp did not run. Unknown values are 400. |
| `window` | query | `integer` (15–10080) | no | How many minutes back to consider a state row current, 15-10080. Values below 15 are raised to 15; above 10080 are clamped. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/blindspots' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "storyId": 44,
      "state": "blindspot",
      "label": "Not in the Haredi press",
      "importance": 8.4,
      "heat": 5.1,
      "velocity": 6,
      "acceleration": 4,
      "significance": 4,
      "sides": {
        "centre": 2,
        "left": 1
      },
      "missingSides": [
        "haredi"
      ],
      "threadId": null,
      "computedAt": "2026-09-04T11:55:00.000Z",
      "gaps": [
        {
          "side": "haredi",
          "label": "Haredi press"
        }
      ],
      "story": {
        "id": 44,
        "url": "https://news.itsbaba.com/story/44/cabinet-approves",
        "headline": "Cabinet approves the deal",
        "summary": "Ministers voted after midnight.",
        "topic": "politics",
        "lang": "en",
        "publishedAt": "2026-09-01T08:00:00.000Z",
        "latestAt": "2026-09-01T08:00:00.000Z",
        "outlets": 3,
        "sides": {
          "centre": 2,
          "left": 1
        },
        "missingSides": [
          "haredi"
        ],
        "state": "consensus",
        "verdict": null,
        "lean": {
          "left": 1,
          "center": 2,
          "right": 0,
          "unrated": 0
        },
        "sources": [
          "ynet",
          "kan",
          "haaretz_he"
        ],
        "thread": null,
        "updatedAt": null
      }
    }
  ],
  "nextCursor": null,
  "states": [
    "blindspot",
    "undercovered"
  ],
  "side": null,
  "windowMinutes": 1440,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid cursor, state, side, window, or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Newsrooms

Newsrooms in the wire.

### GET /api/v1/sources

List newsrooms Requires the `sources` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/sources' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "key": "ynet",
      "name": "Ynet",
      "language": "he",
      "side": "centre",
      "lean": "center",
      "place": "Rishon LeZion",
      "profile": null
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z"
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/sources/{key}

One newsroom, with profile when computed Requires the `sources` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `key` | path | `string` | yes | — |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/sources/ynet' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

Other responses: `304` Not modified; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Source not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/sources/{key}/activity

Measured newsroom behaviour Requires the `sources` scope.

What a newsroom did rather than what its profile says it is: crawl outcomes over the window, and the byline, originality, opinion, press-release and filing-lag rates the profile cron computed over its own 30-day window. successRate is over finished runs only, so a crawl still in flight never reads as a failure.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `key` | path | `string` | yes | — |
| `days` | query | `integer` (1–30, default `7`) | no | Days back, 1-30. Non-integer or negative values are 400; values above 30 are clamped. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/sources/ynet/activity' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "key": "ynet",
  "windowDays": 7,
  "crawl": {
    "windowDays": 7,
    "runs": 249,
    "okRuns": 246,
    "errorRuns": 2,
    "abortedRuns": 0,
    "runningRuns": 1,
    "discovered": 5120,
    "scraped": 980,
    "newArticles": 412,
    "errors": 14,
    "lastRunAt": "2026-09-04T11:50:00.000Z",
    "lastFinishedAt": "2026-09-04T11:51:00.000Z",
    "successRate": 0.9919
  },
  "behaviour": {
    "windowDays": 30,
    "stories": 400,
    "bylineRate": 0.8,
    "originalRate": 0.6,
    "opinionShare": 0.1,
    "pressReleaseShare": 0.05,
    "medianLagMinutes": 20,
    "computedAt": "2026-09-04T04:00:00.000Z"
  },
  "generatedAt": "2026-09-04T12:00:00.000Z"
}
```

Other responses: `304` Not modified; `400` Invalid days; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Source not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Topics and changes

The desk register with live volume.

### GET /api/v1/topics

The desk register with live volume Requires the `sources` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `days` | query | `integer` (1–7, default `1`) | no | Days back, 1-7. Non-integer or negative values are 400; values above 7 are clamped. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/topics' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "id": "politics",
      "label": "Politics",
      "hue": 25,
      "articles": 987
    }
  ],
  "nextCursor": null,
  "days": 1,
  "generatedAt": "2026-09-04T12:00:00.000Z"
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid days; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/changes

Incremental change feed Requires the `stories` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `since` | query | `string` | yes | ISO 8601 instant. Runs forward in time from here. Values older than seven days are raised to seven days ago, which is as far back as cluster state is kept warm. |
| `limit` | query | `integer` (1–500, default `100`) | no | Page size, 1-500. Non-integer or negative values are 400; values above 500 are clamped. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/changes?since=…' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "storyId": 44,
      "state": "consensus",
      "label": null,
      "missingSides": [],
      "threadId": 7,
      "changedAt": "2026-09-04T11:55:00.000Z"
    }
  ],
  "nextCursor": null,
  "checkpoint": "2026-09-04T11:55:00.000Z",
  "since": "2026-09-04T00:00:00.000Z",
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 100
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Missing or invalid since, or invalid cursor or limit; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Search

Headline and entity search.

### GET /api/v1/search

Search stories Requires the `search` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `q` | query | `string` (2–120 chars) | yes | 2-120 characters. Matches title, summary, and entities. Search lives on /search only. |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |
| `state` | query | `string` | no | Cluster state. Unknown values are ignored. |
| `topic` | query | `string` | no | Desk id. Repeatable. |
| `source` | query | `string` | no | Newsroom key. Repeatable. |
| `since` | query | `integer` (0–30) | no | Jerusalem calendar dates back, 0-30, today inclusive. Non-integer or negative values are 400; values above 30 are clamped to 30. |
| `limit` | query | `integer` (1–100, default `40`) | no | Page size. Non-integer or negative values are 400; values above 100 are clamped to 100 and echoed as page.limit. |
| `cursor` | query | `string` | no | Opaque keyset cursor from a previous page nextCursor. Malformed values are 400. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/search?q=…' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "id": 44,
      "url": "https://news.itsbaba.com/story/44/cabinet-approves",
      "headline": "Cabinet approves the deal",
      "summary": "Ministers voted after midnight.",
      "topic": "politics",
      "lang": "en",
      "publishedAt": "2026-09-01T08:00:00.000Z",
      "latestAt": "2026-09-01T08:00:00.000Z",
      "outlets": 3,
      "sides": {
        "centre": 2,
        "left": 1
      },
      "missingSides": [
        "haredi"
      ],
      "state": "consensus",
      "verdict": null,
      "lean": {
        "left": 1,
        "center": 2,
        "right": 0,
        "unrated": 0
      },
      "sources": [
        "ynet",
        "kan",
        "haaretz_he"
      ],
      "thread": null,
      "updatedAt": null
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z",
  "limit": 40
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `400` Invalid cursor, since, or limit, or q outside 2-120 characters; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## People

People named in the last 24 hours.

### GET /api/v1/people

People in the last 24 hours Requires the `people` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/people' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "data": [
    {
      "id": 41,
      "name": "A person",
      "canonicalName": null,
      "role": null,
      "avatarUrl": null,
      "mentions": 4
    }
  ],
  "nextCursor": null,
  "lang": "en",
  "generatedAt": "2026-09-04T12:00:00.000Z"
}
```

Other responses: `304` Not modified. Same ETag and Cache-Control as 200, empty body; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

### GET /api/v1/people/{id}

One person, with every spelling folded into them Requires the `people` scope.

Identity and aliases. recentCoverage is always null: resolving a person to their stories has no index behind it today, and the field is in the contract so filling it later is additive.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `id` | path | `integer` (1–) | yes | — |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/people/123' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "id": 2,
  "wikidataId": "Q57553",
  "name": "Benjamin Netanyahu",
  "nameEn": "Benjamin Netanyahu",
  "nameHe": "בנימין נתניהו",
  "role": "Prime Minister of Israel",
  "mentions": 1641,
  "avatarUrl": null,
  "aliases": [
    {
      "alias": "netanyahu",
      "display": "Netanyahu",
      "status": "resolved"
    }
  ],
  "updatedAt": "2026-09-04T04:00:00.000Z",
  "recentCoverage": null
}
```

Other responses: `304` Not modified; `400` Invalid person id; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` Person not found; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Daily brief

Today in Brief.

### GET /api/v1/brief

Today in Brief Requires the `brief` scope.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `lang` | query | `en` \| `he` | no | Output language. Hebrew falls back to English per field when a row is missing. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/brief' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

```json Response
{
  "lang": "en",
  "generatedAt": "2026-09-04T04:30:00.000Z",
  "intro": "Overnight.",
  "items": [
    {
      "storyUrl": "https://news.itsbaba.com/1/a-story",
      "headline": "A story",
      "text": "It happened."
    }
  ]
}
```

Other responses: `304` Not modified; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `404` No brief is available; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## Bulk export

### GET /api/v1/export

Enterprise historical article and cluster export Requires the `export` scope.

Inclusive UTC date range, at most 366 days. Up to 500 article records per page, grouped by storyId. Snapshot fixes the insertion cutoff; corrections and current cluster state may change during pagination. No full publisher article bodies.

| Parameter | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `from` | query | `string` | yes | — |
| `to` | query | `string` | yes | — |
| `format` | query | `csv` \| `jsonl` | no | — |
| `lang` | query | `en` \| `he` | no | Export only stored records in this language; no fallback. |
| `cursor` | query | `string` | no | X-Next-Cursor from the previous page, with unchanged from/to/lang filters. |

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/export?from=…&to=…' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```

Other responses: `400` Invalid dates, range, format, language, or cursor; `401` Missing or invalid API key; `403` This key cannot access this endpoint; `429` Rate limit or monthly quota exceeded; `503` The News API is temporarily unavailable.

## The OpenAPI document

### GET /api/v1/openapi.json

This OpenAPI document

```bash Request
curl -s 'https://news.itsbaba.com/api/v1/openapi.json' \
  -H "Authorization: Bearer $BABA_NEWS_API_KEY"
```
