Correct use of builder assumes that each step makes isolated instance. Thus, not using result of build step makes builder just ignore that action.
Miniflux Fever API
This document describes the Fever-compatible API implemented by the internal/fever package in this repository.
Endpoint
- Path:
BASE_URL/fever/ - Methods: not restricted by the router; read requests are typically sent as
GET, write requests should be sent asPOST - Response format: JSON only
- Reported API version:
3
Authentication
Fever authentication is enabled per user from the Miniflux integrations page.
Fever UsernameandFever Passwordare configured in Miniflux- Miniflux stores the Fever token as the MD5 hash of
username:password - Clients authenticate by sending that token as the
api_keyparameter - Token lookup is case-insensitive
Example:
api_key = md5("fever_username:fever_password")
Example shell command:
printf '%s' 'fever_username:fever_password' | md5sum
Authentication failure does not return HTTP 401. The middleware returns HTTP 200 with:
{
"api_version": 3,
"auth": 0
}
On successful authentication, every response includes:
api_version: always3auth: always1last_refreshed_on_time: current server Unix timestamp at response time
Dispatch Rules
The handler selects the first matching operation in this order:
groupsfeedsfaviconsunread_item_idssaved_item_idsitemsmark=itemmark=feedmark=group
If no selector is provided, the server returns the base authenticated response only.
For read operations, the selector must be present in the query string. For write operations, mark, as, id, and before are read from request form values, so they may come from the query string or a form body.
Read Operations
?groups
Returns:
groups: list of categoriesfeeds_groups: mapping of category IDs to feed IDs
Response shape:
{
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": 1710000000,
"groups": [
{
"id": 1,
"title": "All"
}
],
"feeds_groups": [
{
"group_id": 1,
"feed_ids": "10,11"
}
]
}
Notes:
groupsare Miniflux categoriesfeeds_groups.feed_idsis a comma-separated string- categories with no feeds are returned in
groupsbut have nofeeds_groupsentry
?feeds
Returns:
feeds: list of feedsfeeds_groups: mapping of category IDs to feed IDs
Feed fields:
idfavicon_idtitleurlsite_urlis_sparklast_updated_on_time
Notes:
favicon_idis0when the feed has no iconis_sparkis always0in this implementationlast_updated_on_timeis the feed check time as a Unix timestamp
?favicons
Returns:
favicons: list of favicon objects
Favicon fields:
iddata
Notes:
datais a data URL such asimage/png;base64,...
?unread_item_ids
Returns:
unread_item_ids: comma-separated list of unread entry IDs
Response shape:
{
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": 1710000000,
"unread_item_ids": "100,101,102"
}
?saved_item_ids
Returns:
saved_item_ids: comma-separated list of starred entry IDs
?items
Returns:
items: list of entriestotal_items: total number of non-removed entries for the user
Item fields:
idfeed_idtitleauthorhtmlurlis_savedis_readcreated_on_time
The implementation always excludes entries whose status is removed.
Pagination and filtering
The handler applies a fixed limit of 50 items.
Supported parameters:
since_id: when greater than0, returns entries withid > since_id, ordered byid ASCmax_id: when equal to0, returns the most recent entries ordered byid DESC; when greater than0, returns entries withid < max_id, ordered byid DESCwith_ids: comma-separated list of entry IDs to fetch
Selector precedence inside ?items is:
since_idmax_idwith_ids- no item filter
Notes:
with_idsdoes not enforce the 50-ID maximum mentioned in older Fever documentation- invalid
with_idsmembers are parsed as0and do not match normal entries - when
itemsis requested withoutsince_id,max_id, orwith_ids, the code applies no explicitORDER BY, so result ordering is not guaranteed by SQL htmlis returned after Miniflux content rewriting and may include media-proxy-rewritten URLs
Example:
{
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": 1710000000,
"total_items": 245,
"items": [
{
"id": 100,
"feed_id": 10,
"title": "Example entry",
"author": "Author",
"html": "<p>Content</p>",
"url": "https://example.org/post",
"is_saved": 0,
"is_read": 1,
"created_on_time": 1709990000
}
]
}
Write Operations
Normal successful write operations return the base authenticated response:
{
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": 1710000000
}
mark=item
Parameters:
mark=itemid=<entry_id>as=read|unread|saved|unsaved
Behavior:
as=read: marks the entry as readas=unread: marks the entry as unreadas=saved: toggles the starred flagas=unsaved: toggles the starred flag
Important:
savedandunsavedboth call the same toggle operation- sending
as=savedtwice will save, then unsave - sending
as=unsavedtwice will unsave, then save - if
id <= 0, the handler returns without writing a response body - if the entry does not exist or is already removed, the server returns the base response without an error
mark=feed
Parameters:
mark=feedas=readid=<feed_id>before=<unix_timestamp>
Behavior:
- marks unread entries in the feed as read when
published_at < before - the update runs asynchronously in a goroutine after the response is returned
Notes:
- if
id <= 0, the handler returns without writing a response body - if
beforeis missing or invalid, it is treated as Unix time0, which usually means nothing is marked as read
mark=group
Parameters:
mark=groupas=readid=<group_id>before=<unix_timestamp>
Behavior:
id=0: marks all unread entries as read, ignoringbeforeid>0: marks unread entries in the matching category as read whenpublished_at < before- the update runs asynchronously in a goroutine after the response is returned
Notes:
- group IDs map to Miniflux category IDs
- if
id < 0, the handler returns without writing a response body - if
beforeis missing or invalid forid>0, it is treated as Unix time0, which usually means nothing is marked as read
Error Handling
Authentication failures:
- HTTP status:
200 - body:
{"api_version":3,"auth":0}
Internal errors:
- HTTP status:
500 - body:
{
"error_message": "..."
}
Differences From Generic Fever Documentation
This implementation is Fever-compatible, but it does not match every detail of historical Fever API docs.
- Responses are always JSON;
api=xmlis mentioned in code comments but is not implemented api_versionis3last_refreshed_on_timeis set to the current response time, not the timestamp of the most recently refreshed feed- the
KindlingandSparkssuper groups are not returned feeds[].is_sparkis always0- item ordering without explicit pagination parameters is unspecified
as=savedandas=unsavedtoggle the saved flag instead of setting it absolutely
Examples
Fetch groups:
curl -s 'https://miniflux.example.com/fever/?api_key=TOKEN&groups'
Fetch most recent items:
curl -s 'https://miniflux.example.com/fever/?api_key=TOKEN&items&max_id=0'
Fetch items after a known ID:
curl -s 'https://miniflux.example.com/fever/?api_key=TOKEN&items&since_id=123'
Mark an item as read:
curl -s -X POST 'https://miniflux.example.com/fever/' \
-d 'api_key=TOKEN' \
-d 'mark=item' \
-d 'as=read' \
-d 'id=123'
Mark a feed as read before a timestamp:
curl -s -X POST 'https://miniflux.example.com/fever/' \
-d 'api_key=TOKEN' \
-d 'mark=feed' \
-d 'as=read' \
-d 'id=10' \
-d 'before=1710000000'
Mark all items as read through the group endpoint:
curl -s -X POST 'https://miniflux.example.com/fever/' \
-d 'api_key=TOKEN' \
-d 'mark=group' \
-d 'as=read' \
-d 'id=0'