{"openapi":"3.1.0","info":{"title":"nowreading.dev API","summary":"Agent-native reading list: read any user's public list, or curate a user's list on their behalf.","description":"The nowreading.dev HTTP API lets AI agents and developers:\n\n- **Read** any user's public reading list as JSON (no auth required).\n- **Write** (create, update, delete, refresh) to a user's list with a per-user bearer token.\n\n- **Recall** the user's resonant memories from your current working context via `POST /api/resonance`.\n\nAgents should first call `GET /api/me` to verify the token and discover the handle it represents.\nEvery reading list is also published as RSS, Atom, JSON Feed, Markdown, plain text, and llms.txt at `/:handle.*`.\n\nTokens carry **scopes** (`recall` ⊂ `read` ⊂ `write`); a request beyond the token's scope\nreturns `403` with code `insufficient_scope`. An MCP server with the same capabilities is\nserved at `/mcp` (see `/.well-known/mcp/server-card.json`).\n\n**Rate limits** are returned on every response via `X-RateLimit-Limit`, `X-RateLimit-Remaining`,\nand `X-RateLimit-Reset` headers. Agents receiving `429 Too Many Requests` should respect the\n`Retry-After` header.\n","version":"1.0.0","contact":{"name":"nowreading.dev","email":"v@codenamev.com","url":"https://nowreading.dev"},"license":{"name":"Proprietary"},"x-logo":{"url":"https://nowreading.dev/icon.png"}},"servers":[{"url":"https://nowreading.dev","description":"Production"}],"externalDocs":{"description":"Markdown API documentation (llms.txt)","url":"https://nowreading.dev/llms.txt"},"security":[{"bearerAuth":[]}],"tags":[{"name":"me","description":"Token-holder identity & discovery."},{"name":"resonance","description":"The associative-memory reflex: send working context, receive the user's resonant readings and reflections."},{"name":"articles","description":"Create, read, update, and delete the authenticated user's articles."},{"name":"reflections","description":"The user's timestamped thoughts attached to articles or other reflectables."},{"name":"connections","description":"Edges between two of the user's articles. Pending suggestions transition to accepted or dismissed."},{"name":"surface","description":"Weekly surface — proactive resurfacing of old reads, dormant reflections, stale suggestions, and feed-item discoveries."},{"name":"feed_sources","description":"RSS / Atom subscriptions used for external discovery."},{"name":"feed_items","description":"Items fetched from the user's discovery feeds; can be saved (promoted to articles) or dismissed."},{"name":"users","description":"Public reads of other users' reading lists (no auth)."}],"paths":{"/api/me":{"get":{"operationId":"getMe","tags":["me"],"summary":"Verify bearer token and discover the handle it represents.","description":"Returns the handle, reading-list URL, feed URLs, and article count for the authenticated user. Call this first after a token handoff.","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/MeResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/api/articles":{"get":{"operationId":"listArticles","tags":["articles"],"summary":"List the authenticated user's articles (including drafts).","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1},"description":"1-based page number. Page size is 50."}],"responses":{"200":{"$ref":"#/components/responses/ArticleListResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"post":{"operationId":"createArticle","tags":["articles"],"summary":"Add an article to the authenticated user's reading list.","description":"If the URL already exists on the user's list, returns 200 with `{ message: 'Already saved.' }`. Otherwise returns 201. Metadata extraction runs asynchronously; the first response may have partial fields.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleCreateRequest"},"examples":{"basic":{"value":{"url":"https://example.com/post"}},"withNotes":{"value":{"url":"https://example.com/post","notes":"Revisit before next demo."}},"backfill":{"value":{"url":"https://example.com/post","added_at":"2026-05-12T09:00:00Z"}}}}}},"responses":{"200":{"$ref":"#/components/responses/ArticleResponse"},"201":{"$ref":"#/components/responses/ArticleResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/articles/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"patch":{"operationId":"updateArticle","tags":["articles"],"summary":"Update one of the authenticated user's articles.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleUpdateRequest"}}}},"responses":{"200":{"$ref":"#/components/responses/ArticleResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteArticle","tags":["articles"],"summary":"Remove an article from the authenticated user's reading list.","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/articles/{id}/refresh_metadata":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"post":{"operationId":"refreshArticleMetadata","tags":["articles"],"summary":"Queue a metadata re-extraction for an article.","description":"Returns 202 immediately; the extraction runs asynchronously.","security":[{"bearerAuth":[]}],"responses":{"202":{"$ref":"#/components/responses/ArticleResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/articles/{article_id}/reflections":{"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"get":{"operationId":"listReflections","tags":["reflections"],"summary":"List reflections on one of the authenticated user's articles.","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/ReflectionListResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}},"post":{"operationId":"createReflection","tags":["reflections"],"summary":"Add a reflection to an article.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReflectionCreateRequest"}}}},"responses":{"201":{"$ref":"#/components/responses/ReflectionResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/reflections/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"delete":{"operationId":"deleteReflection","tags":["reflections"],"summary":"Delete one of the authenticated user's reflections.","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/articles/{article_id}/connections":{"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"get":{"operationId":"listConnections","tags":["connections"],"summary":"List connections involving an article (pending or accepted).","security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","accepted","dismissed"]}}],"responses":{"200":{"$ref":"#/components/responses/ConnectionListResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}},"post":{"operationId":"createConnection","tags":["connections"],"summary":"Manually connect an article to one of your other articles.","description":"Always created with status=accepted, source=manual. Symmetric kinds canonicalize endpoint order.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionCreateRequest"}}}},"responses":{"201":{"$ref":"#/components/responses/ConnectionResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/connections/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"patch":{"operationId":"updateConnection","tags":["connections"],"summary":"Transition a connection's status (accept or dismiss a pending suggestion).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionUpdateRequest"}}}},"responses":{"200":{"$ref":"#/components/responses/ConnectionResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteConnection","tags":["connections"],"summary":"Delete a connection.","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/surface":{"get":{"operationId":"getLatestSurface","tags":["surface"],"summary":"Return the user's latest weekly surface (resurfaced items grouped by reason).","description":"Marks the surface as seen on first read. Returns 404 if no surface has been built yet.","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/SurfaceResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/feed_sources":{"get":{"operationId":"listFeedSources","tags":["feed_sources"],"summary":"List the user's discovery feed sources.","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/FeedSourceListResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"post":{"operationId":"createFeedSource","tags":["feed_sources"],"summary":"Subscribe to an RSS / Atom feed for discovery.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedSourceCreateRequest"}}}},"responses":{"201":{"$ref":"#/components/responses/FeedSourceResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/feed_sources/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"delete":{"operationId":"deleteFeedSource","tags":["feed_sources"],"summary":"Unsubscribe from a feed source (also removes its items).","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/feed_sources/{id}/fetch":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"post":{"operationId":"fetchFeedSource","tags":["feed_sources"],"summary":"Queue an immediate fetch for a feed source.","security":[{"bearerAuth":[]}],"responses":{"202":{"$ref":"#/components/responses/FeedSourceResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/feed_items":{"get":{"operationId":"listFeedItems","tags":["feed_items"],"summary":"List feed items across the user's feed sources.","security":[{"bearerAuth":[]}],"parameters":[{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["pending","saved","dismissed"]},"description":"Defaults to 'pending'."}],"responses":{"200":{"$ref":"#/components/responses/FeedItemListResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/api/feed_items/{id}/save":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"post":{"operationId":"saveFeedItem","tags":["feed_items"],"summary":"Promote a feed item into the authenticated user's reading list.","description":"Idempotent: if the URL already exists in the user's articles, returns the existing one and stamps saved_at on the feed item.","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/FeedItemSaveResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/feed_items/{id}/dismiss":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"delete":{"operationId":"dismissFeedItem","tags":["feed_items"],"summary":"Dismiss a feed item so it is not re-surfaced.","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Dismissed."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"}}}},"/api/resonance":{"post":{"operationId":"recallResonance","tags":["resonance"],"summary":"Recall the user's memories that resonate with the supplied context.","description":"Send a snippet of the agent's current working context (a sentence to a paragraph — the thought itself, not keywords). Returns the few articles and reflections above a high similarity floor, best first. Requires only the `recall` scope. Every call is logged to the user's recall audit. An empty `hits` array means nothing rang, not an empty library.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResonanceRequest"},"examples":{"planning":{"value":{"context":"Designing a token-scoping model for a small Rails API; wondering how much granularity is worth it."}}}}}},"responses":{"200":{"$ref":"#/components/responses/ResonanceResponse"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"$ref":"#/components/responses/InsufficientScopeError"},"503":{"$ref":"#/components/responses/EmbeddingUnavailableError"}}}},"/api/users/{handle}/articles":{"get":{"operationId":"listUserArticles","tags":["users"],"summary":"List any user's published articles (public; no auth).","description":"Returns the 50 most recent published articles. Equivalent to `/:handle.json` (JSON Feed 1.1).","security":[],"parameters":[{"name":"handle","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$"}}],"responses":{"200":{"$ref":"#/components/responses/PublicArticleListResponse"},"404":{"$ref":"#/components/responses/NotFoundError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"Opaque per-user token (has_secure_token)","description":"Per-user bearer token created at /token. Tokens carry scopes — `recall` (resonance only), `read` (browse the library), `write` (mutations); broader scopes include narrower ones. The legacy single per-user token has all scopes. Requests beyond the token's scope return 403 `insufficient_scope`."}},"parameters":{},"schemas":{"Article":{"type":"object","required":["id","url","added_at"],"properties":{"id":{"type":"integer","example":42},"url":{"type":"string","format":"uri","example":"https://example.com/post"},"title":{"type":"string","nullable":true,"example":"Diffusion based LLMs are here"},"summary":{"type":"string","nullable":true},"author":{"type":"string","nullable":true},"source":{"type":"string","nullable":true,"description":"Canonical site or publisher."},"publication_date":{"type":"string","format":"date-time","nullable":true,"description":"When the original source was published."},"content_type":{"type":"string","nullable":true,"example":"article"},"length":{"type":"integer","nullable":true,"description":"Word count if known."},"keywords":{"type":"array","items":{"type":"string"},"nullable":true},"added_at":{"type":"string","format":"date-time","description":"When the user actually read/saved the article. Defaults to creation time; backdatable on create and update for history backfill."},"notes":{"type":"string","nullable":true,"description":"Owner-only."},"draft":{"type":"boolean","description":"Owner-only. Drafts are excluded from public feeds."},"updated_at":{"type":"string","format":"date-time","description":"Owner-only."}}},"ArticleCreateRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"notes":{"type":"string"},"added_at":{"type":"string","format":"date-time","description":"ISO 8601. When the user actually read/saved this — send it when backfilling reading history. Omit for something read just now. Must not be in the future; invalid or future values return 422."}}},"ArticleUpdateRequest":{"type":"object","properties":{"notes":{"type":"string"},"draft":{"type":"boolean"},"title":{"type":"string"},"summary":{"type":"string"},"added_at":{"type":"string","format":"date-time","description":"ISO 8601. Correct when the user actually read/saved this article (backdating). Must not be in the future."}}},"ArticleListResponse":{"type":"object","required":["page","page_size","articles"],"properties":{"page":{"type":"integer","minimum":1},"page_size":{"type":"integer","example":50},"articles":{"type":"array","items":{"$ref":"#/components/schemas/Article"}}}},"PublicArticleListResponse":{"type":"object","description":"JSON Feed 1.1 formatted reading list.","properties":{"version":{"type":"string","example":"https://jsonfeed.org/version/1.1"},"title":{"type":"string"},"home_page_url":{"type":"string","format":"uri"},"feed_url":{"type":"string","format":"uri"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"content_text":{"type":"string"},"date_published":{"type":"string","format":"date-time"},"tags":{"type":"array","items":{"type":"string"}}}}}}},"ArticleCreateOrShowResponse":{"type":"object","properties":{"message":{"type":"string","example":"Article added!"},"article":{"$ref":"#/components/schemas/Article"}}},"MeResponse":{"type":"object","required":["handle","reading_list_url","article_count","feeds"],"properties":{"handle":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$"},"reading_list_url":{"type":"string","format":"uri"},"llms_txt_url":{"type":"string","format":"uri"},"docs_url":{"type":"string","format":"uri"},"article_count":{"type":"integer"},"feeds":{"type":"object","properties":{"rss":{"type":"string","format":"uri"},"atom":{"type":"string","format":"uri"},"json":{"type":"string","format":"uri"},"md":{"type":"string","format":"uri"},"text":{"type":"string","format":"uri"}}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code.","example":"unauthorized"},"resolution":{"type":"string","description":"Suggested agent action to resolve the error."},"docs_url":{"type":"string","format":"uri","description":"Link to relevant documentation."}}},"ValidationErrorBody":{"type":"object","required":["errors"],"properties":{"errors":{"type":"array","items":{"type":"string"}},"code":{"type":"string","example":"validation_failed"},"resolution":{"type":"string"}}},"Reflection":{"type":"object","required":["id","body","reflectable_type","reflectable_id","created_at"],"properties":{"id":{"type":"integer"},"body":{"type":"string"},"source":{"type":"string","enum":["user","agent"],"description":"Provenance: 'user' entries are the human's journal; 'agent' entries were written back by connected agents."},"reflectable_type":{"type":"string","example":"Article"},"reflectable_id":{"type":"integer"},"reflected_at":{"type":"string","format":"date-time","description":"When the thought actually happened. Defaults to creation time; backdatable on create."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ResonanceRequest":{"type":"object","required":["context"],"properties":{"context":{"type":"string","description":"The agent's current working context — a sentence to a paragraph. The thought itself, not a keyword query."},"limit":{"type":"integer","minimum":1,"maximum":5,"default":3,"description":"Max hits per kind (articles, reflections)."}}},"ResonanceHit":{"type":"object","required":["type","similarity"],"properties":{"type":{"type":"string","enum":["article","reflection"]},"id":{"type":"integer"},"similarity":{"type":"number","description":"Cosine similarity to the supplied context (threshold 0.6)."},"title":{"type":"string","description":"Articles only."},"url":{"type":"string","format":"uri","description":"Articles only."},"summary":{"type":"string","nullable":true,"description":"Articles only."},"notes":{"type":"string","nullable":true,"description":"Articles only."},"saved_at":{"type":"string","format":"date-time","description":"Articles only."},"excerpt":{"type":"string","description":"Reflections only: the user's words, truncated."},"source":{"type":"string","enum":["user","agent"],"description":"Reflections only."},"reflected_at":{"type":"string","format":"date-time","description":"Reflections only."},"about":{"type":"object","description":"Reflections only: what the reflection is attached to."}}},"ResonanceResponse":{"type":"object","required":["hits"],"properties":{"context_excerpt":{"type":"string","description":"The truncated excerpt stored in the recall audit log."},"recall_event_id":{"type":"integer"},"hits":{"type":"array","items":{"$ref":"#/components/schemas/ResonanceHit"},"description":"Best first. Empty means nothing resonated above the threshold."},"guidance":{"type":"string"}}},"ReflectionCreateRequest":{"type":"object","required":["reflection"],"properties":{"reflection":{"type":"object","required":["body"],"properties":{"body":{"type":"string","description":"The thought to record."},"reflected_at":{"type":"string","format":"date-time","description":"ISO 8601. When the thought actually happened — send it when backfilling history. Omit for a thought happening now. Must not be in the future."}}}}},"Connection":{"type":"object","required":["id","from_article_id","to_article_id","kind","status","source"],"properties":{"id":{"type":"integer"},"from_article_id":{"type":"integer"},"to_article_id":{"type":"integer"},"kind":{"type":"string","enum":["related","extends","contradicts","informs","references"]},"status":{"type":"string","enum":["pending","accepted","dismissed"]},"source":{"type":"string","enum":["suggested","manual"]},"score":{"type":"number","nullable":true,"description":"Cosine similarity used by the suggestion job; nil for manual connections."},"forward_label":{"type":"string","description":"Human label for this kind, e.g. 'extends' or 'is related to'."},"symmetric":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ConnectionCreateRequest":{"type":"object","required":["connection"],"properties":{"connection":{"type":"object","required":["to_article_id"],"properties":{"to_article_id":{"type":"integer"},"kind":{"type":"string","enum":["related","extends","contradicts","informs","references"],"default":"related"}}}}},"ConnectionUpdateRequest":{"type":"object","required":["connection"],"properties":{"connection":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["accepted","dismissed"]}}}}},"Surface":{"type":"object","properties":{"id":{"type":"integer"},"period_start":{"type":"string","format":"date-time"},"period_end":{"type":"string","format":"date-time"},"delivered_at":{"type":"string","format":"date-time","nullable":true},"seen_at":{"type":"string","format":"date-time","nullable":true},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"reason":{"type":"string","enum":["agent_recall","recent_theme_match","dormant_reflection","unaccepted_suggestion","external_discovery"]},"score":{"type":"number"},"surfaceable_type":{"type":"string","enum":["Article","Reflection","Connection","FeedItem"]},"surfaceable_id":{"type":"integer"},"surfaceable":{"type":"object","description":"Polymorphic payload; shape depends on surfaceable_type."}}}}}},"FeedSource":{"type":"object","required":["id","url","fetch_status"],"properties":{"id":{"type":"integer"},"url":{"type":"string","format":"uri"},"name":{"type":"string","nullable":true},"kind":{"type":"string","enum":["rss","atom","unknown"],"nullable":true},"fetch_status":{"type":"string","enum":["pending","ok","error"]},"last_fetched_at":{"type":"string","format":"date-time","nullable":true},"last_successful_fetch_at":{"type":"string","format":"date-time","nullable":true},"fetch_error":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"FeedSourceCreateRequest":{"type":"object","required":["feed_source"],"properties":{"feed_source":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"name":{"type":"string"}}}}},"FeedItem":{"type":"object","required":["id","feed_source_id","url"],"properties":{"id":{"type":"integer"},"feed_source_id":{"type":"integer"},"url":{"type":"string","format":"uri"},"title":{"type":"string","nullable":true},"summary":{"type":"string","nullable":true},"author":{"type":"string","nullable":true},"published_at":{"type":"string","format":"date-time","nullable":true},"saved_at":{"type":"string","format":"date-time","nullable":true},"dismissed_at":{"type":"string","format":"date-time","nullable":true}}}},"responses":{"MeResponse":{"description":"Token is valid; returns the owning handle and feed URLs.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"ArticleListResponse":{"description":"List of the authenticated user's articles.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleListResponse"}}}},"PublicArticleListResponse":{"description":"Public JSON Feed for the given handle.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicArticleListResponse"}}}},"ArticleResponse":{"description":"A single article with optional message.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleCreateOrShowResponse"}}}},"UnauthorizedError":{"description":"Missing or invalid bearer token.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InsufficientScopeError":{"description":"The token is valid but lacks the scope this endpoint requires.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"EmbeddingUnavailableError":{"description":"Embedding provider unavailable (transient). Retry with backoff; treat as no resonance, not an empty library.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ResonanceResponse":{"description":"The user's memories that resonate with the supplied context.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResonanceResponse"}}}},"NotFoundError":{"description":"Resource does not exist or is not visible to this token.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ValidationError":{"description":"Request failed validation.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorBody"}}}},"ReflectionListResponse":{"description":"List of reflections.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"reflections":{"type":"array","items":{"$ref":"#/components/schemas/Reflection"}}}}}}},"ReflectionResponse":{"description":"A single reflection.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"reflection":{"$ref":"#/components/schemas/Reflection"}}}}}},"ConnectionListResponse":{"description":"List of connections.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/Connection"}}}}}}},"ConnectionResponse":{"description":"A single connection.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/Connection"}}}}}},"SurfaceResponse":{"description":"The latest weekly surface for the user.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"surface":{"$ref":"#/components/schemas/Surface"}}}}}},"FeedSourceListResponse":{"description":"List of the user's feed sources.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"feed_sources":{"type":"array","items":{"$ref":"#/components/schemas/FeedSource"}}}}}}},"FeedSourceResponse":{"description":"A single feed source.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"feed_source":{"$ref":"#/components/schemas/FeedSource"},"message":{"type":"string"}}}}}},"FeedItemListResponse":{"description":"List of feed items.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"feed_items":{"type":"array","items":{"$ref":"#/components/schemas/FeedItem"}}}}}}},"FeedItemSaveResponse":{"description":"The promoted feed item plus the resulting article.","headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"feed_item":{"$ref":"#/components/schemas/FeedItem"},"article":{"$ref":"#/components/schemas/Article"}}}}}}},"headers":{"X-RateLimit-Limit":{"description":"Request quota per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Epoch seconds when the window resets.","schema":{"type":"integer"}}}}}