The SlashFeed API is organized around REST with predictable resource-oriented URLs, JSON bodies, and standard HTTP verbs and response codes.
https://slashfeed.app/api/v1
application/json.
Base URL
https://slashfeed.app/api/v1
Request
curl https://slashfeed.app/api/v1/me \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"id": "019e02ab-...",
"email": "[email protected]",
"confirmed": true,
"created_at": "2025-01-01T00:00:00Z"
}
Create and manage tokens from Settings → API Tokens.
Tokens are prefixed
sk_live_
and shown only once
— treat them like passwords.
Pass your token in the
Authorization
header:
Authorization: Bearer sk_live_xxxx
Requests without a valid token return HTTP 401.
Authenticated request
curl https://slashfeed.app/api/v1/me \ -H "Authorization: Bearer sk_live_Rn8KdPwXmZq5"
401 — invalid token
{
"error": "unauthorized",
"message": "Invalid or missing API token"
}
Every API token is limited to 1,000 requests per hour, tracked via an in-memory ETS counter (Hammer — no Redis required).
X-RateLimit-Limit
integer
Maximum requests per hour (always 1000).
X-RateLimit-Remaining
integer
Requests remaining in the current window.
Retry-After
integer
Seconds to wait. Present only on 429 responses.
Response headers
X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 987
429 — limit exceeded
{
"error": "too_many_requests",
"message": "Rate limit exceeded",
"retry_after": 3600
}
BoringRSS uses standard HTTP status codes.
2xx
= success, 4xx
= client error, 5xx
= server error.
| 200 | OK | Success. |
| 201 | Created | Resource was created. |
| 204 | No Content | Successful delete — no body. |
| 401 | Unauthorized | No valid API token. |
| 404 | Not Found | Resource does not exist. |
| 422 | Unprocessable Entity | Validation failed. |
| 429 | Too Many Requests | Rate limit exceeded. |
| 500 | Server Error | Something went wrong. |
Error object
{
"error": "not_found",
"message": "Resource not found"
}
422 — validation error
{
"error": "unprocessable_entity",
"message": "Validation failed",
"errors": {
"name": ["can't be blank"],
"url": ["must be a valid HTTP or HTTPS URL"]
}
}
Retrieve information about the API token's owner.
/api/v1/me
Returns the account object for the token owner.
id
string
Unique user UUID v7.
email
string
User email address.
confirmed
boolean
Email confirmed status.
created_at
datetime
ISO 8601 creation timestamp.
Request
curl https://slashfeed.app/api/v1/me \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"id": "019e02ab-89ab-7f73-a445-12c863138d21",
"email": "[email protected]",
"confirmed": true,
"created_at": "2025-01-15T09:00:00Z"
}
A Feed object represents one of your RSS/Atom subscriptions.
The id
is the subscription
UUID, not the underlying feed's canonical UUID.
id
string
Subscription UUID.
feed_id
string
Underlying feed UUID (shared across subscribers).
url
string
Feed URL.
title
string
Feed title.
custom_title
string
Your personal override title.
category_id
string
Assigned category UUID, or null.
unread_count
integer
Live unread entry count.
last_fetched_at
datetime
Last successful fetch timestamp.
fetch_error
string
Last fetch error, or null.
Feed object
{
"id": "019e02ab-...",
"feed_id": "019e01ff-...",
"url": "https://example.com/feed.xml",
"title": "Example Blog",
"custom_title": null,
"category_id": "019e03aa-...",
"unread_count": 12,
"last_fetched_at": "2025-01-15T08:30:00Z",
"fetch_error": null
}
/api/v1/feeds
Returns all subscribed feeds with live unread counts.
Request
curl https://slashfeed.app/api/v1/feeds \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"feeds": [
{
"id": "019e02ab-...",
"title": "Example Blog",
"unread_count": 12
}
]
}
/api/v1/feeds
Subscribe to a new feed by URL.
url
string
required
RSS or Atom feed URL.
category_id
string
Category UUID to assign the subscription.
custom_title
string
Override the feed title for your account.
Request
curl -X POST https://slashfeed.app/api/v1/feeds \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/feed.xml"}'
Response
{
"feed": {
"id": "019e02ab-...",
"url": "https://example.com/feed.xml",
"unread_count": 0
}
}
/api/v1/feeds/:id
Retrieve a specific feed subscription.
Request
curl https://slashfeed.app/api/v1/feeds/019e02ab-... \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"id": "019e02ab-...",
"feed_id": "019e01ff-...",
"url": "https://example.com/feed.xml",
"title": "Example Blog",
"custom_title": null,
"category_id": "019e03aa-...",
"unread_count": 12,
"last_fetched_at": "2025-01-15T08:30:00Z",
"fetch_error": null
}
/api/v1/feeds/:id
Unsubscribe. Feed record and entries are preserved.
Request
curl -X DELETE https://slashfeed.app/api/v1/feeds/019e02ab-... \ -H "Authorization: Bearer sk_live_xxx"
Response
HTTP 204 No Content
/api/v1/feeds/:id/refresh
Enqueue a background fetch. Poll last_fetched_at to track completion.
Request
curl -X POST https://slashfeed.app/api/v1/feeds/019e02ab-.../refresh \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"message": "Feed refresh enqueued"
}
Individual articles from your subscribed feeds.
id
string
Entry UUID.
feed_id
string
Feed UUID this entry belongs to.
title
string
Article title.
url
string
Link to the original article.
summary
string
Sanitised HTML excerpt.
author
string
Author name, if provided.
published_at
datetime
Publication timestamp.
read
boolean
Whether you have read this entry.
starred
boolean
Whether you have starred this entry.
saved_for_later
boolean
In your Read Later list.
Entry object
{
"id": "019e05cc-...",
"feed_id": "019e01ff-...",
"title": "Hello, Elixir 2.0",
"url": "https://example.com/posts/hello",
"author": "Jane Doe",
"published_at": "2025-01-14T18:00:00Z",
"read": false,
"starred": false,
"saved_for_later": false
}
/api/v1/entries
Paginated list of entries across all subscribed feeds.
unread_only
boolean
Return only unread entries (default: false).
feed_id
string
Filter to a specific feed subscription.
category_id
string
Filter to a category.
limit
integer
Page size (default 50, max 200).
offset
integer
Pagination offset (default 0).
Request
curl "https://slashfeed.app/api/v1/entries?unread_only=true&limit=20" \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"total": 142,
"entries": [
{
"id": "019e05cc-...",
"title": "Hello, Elixir 2.0",
"read": false
}
]
}
/api/v1/entries/:id
Retrieve a single entry by its UUID.
Request
curl https://slashfeed.app/api/v1/entries/019e05cc-... \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"id": "019e05cc-...",
"feed_id": "019e01ff-...",
"title": "Hello, Elixir 2.0",
"url": "https://example.com/posts/hello",
"author": "Jane Doe",
"published_at": "2025-01-14T18:00:00Z",
"read": false,
"starred": false,
"saved_for_later": false
}
/api/v1/entries/:id/read
Mark a single entry as read. Idempotent.
Request
curl -X POST https://slashfeed.app/api/v1/entries/019e05cc-.../read \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"entry": { "id": "019e05cc-...", "read": true }
}
/api/v1/entries/:id/read
Mark a single entry as unread.
Request
curl -X DELETE https://slashfeed.app/api/v1/entries/019e05cc-.../read \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"entry": { "id": "019e05cc-...", "read": false }
}
/api/v1/entries/read
Bulk mark as read. Pass feed_id or an array of entry_ids.
feed_id
string
Mark all unread entries in this feed as read.
entry_ids
array
Array of entry UUIDs to mark as read.
Request
curl -X POST https://slashfeed.app/api/v1/entries/read \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"feed_id": "019e02ab-..."}'
Response
{
"marked": 23
}
Organise subscriptions into named groups. Each subscription can belong to at most one category.
id
string
Category UUID.
name
string
Unique name per user.
color
string
Hex colour code, e.g. #6366f1.
position
integer
Display order (lower = first).
Category object
{
"id": "019e03aa-...",
"name": "Tech News",
"color": "#6366f1",
"position": 0
}
/api/v1/categories
Returns all categories ordered by position.
Request
curl https://slashfeed.app/api/v1/categories \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"categories": [
{ "id": "019e03aa-...", "name": "Tech News", "color": "#6366f1" }
]
}
/api/v1/categories
Create a new category.
name
string
required
Category name — unique per account.
color
string
Hex colour code, e.g. #6366f1.
Request
curl -X POST https://slashfeed.app/api/v1/categories \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"name": "Tech News", "color": "#6366f1"}'
Response
{
"category": { "id": "019e03aa-...", "name": "Tech News", "color": "#6366f1" }
}
/api/v1/categories/:id
Update a category. Only fields you send are changed.
name
string
New name.
color
string
New hex colour.
Request
curl -X PUT https://slashfeed.app/api/v1/categories/019e03aa-... \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"name": "Technology"}'
Response
{
"category": { "id": "019e03aa-...", "name": "Technology" }
}
/api/v1/categories/:id
Delete a category. Subscriptions have their category_id set to null.
Request
curl -X DELETE https://slashfeed.app/api/v1/categories/019e03aa-... \ -H "Authorization: Bearer sk_live_xxx"
Response
HTTP 204 No Content
/api/v1/tags
Returns all tags sorted alphabetically.
Request
curl https://slashfeed.app/api/v1/tags \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"tags": [
{ "id": "019e07bb-...", "name": "must-read", "color": "#10b981" }
]
}
/api/v1/tags
Create a new tag.
name
string
required
Tag name — unique per account.
color
string
Hex colour code.
Request
curl -X POST https://slashfeed.app/api/v1/tags \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"name": "must-read"}'
Response
{
"tag": { "id": "019e07bb-...", "name": "must-read" }
}
/api/v1/tags/:id
Delete a tag and remove it from all entries and subscriptions.
Request
curl -X DELETE https://slashfeed.app/api/v1/tags/019e07bb-... \ -H "Authorization: Bearer sk_live_xxx"
Response
HTTP 204 No Content
Reading statistics for the authenticated user over the last 30 days.
/api/v1/stats
Returns total reads, reading streaks, and most-read feeds.
Request
curl https://slashfeed.app/api/v1/stats \ -H "Authorization: Bearer sk_live_xxx"
Response
{
"total_reads_30d": 214,
"reading_streak": { "current": 7, "longest": 23 },
"most_read_feeds": [
{ "feed_id": "019e01ff-...", "title": "Hacker News", "count": 88 }
]
}
BoringRSS implements a subset of the
Miniflux v1 API
at /v1/
—
connect any Miniflux-compatible client without code changes.
https://yourserver.com/v1
X-Auth-Token
header, or as the password in HTTP Basic Auth (any username).
| Method | Path | Description |
|---|---|---|
| GET | /v1/me | Current user |
| GET | /v1/feeds | List feeds |
| POST | /v1/feeds | Subscribe to feed |
| GET | /v1/feeds/:id | Get feed |
| DELETE | /v1/feeds/:id | Delete feed |
| PUT | /v1/feeds/:id/refresh | Refresh feed |
| POST | /v1/feeds/refresh | Refresh all feeds |
| GET | /v1/feeds/:id/entries | Get feed entries |
| GET | /v1/entries | List entries |
| GET | /v1/entries/:id | Get entry |
| PUT | /v1/entries | Update entries |
| GET | /v1/categories | List categories |
| POST | /v1/categories | Create category |
| DELETE | /v1/categories/:id | Delete category |
X-Auth-Token header
curl https://yourserver.com/v1/me \ -H "X-Auth-Token: sk_live_xxx"
HTTP Basic Auth (alternative)
# Any username, token as password curl https://yourserver.com/v1/feeds \ -u "user:sk_live_xxx"
User object (Miniflux format)
{
"id": 1234567,
"username": "[email protected]",
"is_admin": false,
"language": "en_US",
"timezone": "UTC",
"theme": "light",
"entry_sorting_direction": "desc"
}
Implements the
Fever RSS protocol
at POST /fever
—
for Reeder 5, NetNewsWire, ReadKit, and more.
Setup
https://yourserver.com/fever
as the server URL.
api_key=MD5(email:fever_password)
as a POST parameter.
| ?feeds | All subscribed feeds |
| ?groups | Categories as Fever groups |
| ?items | Entries (paginated: since_id, max_id, with_ids) |
| ?unread_item_ids | Comma-separated unread entry IDs |
| ?saved_item_ids | Comma-separated starred entry IDs |
| ?mark=item… | Mark entry read/unread/saved/unsaved |
| ?mark=feed… | Mark all feed entries as read |
| ?mark=group… | Mark all category entries as read |
Fever request
curl -X POST "https://yourserver.com/fever?feeds" \ -d "api_key=5f4dcc3b5aa765d61d8327deb882cf99"
Successful response
{
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": "1736928000",
"feeds": [
{
"id": 12345678,
"title": "Example Blog",
"url": "https://example.com/feed.xml",
"is_spark": 0
}
]
}
Connect Claude Desktop, Cursor, Zed, or any MCP-compatible client to your personal RSS reading data. The MCP endpoint gives your AI assistant real-time access to your subscribed feeds, unread entries, reading stats, and more.
https://slashfeed.app/api/mcp
| Tool | Description |
|---|---|
| list_my_feeds | All subscribed feeds with category, fetch status, and error state |
| list_my_entries | Recent unread entries, filterable by feed or category |
| search_my_entries | Full-text search across your subscribed feeds |
| subscribe_to_feed | Add a new RSS/Atom feed to your subscriptions |
| mark_entry_read | Mark a single entry as read |
| save_for_later | Save an entry to your Read Later list |
| get_my_stats | Reading streak, total reads, and top feeds for a date window |
Example tool call
POST /api/mcp
Authorization: Bearer <token>
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_my_feeds",
"arguments": {}
}
}
Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "[019e…] Hacker News [Tech]\n url: https://news.ycombinator.com/rss | last_fetched: 2026-05-21T08:00:00Z\n\n[019f…] The Register\n url: https://www.theregister.com/headlines.atom | last_fetched: 2026-05-21T07:45:00Z"
}
]
}
}
The preferred authentication method. Your LLM client opens a browser, you sign in with your existing BoringRSS account, and the client stores/refreshes tokens automatically — no credential management on your end.
/admin/oauth/clients).
client_id
and the endpoint URL (see Client Config section).
/.well-known/openid-configuration
.
https://slashfeed.app/.well-known/openid-configuration
.
Access tokens expire after 1 hour; refresh tokens last 30 days.
Register a client (run once)
mix boring_rss.oauth.create_client \ --name "Claude Desktop" \ --redirect-uri "http://localhost:8888/callback" \ --grants "authorization_code,refresh_token" \ --scopes "feeds:read,entries:read,entries:write,categories:read,stats:read" \ --pkce \ --access-ttl 3600 \ --refresh-ttl 2592000 # → client_id: 019f1a2b-... (no secret — PKCE public client)
PKCE authorization flow
# 1. Generate PKCE pair (your MCP client does this automatically)
code_verifier = random 32-byte hex string
code_challenge = BASE64URL(SHA-256(code_verifier))
# 2. Open in browser
GET /oauth/authorize
?client_id=019f1a2b-...
&redirect_uri=http://localhost:8888/callback
&response_type=code
&scope=feeds:read+entries:read+stats:read
&code_challenge=<challenge>
&code_challenge_method=S256
# 3. User logs in → redirected to callback with ?code=…
# 4. Exchange code for tokens
POST /oauth/token
grant_type=authorization_code
&code=<code>
&code_verifier=<verifier>
&client_id=019f1a2b-...
# → {"access_token": "…", "expires_in": 3600, "refresh_token": "…"}
Refresh an expired token
POST /oauth/token grant_type=refresh_token &refresh_token=<refresh_token> &client_id=019f1a2b-...
A simpler alternative for headless scripts, one-person self-hosting setups, or any client that can't complete an OAuth browser flow. Generate a permanent 64-character token in Settings and paste it once.
Authorization: Bearer <token>
header in your MCP client config.
?token=<value>
to the URL —
but only over HTTPS.
Rotating (re-generating) a token immediately invalidates the previous one.
Generate & use
# In Settings → MCP Access Token, click "Generate Token" # Copy the 64-character token shown once: # a3f9e2b1c4d5... (64 hex chars) # Use it as a Bearer token in any HTTP client: curl -N https://slashfeed.app/api/mcp \ -H "Authorization: Bearer a3f9e2b1c4d5..."
Complete configuration examples for the three most popular
MCP-compatible AI clients. Replace
019f1a2b-...
with the client_id
printed by
mix boring_rss.oauth.create_client
.
Claude Desktop
Add the boring-rss
block to your
claude_desktop_config.json
file.
Cursor
Add to
~/.cursor/mcp.json
under the mcpServers
key.
Zed
Add to
~/.config/zed/settings.json
inside the assistant
key.
Personal Token (all clients)
For clients that don't support OAuth, use the bearer header approach —
pass the token directly in the
headers
map instead.
For self-hosted instances, replace
slashfeed.app
with your own domain.
Claude Desktop
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"slashfeed": {
"type": "http",
"url": "https://slashfeed.app/api/mcp",
"oauth": {
"client_id": "019f1a2b-...",
"authorization_url": "https://slashfeed.app/oauth/authorize",
"token_url": "https://slashfeed.app/oauth/token",
"scope": "feeds:read entries:read entries:write categories:read stats:read"
}
}
}
}
Cursor
// ~/.cursor/mcp.json
{
"mcpServers": {
"slashfeed": {
"type": "http",
"url": "https://slashfeed.app/api/mcp",
"oauth": {
"client_id": "019f1a2b-...",
"authorization_url": "https://slashfeed.app/oauth/authorize",
"token_url": "https://slashfeed.app/oauth/token",
"scope": "feeds:read entries:read entries:write categories:read stats:read"
}
}
}
}
Zed
// ~/.config/zed/settings.json (inside "assistant" key)
{
"assistant": {
"version": "2",
"mcp_servers": {
"slashfeed": {
"type": "http",
"url": "https://slashfeed.app/api/mcp",
"oauth": {
"client_id": "019f1a2b-...",
"discovery_url": "https://slashfeed.app/.well-known/openid-configuration",
"scope": "feeds:read entries:read entries:write categories:read stats:read"
}
}
}
}
}
Personal token (any client)
// Any client — paste your personal token directly:
{
"mcpServers": {
"slashfeed": {
"type": "http",
"url": "https://slashfeed.app/api/mcp",
"headers": {
"Authorization": "Bearer a3f9e2b1c4d5..."
}
}
}
}
Download a pre-built collection for
Insomnia
or
Hoppscotch
to test every endpoint instantly. After importing, set the
base_url
and api_token
environment variables shown on the right.
Covers all three APIs — REST v1, Miniflux, and Fever.
Insomnia — environment variables
{
"base_url": "https://yourserver.com",
"api_token": "sk_live_your_token_here"
}
Hoppscotch — environment variables
[
{ "key": "base_url", "value": "https://yourserver.com", "secret": false },
{ "key": "api_token", "value": "sk_live_your_token_here", "secret": true }
]