Docs
Feedmon HTTPS API Reference
/.well-known/skills.md
markdown
# Feedmon HTTPS API skills
This is the canonical reference for Feedmon's supported external HTTPS API. Internal browser endpoints are intentionally omitted and may change without notice.
## Finding the API base
Use the path that contains `/.well-known/skills.md`, without that suffix. For example:
- document `https://app.a250.ca/i/example/.well-known/skills.md`
- API base `https://app.a250.ca/i/example`
- recent posts `https://app.a250.ca/i/example/api/posts/recent`
At a dedicated Feedmon origin the API base may be empty, such as `https://feedmon.example.com/api/posts/recent`. Do not discard an `/i/{instance}` prefix when it is present.
The JSON file beside this document at `mcp.json` is a small pointer back here. If the documents disagree, this file is authoritative.
## Authentication and safety
Browser sessions use the instance's normal sign-in flow. Automation uses an instance API key as `Authorization: Bearer <key>`.
Responses behind the application gateway are private and must not be cached. Never place API keys, OAuth codes, or other credentials in query parameters. Unknown routes and methods are denied to bearer clients even if an internal browser endpoint with that path exists.
## Supported endpoints
### `GET /api/version`
Returns the deployed Feedmon commit and build time.
### `GET /api/posts/recent`
Returns one page of posts from configured feeds as a JSON array.
Supported query parameters:
- `status=all|unread|read|replied|archived`; legacy `new` is treated as `unread`
- `days=7` for the default recent window or `days=0` for all retained time
- `subreddit=<name>`
- `min_score=<non-negative integer>`
- `page=<positive integer>`
- repeated `intent=<value>` parameters, combined as OR
Intent values are `help_request`, `troubleshooting`, `recommendation_request`, `purchase_intent`, `complaint`, `incident_report`, `showcase`, `news_information`, `offering`, and `general_discussion`.
Invalid filters return `400`; they are not silently replaced with defaults. Each post may include identity, subreddit, title, author, URL, permalink, best-effort content, timestamps, workflow status, feed metadata, comment count, analysis, matched targeting phrases, and relevance score. Premium match fields are omitted when unavailable.
### `GET /api/subreddits/{subreddit}/posts/download`
Downloads the retained local mirror for one configured subreddit as newline-delimited JSON. Optional `format=jsonl` is accepted; other formats return `400`.
Repeated `intent=<value>` parameters use the same closed values and OR semantics as `/api/posts/recent`, so exports can be limited to one or more intent types.
The response uses `Content-Type: application/x-ndjson` and `Content-Disposition: attachment`. It includes archived and otherwise hidden retained rows. Comments are not included.
### `GET /api/ingestion/coverage`
Observational health report for configured subreddits, Valkey reachability, retained SQLite mirror state, and a `summary` object. Calling this endpoint does not register feeds or mutate ingestion state.
Important fields:
- `subreddits` is the sorted configured feed list.
- `summary.ok` is false only when hard `issues` exist; `warnings` are diagnostic.
- `valkey.ping_ok` reports shared Valkey reachability.
- `valkey.rfetcher_subs_requested` is a pending handoff queue, not durable subscription truth.
- `sync` reports retained stream mirror state per subreddit.
Use this endpoint together with rfetcher's registered subreddit list when checking end-to-end ingestion.
### `POST /api/settings/keyword-scan`
Fallback scanner available only on instances where advanced Targeting research is disabled. It reads exactly one public webpage, returns deterministic starter terms, and saves nothing automatically.
Send `{"url":"https://example.com"}`. Only public HTTP and HTTPS targets are accepted. Private, local, and link-local hosts are blocked. Requests are limited to one scan per requester per minute.
Instances with advanced Targeting research intentionally return `404` for this fallback route and expose the richer research workflow through the browser Settings page instead.
### `GET /api/train/posts`
Returns unrated training candidates as a JSON array.
- `limit=1..100` selects the queue size.
- `for_agent=0|1`; `1` omits `relevance_score`.
Invalid values return `400`.
Content and match details are best-effort and may be absent.
### `POST /api/train/feedback`
Send `{"post_id":123,"rating":"Excellent"}`. Ratings are case-insensitive: `excellent`, `good` (or `acceptable`), and `bad`.
This operation is not idempotent with respect to learning. It records or replaces feedback, updates learned keyword and phrase signals, and changes workflow status: excellent becomes replied; good/acceptable becomes read; bad does not automatically change status.
### `POST /api/train/undo`
Send `{"post_id":123}`. This removes the current feedback, reverses its learning deltas, and returns an automatically changed replied/read status to unread when it still matches that feedback. It returns `404` when no feedback exists, so it is not idempotent.
### `GET /api/train/stats`
Returns training progress JSON. It may be an empty object when statistics are unavailable.
## Recommended training loop
1. `GET /api/train/posts`
2. Select `Excellent`, `Good`, or `Bad`
3. `POST /api/train/feedback`
4. Optionally `POST /api/train/undo`
## Browser documentation
Relative to the API base, the human reference is `/docs/skills`, training is `/train`, and retained posts are `/posts`.