# info.summary
Read-only endpoints for the personal site, daily news feed and notes of Harshit Khemani.

# info.description
Public, unauthenticated, read-only HTTP API.

When to use: fetch the curated daily AI/technology news digest, read published notes and essays, retrieve an agent-readable markdown representation of the site, or check what Harshit is currently listening to. Every endpoint is a plain GET, returns `application/json` unless stated otherwise, and needs no API key or sign-up.

Not for: writing, posting, or any mutation. The webhook and MCP-admin routes that do accept writes are authenticated and are deliberately not described here.

Markdown negotiation: `/` and `/news` return `text/markdown` when the request sends `Accept: text/markdown`, and HTML otherwise. Both vary on `Accept`.

Versioning: the API is versioned by date, matching info.version, and reported in the `X-API-Version` response header. Every endpoint is also reachable under a stable `/api/v1/` prefix. Additive changes ship without notice; a breaking change to an existing response would ship under a new prefix, with the previous one kept working for at least 90 days, marked `deprecated` here and carrying `Deprecation` and `Sunset` headers.

Rate limits: none are enforced and no rate-limit headers are returned. Please stay under about 60 requests per minute, send an identifying User-Agent, and back off exponentially on 5xx.

Errors: every REST error uses the Error schema below. Branch on the stable `code` field, never on the message text. Unknown /api/* paths return a JSON 404 rather than an HTML page.

# info.license.name
Content is © Harshit Khemani; endpoints may be called freely for agent and personal use.

# servers[].description
Stable versioned prefix; same endpoints without the /api prefix

# tags[].description
Curated daily AI and technology news digest.

# tags[].description
Agent-readable representations of the site itself.

# paths./api/news.get.description
Returns the aggregated AI and technology news payload behind https://www.khe.money/news, including the upstream sources it was assembled from, the time it was fetched, and the extracted keyword set. Refreshed on a schedule; use `lastUpdatedMarker` to detect a change without diffing the whole body.

# paths./api/news-last-updated.get.description
Cheap poll target. Returns the same marker as `lastUpdatedMarker` on the full digest, so an agent can decide whether re-fetching /api/news is worthwhile.

# paths./api/notes.get.description
Returns every published note in reverse-chronological order with its slug, excerpt and tags. Fetch the full body of one note with `getNote` using the `slug` from this list.

# paths./api/notes/{slug}.get.description
Returns the full content of a single note. The `slug` comes from `listNotes`.

# paths./api/notes/{slug}.get.parameters[].description
URL slug of the note, as returned by listNotes.

# paths./api/home-page.get.description
Agent-readable markdown representation of the home page. Requires `Accept: text/markdown`; any other Accept returns 406. The same document is served from `/` under markdown content negotiation, and as a static file at /.well-known/home.md.

# paths./api/home-page.get.responses.406.description
Accept header did not include text/markdown.

# paths./api/news-page.get.description
Agent-readable markdown rendering of the daily news page. Requires `Accept: text/markdown`.

# paths./api/news-page.get.responses.406.description
Accept header did not include text/markdown.

# paths./api/content.get.description
Backing endpoint for the markdown representations. Prefer the named aliases (`getHomePageMarkdown`, `getNewsPageMarkdown`, `getNewsLastUpdated`) — they are stable, this parameterised form is an implementation detail.

# paths./api/content.get.responses.406.description
Accept header did not include text/markdown for a markdown document.

# paths./api/spotify-last-listened.get.summary
Get the most recently played Spotify track

# paths./api/spotify-last-listened.get.description
Returns the last track Harshit finished listening to. `ok` is false with a null `track` when the upstream is unavailable or nothing has been played recently — treat that as a normal, expected state rather than an error.

# paths./api/spotify-last-listened.get.responses.200.description
The last played track, or ok:false when unavailable.

# paths./api/sitemaps.get.description
Returns an XML sitemap. Also reachable at the conventional paths /sitemap.xml, /sitemap-index.xml and /news-sources-sitemap.xml.

# paths./news/mcp.post.summary
Model Context Protocol endpoint for the news feed

# paths./news/mcp.post.description
Streamable-HTTP MCP server exposing read-only tools over the daily news digest. Speaks JSON-RPC 2.0. No write operations are exposed and no credentials are required.

# components.responses.BadRequest.description
A required parameter was missing or outside its allowed set.

# components.responses.BadRequest.content.application/json.example.message
The 'kind' query parameter must be one of: home-page, news-page, news-last-updated.

# components.responses.NotFound.content.application/json.example.hint
Call listNotes (GET /api/notes) for the current set of slugs.

# components.responses.MethodNotAllowed.content.application/json.example.message
This endpoint is read-only and only accepts GET.

# components.responses.UpstreamError.description
An upstream source was unavailable. Transient — retry with backoff.

# components.responses.UpstreamError.content.application/json.example.error
Unable to fetch aligned news API data right now.

# components.responses.UpstreamError.content.application/json.example.message
An upstream source did not respond in time.

# components.responses.UpstreamError.content.application/json.example.hint
Transient. Retry after 30 seconds with exponential backoff.

# components.schemas.Error.properties.error.description
Short human-readable summary. Retained for backwards compatibility.

# components.schemas.Error.properties.code.description
Stable machine-readable identifier. Branch on this, not on the message text.

# components.schemas.Error.properties.hint.description
What to do about it, including whether a retry is worthwhile.

# components.schemas.NewsDigest.properties.source.description
Comma-separated upstream URLs the digest was assembled from.

# components.schemas.NewsDigest.properties.lastUpdatedMarker.description
Opaque freshness token; compare for equality only.

# components.schemas.NoteSummary.properties.cover.description
Cover image URL, or an empty string when there is none.

# components.schemas.LastListened.properties.ok.description
False when the upstream is unavailable or nothing was played recently.

# components.schemas.NewsFreshness.description
Freshness marker for the news digest, for cheap polling.

# components.schemas.NewsFreshness.properties.lastUpdatedMarker.description
Opaque token; compare for equality only.

# components.schemas.SitemapXml.description
A sitemaps.org urlset or sitemapindex document.

# components.headers.XApiVersion.description
Date-based API version of the responding deployment.