# Feed

`GET /v1/feed`

What went live on bullpen.news, oldest first: stories, X posts, videos and investor letters in one list. Poll it with the last nextCursor. It runs two minutes behind. Any other parameter is refused.

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `since` | string | A time in UTC, such as 2026-10-28T14:00:00Z, for the first call: what went live from then on. It must be from 1970 on. Send exactly one of since and cursor. |
| `cursor` | string | The nextCursor the previous call returned, in place of since. Send exactly one of since and cursor. |
| `kind` | string | Only results of this kind. One of `story`, `x_post`, `video` or `letter`. |
| `ticker` | string | Only results about this company, by its ticker: the stories, X posts, videos and letters its page lists. |
| `limit` | integer, 1 to 100, default 10 | How many results to return, from 1 to 100. |

```sh
curl "https://api.bullpen.news/v1/feed?since=2026-10-30T18%3A00%3A00Z&limit=3" \
  -H "Authorization: Bearer $BULLPEN_KEY"
```

```python
import os, requests

r = requests.get(
    "https://api.bullpen.news/v1/feed",
    params={"since": "2026-10-30T18:00:00Z", "limit": 3},
    headers={"Authorization": f"Bearer {os.environ['BULLPEN_KEY']}"},
)
r.raise_for_status()
print(r.json())
```

```js
const r = await fetch('https://api.bullpen.news/v1/feed?since=2026-10-30T18%3A00%3A00Z&limit=3', {
	headers: { Authorization: `Bearer ${process.env.BULLPEN_KEY}` }
});
if (!r.ok) throw new Error((await r.json()).detail);
console.log(await r.json());
```

## What comes back

| Field | Type | Description |
| --- | --- | --- |
| `results` | array of [Story](/docs/reference#story), [XPost](/docs/reference#xpost), [Video](/docs/reference#video) or [Letter](/docs/reference#letter) | What went live, oldest first. Two minutes behind, and short when some are left out. |
| `tickers` | map of [TickerEntry](/docs/reference#tickerentry) | Each company the results name, by ticker. |
| `nextCursor` | string | Pass it as cursor for what goes live next. Always sent, even on an empty page. |

| Header | Sent with | Description |
| --- | --- | --- |
| `Request-Id` | every answer | This request's id, such as req_ followed by 24 letters and digits. Quote it to support. |
| `RateLimit-Policy` | 200, 400, 404, 429, 500, 503 | Your plan's quotas, per minute and per day (IETF draft-11). It may change to match the RFC. |
| `RateLimit` | 200, 400, 404, 429, 500, 503 | What each window has left, and the seconds until it resets (IETF draft-11). |
| `WWW-Authenticate` | 401 | Bearer realm="bullpen.news" |
| `Retry-After` | 429, 503 | How many seconds to wait. |

`GET /v1/feed?since=2026-10-30T18%3A00%3A00Z&limit=3`

```json
{
  "results": [
    {
      "id": "x:5248287",
      "kind": "x_post",
      "postId": "2116227609486856624",
      "url": "https://x.com/i/web/status/2116227609486856624",
      "published": "2026-10-30T17:55:54Z",
      "wentLive": "2026-10-30T18:01:20Z",
      "companies": [
        "PPIH"
      ]
    },
    {
      "id": "x:5248829",
      "kind": "x_post",
      "postId": "2116229734162174006",
      "url": "https://x.com/i/web/status/2116229734162174006",
      "published": "2026-10-30T18:04:20Z",
      "wentLive": "2026-10-30T18:06:06Z",
      "companies": [
        "TFC"
      ]
    },
    {
      "id": "x:5248828",
      "kind": "x_post",
      "postId": "2116229150726033736",
      "url": "https://x.com/i/web/status/2116229150726033736",
      "published": "2026-10-30T18:02:01Z",
      "wentLive": "2026-10-30T18:06:06Z",
      "companies": [
        "QMCO"
      ]
    }
  ],
  "tickers": {
    "PPIH": {
      "name": "Perma-Pipe International Holdings, Inc.",
      "sector": "Industrials",
      "marketCapUsd": 243400000,
      "bullpenUrl": "https://bullpen.news/ticker/PPIH"
    },
    "TFC": {
      "name": "Truist Financial CORP",
      "sector": "Financials",
      "marketCapUsd": 59151140000,
      "bullpenUrl": "https://bullpen.news/ticker/TFC"
    },
    "QMCO": {
      "name": "Quantum CORP",
      "sector": "Technology",
      "marketCapUsd": 798050000,
      "bullpenUrl": "https://bullpen.news/ticker/QMCO"
    }
  },
  "nextCursor": "WyJmZWVkIiwiZmVlZCIsIlJCTnZvMVd6WjRvUlJxMFciLFsxNzkzMzgzNTY2NjU2LCJpdGVtIiw1MjQ4ODI4XV0"
}
```

## Status codes

| Status | Meaning | Codes |
| --- | --- | --- |
| `200` | The answer. |  |
| `400` | A parameter is invalid or unknown (invalid_request), a key is in the URL (key_in_url), or a cursor is not this call's (invalid_cursor). | [`key_in_url`](/docs/errors#key_in_url), [`invalid_request`](/docs/errors#invalid_request), [`invalid_cursor`](/docs/errors#invalid_cursor) |
| `401` | No valid key (unauthorized), or a revoked one (revoked). | [`unauthorized`](/docs/errors#unauthorized), [`revoked`](/docs/errors#revoked) |
| `403` | Your account can't use this endpoint now: invite, disabled, terms, no_plan, ended, unpaid or tool. | [`no_plan`](/docs/errors#no_plan), [`ended`](/docs/errors#ended), [`unpaid`](/docs/errors#unpaid), [`terms`](/docs/errors#terms), [`disabled`](/docs/errors#disabled), [`invite`](/docs/errors#invite), [`tool`](/docs/errors#tool) |
| `404` | Nothing by that ticker, firm, id or day (not_found). | [`not_found`](/docs/errors#not_found) |
| `429` | Your plan's minute or day limit is reached (minute, day). | [`minute`](/docs/errors#minute), [`day`](/docs/errors#day) |
| `500` | Something went wrong on bullpen.news (internal). | [`internal`](/docs/errors#internal) |
| `503` | The API is paused (off), busy (ceiling) or having trouble (unavailable). Retry-After comes with all but off. | [`ceiling`](/docs/errors#ceiling), [`off`](/docs/errors#off), [`unavailable`](/docs/errors#unavailable) |

**Fresh:** Two minutes behind.
**History:** Anything that went live from 28 July 2026.
**Cost:** One call, however many results.
