VOL. I · API v1

Better RSS API

Read your feeds, items, and briefs programmatically. Mark things read, star them, subscribe or unsubscribe. Pro or Ultra tier only.

Base URL

https://www.better-rss.com/api/v1

Authentication

Every request sends a bearer token in the Authorization header:

Authorization: Bearer brss_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Generate tokens from Settings → API. Each token has read and/or write scopes and an optional expiry (30d, 90d, 1y, or never). The raw token is shown once on creation — save it immediately. Revoke any time from the same page.

Tokens belong to you. Don't share them. If one leaks, revoke it. Short-lived tokens are safer for scripts and one-off integrations.

How It Works

  1. Upgrade the account to Pro or Ultra.
  2. Open Settings → API and create a token.
  3. Pick read for list/sync clients, or add write for clients that mark items read, star items, subscribe, or unsubscribe.
  4. Store the token in your app or script environment as a secret.
  5. Call /api/v1/* with the bearer header shown above.

The API checks the token, token expiry, token scope, resource ownership, current Pro/Ultra status, and daily API cap on every request. If the account leaves Pro or Ultra, existing tokens stop working with 402 pro_required until API access is active again.

Quick Check

Use /me as a simple integration health check.

curl https://www.better-rss.com/api/v1/me \
  -H "Authorization: Bearer $BRSS_TOKEN"
{
  "email": "<account-email>",
  "tier": "pro",
  "scopes": ["read", "write"]
}

CORS

All /api/v1/* endpoints send Access-Control-Allow-Origin: *, so browser apps can call them directly with fetch(). The API uses bearer-token auth — no cookies are ever read — which is why permissive CORS is safe.

Errors

JSON errors on non-2xx responses:

{
  "error": {
    "code": "invalid_token",
    "message": "Token is invalid or revoked."
  }
}
  • 400 — malformed request
  • 401 — missing or bad token
  • 402 — Pro or Ultra tier required
  • 403 — token lacks the required scope
  • 404 — resource not found or not yours
  • 429 — rate limited
  • 500 — something broke on our side

Endpoints

GET /me

Who am I? Useful for client health checks.

curl https://www.better-rss.com/api/v1/me \
  -H "Authorization: Bearer $BRSS_TOKEN"

GET /stats

Reading statistics for the authenticated Pro or Ultra account. Item totals are an explicitly bounded recent snapshot (up to 25 feeds and four recent items per feed), while top-feed history covers up to 90 days. Inspect the response's scope object for truncation flags.

curl https://www.better-rss.com/api/v1/stats \
  -H "Authorization: Bearer $BRSS_TOKEN"

GET /items

List items from your subscribed feeds. Newest first.

Query params:

  • feed_id — restrict to one feed
  • unread=true — only unread items
  • starred=true — only starred items
  • since — ISO 8601 date; items published after this
  • limit — 1-100, default 50
  • cursor — preferred pagination; pass the opaque next_cursor from the previous response
  • offset — deprecated compatibility pagination, limited to 0-1000; do not combine with cursor; filtered lists (unread or starred) require a cursor
curl "https://www.better-rss.com/api/v1/items?unread=true&limit=25" \
	  -H "Authorization: Bearer $BRSS_TOKEN"

When has_more is true, request the next page with the returned next_cursor. Treat cursors as opaque values, URL-encode them, and do not construct or edit them. They carry the immutable database boundary needed to traverse items with identical publication metadata without skips or repeats.

{
  "items": [...],
  "limit": 25,
  "offset": 0,
  "total": 25,
  "has_more": true,
  "next_cursor": "eyJwdWJsaXNoZWRBdCI6Li4ufQ"
}

For backward compatibility, total remains numeric. It reports matching rows examined in the current bounded page window, not an unbounded count of every item in the account.

Aggregate item pages safely fan in at most 250 subscribed feeds per request. Accounts can retain more subscriptions; above that boundary, request one subscribed feed with feed_id. The API returns 422 item_fanout_limit rather than silently omitting feeds.

POST /items/:id/read

Mark an item read or unread. Scope: write.

curl -X POST "https://www.better-rss.com/api/v1/items/$ID/read" \
  -H "Authorization: Bearer $BRSS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"read": true}'

POST /items/:id/star

Star or unstar an item. Scope: write.

curl -X POST "https://www.better-rss.com/api/v1/items/$ID/star" \
  -H "Authorization: Bearer $BRSS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"starred": true}'

GET /feeds

List your subscriptions.

curl https://www.better-rss.com/api/v1/feeds \
  -H "Authorization: Bearer $BRSS_TOKEN"

POST /feeds/subscribe

Subscribe to a new feed. Returns the existing subscription if you're already subscribed. Scope: write.

curl -X POST https://www.better-rss.com/api/v1/feeds/subscribe \
  -H "Authorization: Bearer $BRSS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/feed.xml", "tag": "tech"}'

DELETE /feeds/:id

Unsubscribe. Scope: write.

curl -X DELETE "https://www.better-rss.com/api/v1/feeds/$FEED_ID" \
  -H "Authorization: Bearer $BRSS_TOKEN"

GET /briefs

List your AI-generated briefs. Newest first.

curl "https://www.better-rss.com/api/v1/briefs?limit=10" \
  -H "Authorization: Bearer $BRSS_TOKEN"

GET /briefs/:id

Full brief, including the markdown body.

curl "https://www.better-rss.com/api/v1/briefs/$BRIEF_ID" \
  -H "Authorization: Bearer $BRSS_TOKEN"

Stability

This is v1. If a field changes shape or a resource moves, we'll do it under /api/v2. v1 stays as-is.