{"openapi":"3.1.0","info":{"title":"Glyph","description":"A language for agents: encode content into the cheapest substrate the reading model can parse, with honest per-reader token math. Fillin is the retrieval product — a time-series index of the dev internet that closes the gap between an LLM's training cutoff and now.","version":"0.1.0"},"paths":{"/":{"get":{"summary":"Root","description":"Host-split front doors.\n\nfillinmcp.com / www.fillinmcp.com → web/fillin.html (Fillin product).\nglyphapi.dev and every other Host (incl. TestClient's testserver) →\nweb/language.html (Glyph language page). The cinematic film stays at /film.\nnginx already forwards Host; no extra vhost required for the split.\n\nThis is the durable replacement for the temporary fillinmcp.com\n`location = /` static file on the VPS. After this ships, glyphdesk\nremoves that nginx override so `/` comes from uvicorn again.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/index.html":{"get":{"summary":" Legacy Funnels Redirect","operationId":"_legacy_funnels_redirect_index_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/old":{"get":{"summary":" Legacy Funnels Redirect","operationId":"_legacy_funnels_redirect_old_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/onboard_v2.html":{"get":{"summary":" Legacy Funnels Redirect","operationId":"_legacy_funnels_redirect_onboard_v2_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v2":{"get":{"summary":" Legacy Funnels Redirect","operationId":"_legacy_funnels_redirect_v2_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/onboard.html":{"get":{"summary":" Legacy Funnels Redirect","operationId":"_legacy_funnels_redirect_onboard_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/pricing":{"get":{"summary":"Pricing","operationId":"pricing_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/signup.html":{"get":{"summary":"Signup","operationId":"signup_signup_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/signup":{"get":{"summary":"Signup","operationId":"signup_signup_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/pitch.html":{"get":{"summary":"Pitch","operationId":"pitch_pitch_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/status":{"get":{"summary":"Status Page","operationId":"status_page_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/changelog":{"get":{"summary":"Changelog Page","description":"Fillin changelog is off the public site. Old links land on the host's `/`.","operationId":"changelog_page_changelog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/glyph.html":{"get":{"summary":"Glyph Page","description":"Glyph photo-glyph surface. Fillin (the retrieval product) supplies the corpus.","operationId":"glyph_page_glyph_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/glyph":{"get":{"summary":"Glyph Page","description":"Glyph photo-glyph surface. Fillin (the retrieval product) supplies the corpus.","operationId":"glyph_page_glyph_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/glyph/film":{"get":{"summary":"Glyph Film","description":"Glyph — the cinematic scroll experience: the product's pipeline (post-cutoff\ncorpus → dense glyph → vision-model read → cited pieces → cross-model transfer)\nperformed as a scroll-driven canvas film. Static asset; additive to /glyph.","operationId":"glyph_film_glyph_film_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/film":{"get":{"summary":"Glyph Film","description":"Glyph — the cinematic scroll experience: the product's pipeline (post-cutoff\ncorpus → dense glyph → vision-model read → cited pieces → cross-model transfer)\nperformed as a scroll-driven canvas film. Static asset; additive to /glyph.","operationId":"glyph_film_film_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/thesis/":{"get":{"summary":"Thesis Latest","operationId":"thesis_latest_thesis__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/thesis":{"get":{"summary":"Thesis Latest","operationId":"thesis_latest_thesis_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/thesis/v1":{"get":{"summary":"Thesis V1","operationId":"thesis_v1_thesis_v1_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/thesis/v2":{"get":{"summary":"Thesis V2","operationId":"thesis_v2_thesis_v2_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/top_models.js":{"get":{"summary":"Top Models Js","operationId":"top_models_js_top_models_js_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp/server-card.json":{"get":{"summary":"Mcp Server Card","operationId":"mcp_server_card__well_known_mcp_server_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/robots.txt":{"get":{"summary":"Robots","operationId":"robots_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sitemap.xml":{"get":{"summary":"Sitemap","operationId":"sitemap_sitemap_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/favicon.svg":{"get":{"summary":"Favicon","operationId":"favicon_favicon_svg_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/favicon.ico":{"get":{"summary":"Favicon Ico","operationId":"favicon_ico_favicon_ico_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/og.svg":{"get":{"summary":"Og Image","operationId":"og_image_og_svg_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/_shared.css":{"get":{"summary":"Shared Css","operationId":"shared_css__shared_css_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/logo.jpg":{"get":{"summary":"Logo Jpg","operationId":"logo_jpg_logo_jpg_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/freshness":{"get":{"summary":"Freshness","description":"Public corpus freshness — no auth. Powers the landing-page widget and\ngives operators a quick liveness signal without exposing /stats. Returns\nonly counts and timestamps; no document content.\n\nServed from the SHARED corpus cache (`corpus()` — 30-min SWR + disk-\npersisted + boot-seeded), not an independent stats() scan. The old path\nhad its own 60s-TTL cache with no stale-while-revalidate, so it cold-\nscanned all ~185k rows (~33s on the 4GB VPS) once a minute and dumped\nthat latency on whichever visitor hit it first (see 2026-06-03).","operationId":"freshness_freshness_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/corpus":{"get":{"summary":"Corpus","description":"Public corpus breakdown — what's in the box, no auth.\n\nAn agent should be able to read this BEFORE deciding whether to spend\n$0.01. Returns total rows, oldest/newest, per-source counts, per-source\noldest/newest, and ingest lag (seconds since the most recent doc).\n\nStale-while-revalidate: 30-min TTL, lock-guarded recompute, never\nblocks a visitor on the column scan if any cached value exists.","operationId":"corpus_v1_corpus_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/gap":{"get":{"summary":"Gap","description":"Exact count of indexed docs published AFTER `cutoff` (YYYY-MM-DD) — the\nlanding page's hero number (\"your agent has missed N documents\").\n\nAnswered instantly from the cached monthly histogram (no per-cutoff scan,\nno auth, no charge). Counts whole months strictly after the cutoff's month,\nso it is a slight, honest UNDER-count near the boundary — never an overcount.\nAn agent can read this BEFORE deciding whether to wire up Fillin.","operationId":"gap_v1_gap_get","parameters":[{"name":"cutoff","in":"query","required":true,"schema":{"type":"string","title":"Cutoff"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/health":{"get":{"summary":"Healthz","description":"Liveness + freshness. No auth.\n\nReturns the public health signal an uptime monitor or evaluating agent\nexpects (`{\"ok\": true}`) plus a minimal freshness echo — last ingest\ntimestamp and lag in seconds — so a caller can verify the corpus is\nactually being kept current without burning the `/v1/corpus` aggregate.\nReads from the same cached aggregate as `/v1/corpus`; no extra DB cost.\n\nWhen `stale_sources` is non-empty, `recovery` tells an agent which sources,\nhow far past SLO they are, the catch-up window the scheduler will use, and\n(only if the scheduler has recorded one) the last attempt. See freshness.py\nfor the SLO table. The field is absent when every source is inside SLO.","operationId":"healthz_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Healthz","description":"Liveness + freshness. No auth.\n\nReturns the public health signal an uptime monitor or evaluating agent\nexpects (`{\"ok\": true}`) plus a minimal freshness echo — last ingest\ntimestamp and lag in seconds — so a caller can verify the corpus is\nactually being kept current without burning the `/v1/corpus` aggregate.\nReads from the same cached aggregate as `/v1/corpus`; no extra DB cost.\n\nWhen `stale_sources` is non-empty, `recovery` tells an agent which sources,\nhow far past SLO they are, the catch-up window the scheduler will use, and\n(only if the scheduler has recorded one) the last attempt. See freshness.py\nfor the SLO table. The field is absent when every source is inside SLO.","operationId":"healthz_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/healthz":{"get":{"summary":"Healthz","description":"Liveness + freshness. No auth.\n\nReturns the public health signal an uptime monitor or evaluating agent\nexpects (`{\"ok\": true}`) plus a minimal freshness echo — last ingest\ntimestamp and lag in seconds — so a caller can verify the corpus is\nactually being kept current without burning the `/v1/corpus` aggregate.\nReads from the same cached aggregate as `/v1/corpus`; no extra DB cost.\n\nWhen `stale_sources` is non-empty, `recovery` tells an agent which sources,\nhow far past SLO they are, the catch-up window the scheduler will use, and\n(only if the scheduler has recorded one) the last attempt. See freshness.py\nfor the SLO table. The field is absent when every source is inside SLO.","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/freshness":{"get":{"summary":"Freshness Sla","description":"Freshness SLA — the one agent-facing gate-point for \"is the corpus current?\".\n\nFree, no auth, no DB cost (reads the same cached aggregate as /v1/corpus and\n/healthz). An agent that watches a topic can poll this and gate on `all_fresh`\n(or the per-source `stale` flags) instead of paying to discover staleness. Each\nsource carries its publish-cadence SLO and the measured lag, so the freshness\nclaim is verifiable rather than marketing — a source past its SLO is `stale: true`.\n\nThis consolidates the freshness signal that was previously only reachable by\nparsing /healthz or /v1/corpus; those endpoints keep their existing shapes.\n\nReturns:\n  as_of               — UTC timestamp this judgement was made (timestamp your gate).\n  rows                — total indexed docs.\n  latest              — newest doc published_at across the whole corpus.\n  ingest_lag_seconds  — seconds since that newest doc.\n  all_fresh           — true iff NO source is past its SLO (the single gate field).\n  stale_sources       — names of sources currently past SLO (empty when all_fresh).\n  sources             — per-source {source, latest, lag_hours, slo_hours, stale}.\n  recovery            — present only when stale_sources is non-empty. Same hint\n                        as /v1/health: per stale source, lag, SLO, catch_up_hours,\n                        next_action, and last_attempt when the scheduler recorded one.","operationId":"freshness_sla_v1_freshness_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/payment/account/{address}":{"get":{"summary":"Payment Account","operationId":"payment_account_v1_payment_account__address__get","parameters":[{"name":"address","in":"path","required":true,"schema":{"type":"string","title":"Address"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/payment/transactions/{address}":{"get":{"summary":"Payment Transactions","description":"Return on-chain USDC deposits seen by the monitor for `address`.\n\nPublic — addresses and tx hashes are public. Lets a paying agent verify\nits top-up landed before retrying a /query, and gives operators an audit\nsurface that doesn't require shell access to the SQLite ledger.","operationId":"payment_transactions_v1_payment_transactions__address__get","parameters":[{"name":"address","in":"path","required":true,"schema":{"type":"string","title":"Address"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/payment/challenge":{"post":{"summary":"Payment Challenge","description":"Mint a one-shot signing challenge. Required before every paid /query.\n\nThe returned `message` is what the client's wallet must sign with EIP-191\npersonal_sign. The signature + this nonce prove the caller controls the\nprivate key for `address` and cannot be spoofed by a third party.","operationId":"payment_challenge_v1_payment_challenge_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChallengeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","description":"Agent-discoverable markdown manifest. Sibling of /agents.json but\noptimized for LLMs scanning the open web for tools.\n\nFormat follows the emerging `llms.txt` convention (a top-level markdown\ndiscovery file at site root). Lets an agent crawl `https://fillinmcp.com/llms.txt`\nand decide whether to integrate without parsing OpenAPI or HTML.","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/agents.json":{"get":{"summary":"Agents Manifest","description":"Agent-discoverable manifest. Mirrors `agents.json` at the repo root.\n\nThe point: any LLM agent or ZHC orchestrator should be able to read one\nURL and bootstrap an integration — endpoint shapes, payment rails, MCP\nconfig, the 4-call funding recipe, all in one document.","operationId":"agents_manifest__well_known_agents_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/agents.json":{"get":{"summary":"Agents Manifest","description":"Agent-discoverable manifest. Mirrors `agents.json` at the repo root.\n\nThe point: any LLM agent or ZHC orchestrator should be able to read one\nURL and bootstrap an integration — endpoint shapes, payment rails, MCP\nconfig, the 4-call funding recipe, all in one document.","operationId":"agents_manifest_agents_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/billing/checkout":{"post":{"summary":"Billing Checkout","description":"Mint a bearer + open a Stripe Checkout session.\n\nThe bearer's raw token is stashed in Stripe session metadata so the\nsuccess page can reveal it once after payment. The hash is persisted on\n`checkout.session.completed` — see /v1/billing/webhook.","operationId":"billing_checkout_v1_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/billing/subscribe":{"post":{"summary":"Billing Subscribe","description":"Open a monthly-plan Stripe Checkout session (recurring card charge).\n\nEach paid invoice — first and every renewal — auto-credits the same\nbearer with the plan's monthly query balance via the invoice.paid webhook.\nGET this route's plan terms from /v1/billing/plan before subscribing.","operationId":"billing_subscribe_v1_billing_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/funnel":{"get":{"summary":"Funnel Stats","description":"Operator-only acquisition funnel: probe → trial → paid counters from\nthe ledger. Answers whether the leak is awareness (no probes) or\nconversion (probes that never become paid).","operationId":"funnel_stats_v1_funnel_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/agents":{"get":{"summary":"List Agents","description":"Operator-only: recent agent profiles (agent-graph v0).\n\nSame gate as `/v1/funnel` — master `FILLIN_API_KEY`. Not a public\ndirectory. Next increment: cohort/retention over `agent_events`.","operationId":"list_agents_v1_agents_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/agents/{agent_id}":{"get":{"summary":"Get Agent","description":"Operator-only: one agent profile + recent compact events.","operationId":"get_agent_v1_agents__agent_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","title":"Agent Id"}},{"name":"events","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Events"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/billing/plan":{"get":{"summary":"Billing Plan","description":"Public terms of the flat monthly tier. No auth.","operationId":"billing_plan_v1_billing_plan_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/billing/webhook":{"post":{"summary":"Billing Webhook","description":"Stripe webhook receiver. Verifies signature, credits the bearer ledger.\n\nIntentionally not rate-limited — Stripe retries on non-2xx and we already\ndedupe by event id, so a burst is harmless. The signature check rejects\nforged traffic before it touches any DB row.","operationId":"billing_webhook_v1_billing_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/billing/transactions":{"get":{"summary":"Billing Transactions","description":"Return the bearer's purchase history — one row per Stripe credit event.\n\nAuth is \"you must hold the bearer\". 404 if unknown so a drive-by scanner\ncan't enumerate which keys exist by reading the response. Same hygiene as\n/v1/billing/balance.","operationId":"billing_transactions_v1_billing_transactions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/subscriptions":{"get":{"summary":"List Subscriptions","description":"List all subscriptions for the bearer in the Authorization header.","operationId":"list_subscriptions_v1_subscriptions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"summary":"Create Subscription","description":"Create a topic-filtered subscription. Returns the new sub record.\n\nFor delivery_kind='webhook', the response includes `webhook_secret` ONCE —\nstore it; future GET responses won't reveal it. Use it to verify the\nX-Fillin-Signature HMAC on each delivered POST.","operationId":"create_subscription_v1_subscriptions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionCreateIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/subscriptions/{sub_id}":{"delete":{"summary":"Delete Subscription","operationId":"delete_subscription_v1_subscriptions__sub_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/subscribe/{sub_id}":{"get":{"summary":"Sse Subscribe","description":"SSE stream of doc events matching `sub_id`'s topic_filter.\n\nAuth: the bearer must own this subscription. Once connected, the client\nreceives one `event: doc` frame per matching doc and a `heartbeat`\ncomment every 15s so intermediaries (Cloudflare, nginx) don't reap the\nconnection as idle.","operationId":"sse_subscribe_v1_subscribe__sub_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/mints":{"post":{"summary":"Create Mint","description":"Mint an information asset. Returns the signed mint payload.\n\nFillin verifies every `evidence[].chunk_id` resolves to a real corpus\nrow, validates the typed reasoning graph, then HMAC-signs the canonical\npayload. The returned `attestation` is what buyers verify; it's also\nwhat makes the asset listable on the marketplace.","operationId":"create_mint_v1_mints_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Search Mints","description":"Search the marketplace by fingerprint. Exact-match on\n(model_family, cutoff_quarter, cluster_id) — the cluster wildcard '*'\nis what minters get before the daily clustering job runs.","operationId":"search_mints_v1_mints_get","parameters":[{"name":"model_family","in":"query","required":true,"schema":{"type":"string","title":"Model Family"}},{"name":"cutoff_quarter","in":"query","required":true,"schema":{"type":"string","title":"Cutoff Quarter"}},{"name":"cluster_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cluster Id"}},{"name":"only_for_sale","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Only For Sale"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/mints/{mint_id}":{"get":{"summary":"Get Mint","description":"Public read of a minted asset. No auth, no charge — discovery is free.\n\nFuture: the heavy `reasoning_graph` field gets paywalled by a separate\n`/v1/mints/{id}/buy` flow once the marketplace ships. For now everything\nis visible so we can prove the attestation contract end-to-end.","operationId":"get_mint_v1_mints__mint_id__get","parameters":[{"name":"mint_id","in":"path","required":true,"schema":{"type":"string","title":"Mint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/mints/{mint_id}/buy":{"post":{"summary":"Buy Mint","description":"Buy a listed mint. Atomically debits the buyer's bearer balance,\ncredits the seller's bearer minus Fillin's rake, records the transaction,\nand returns the full mint payload (the typed reasoning_graph that was\npaywalled to non-buyers in the future read endpoint).\n\nBearer-funded buyers only in MVP. Wallet-funded buyers will be added\nonce x402-out is wired; the seller MUST be a bearer-minter so we have\na SQLite balance to credit.","operationId":"buy_mint_v1_mints__mint_id__buy_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"mint_id","in":"path","required":true,"schema":{"type":"string","title":"Mint Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuyMintIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/billing/balance":{"get":{"summary":"Billing Balance","description":"Return remaining balance for the bearer in the Authorization header.\n\nNo auth ceremony beyond \"you must hold the bearer\". 404 if unknown so a\ndrive-by scanner can't enumerate which keys exist by reading the response.","operationId":"billing_balance_v1_billing_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/billing/success":{"get":{"summary":"Billing Success","description":"One-shot reveal of the raw bearer key after a successful Stripe payment.\n\nTwo layers of protection:\n- The Stripe session must be `paid` and livemode-matched.\n- The raw key is atomically claimed from the pending_reveal table — a\n  second hit on this URL returns 410 Gone, so a leaked session_id\n  (browser history, referrer header) can't be replayed.","operationId":"billing_success_billing_success_get","parameters":[{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/payment/info":{"get":{"summary":"Payment Info","description":"x402-style payment discovery. Unauthed: clients need this to pay.\n\nMirrors GLYPH's /v1/payment/info contract so agents that already speak\nthe GLYPH wallet handshake can pay Fillin the same way. When the server\nadvertises multiple chains (FILLIN_NETWORKS), `networks` enumerates them\nall; the top-level `network`/`usdc_contract` remain set to the primary\nchain for clients that haven't been updated to read the list.","operationId":"payment_info_v1_payment_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/stats":{"get":{"summary":"Get Stats","operationId":"get_stats_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/probe":{"post":{"summary":"Probe","description":"Free taste-test: one request per IP per UTC day, k=1, no payment.\n\nPass model_id (catalog id) or cutoff (ISO-8601). Only documents with\npublished_at strictly after that cutoff are returned. Omit both for the\n90-day default.\n\nLets an agent verify the corpus has something useful for its question\nbefore opening a wallet. The quota is per-IP and per UTC day; the IP\nis resolved from CF-Connecting-IP (see real_client_ip). Burst is\nadditionally capped by slowapi at 10/min as belt-and-suspenders.","operationId":"probe_v1_probe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/signup":{"post":{"summary":"Signup Api","description":"Mint a one-time trial bearer key worth TRIAL_QUERIES base queries.\n\nThe API lane of /signup — smithery.yaml has promised agents a 20-query\ntrial key, but the only implementation was the Stripe checkout HTML page,\na dead end for an autonomous agent. This endpoint closes that gap: no\nwallet, no card, no human. One key per IP per UTC day (reuses the probes\nquota table under a 'trial:' prefix), burst-capped by slowapi.\n\nThe raw key is returned ONCE and only its hash persists — same contract\nas the Stripe lane.","operationId":"signup_api_v1_signup_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TrialSignupIn"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/query":{"post":{"summary":"Query","operationId":"query_query_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/answer":{"post":{"summary":"Answer","description":"Synthesized mode: returns a citation-rich answer composed server-side\nfrom the top-k retrieved docs, alongside the raw docs for verification.\n\nCharges ANSWER_PRICE_USDC (default $0.02). Designed for weaker tool-calling\nmodels that can't reliably synthesize raw retrieval results; premium models\ncan keep using /query at $0.01 and reason over the docs themselves.","operationId":"answer_answer_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/query/cves":{"post":{"summary":"Query Cves Route","description":"CVE / supply-chain advisories slice ($0.02/call).","operationId":"query_cves_route_query_cves_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SliceQueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/query/papers":{"post":{"summary":"Query Papers Route","description":"Research papers slice ($0.03/call) — arXiv ∪ HF daily ∪ bioRxiv.","operationId":"query_papers_route_query_papers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SliceQueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/query/frontier":{"post":{"summary":"Query Frontier Route","description":"Frontier-lab / model-release slice ($0.05/call).","operationId":"query_frontier_route_query_frontier_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SliceQueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/query/markets":{"post":{"summary":"Query Markets Route","description":"Prediction-markets slice ($0.05/call) — Polymarket ∪ Kalshi ∪\nManifold ∪ Metaculus. Discovery across four venues in one call;\nprices in `text` are first-sight snapshots — hit the venue URL for\nlive pre-trade pricing.","operationId":"query_markets_route_query_markets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SliceQueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/glyph":{"post":{"summary":"Glyph Query Route","description":"Search, then return the result pieces as photo glyph image(s).\n\nBilled at the flat /query rate (the glyph render is free). Default returns\nJSON ({query, gap_days, n_results, glyph:{pages:[{png_b64,...}], manifest}}).\nPass `?format=png&page=N` to get raw image/png bytes for one page instead.","operationId":"glyph_query_route_v1_glyph_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"json","title":"Format"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Page"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlyphIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/glyph/sample":{"get":{"summary":"Glyph Sample Route","description":"Free, no-auth, no-corpus demo render. Lets an agent confirm its vision\nmodel can decode glyphs before paying, and powers the landing page.","operationId":"glyph_sample_route_v1_glyph_sample_get","parameters":[{"name":"tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"combined","title":"Mode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/glyph/sample.png":{"get":{"summary":"Glyph Sample Png Route","description":"Raw image/png of the free sample render (page N).","operationId":"glyph_sample_png_route_v1_glyph_sample_png_get","parameters":[{"name":"tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/retrieve":{"post":{"summary":"Retrieve Route","description":"One retrieval, one substrate out. Pass `model_id` or `cutoff` (explicit\ncutoff wins). `substrate` selects the form:\n\n  - \"text\"   (default): raw result pieces — identical payload to POST /query.\n  - \"glyph\"            : result pieces rendered as a VLM-readable photo-glyph.\n  - \"answer\"           : a citation-rich synthesized answer (needs an LLM key).\n  - \"auto\"             : pick the cheapest *legible* substrate for `reader`'s token\n                         billing (text on pixel-billed readers like Claude/GPT, dense\n                         glyph on flat-tile readers like Gemini/Qwen, answer for weak\n                         tool-callers). The response always carries a `selection`\n                         object {substrate, reader, rationale, estimates} explaining\n                         the choice from the honest token math.\n\nPricing (kept consistent with the dedicated endpoints): resolving to text or glyph\nbills the flat /query rate; resolving to answer bills the answer rate. Because the\nauth dependency must charge before the substrate is known, this route charges the\n(higher) answer rate up front and REFUNDS the delta when the chosen substrate is\ntext/glyph — to the x402 payer or the Stripe-funded bearer alike — so the caller pays\nexactly the right rate on either rail and is never undercharged. \"Sign for the max,\nsettle down\" is also the only model x402 allows: a nonce authorizes exactly one spend,\nso a post-hoc answer upcharge would need a second signed handshake or an unsigned\ndebit (a trust-on-header regression). The existing refund-on-error pattern is\npreserved for failures.","operationId":"retrieve_route_v1_retrieve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/encode":{"post":{"summary":"Encode Route","description":"Bring your own text -> the cheapest substrate for your reader, with the\nhonest per-reader-class token manifest. Billed at the flat /query rate\nregardless of which substrate is chosen (text and glyph cost the same\nhere — there is no differential 'answer' substrate to charge-then-refund\nfor, unlike /v1/retrieve).","operationId":"encode_route_v1_encode_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EncodeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/encode/sample":{"post":{"summary":"Encode Sample Route","description":"Free, no-auth, no-corpus proof: paste YOUR OWN text, see it encoded and\nthe honest token math, before paying anything. Byte-capped against abuse.\nSame lesson as /v1/glyph/sample: a stranger needs to see a real artifact\nof their own content, not a canned demo, to trust the pricing.","operationId":"encode_sample_route_v1_encode_sample_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EncodeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AnswerOut":{"properties":{"cutoff":{"type":"string","title":"Cutoff"},"query":{"type":"string","title":"Query"},"gap_days":{"type":"number","title":"Gap Days"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer"},"citations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Citations"},"corpus_match":{"type":"string","title":"Corpus Match"},"top_score":{"type":"number","title":"Top Score"},"model":{"type":"string","title":"Model"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"results":{"items":{"$ref":"#/components/schemas/Hit"},"type":"array","title":"Results"},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"},"cutoff_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cutoff Source"},"model_cutoff":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Cutoff"}},"type":"object","required":["cutoff","query","gap_days","answer","citations","corpus_match","top_score","model","results"],"title":"AnswerOut"},"BuyMintIn":{"properties":{"model_family":{"type":"string","title":"Model Family","description":"Buyer's declared model context — registered alongside the buy"},"cutoff_quarter":{"type":"string","title":"Cutoff Quarter","description":"Buyer's declared cutoff — registered alongside the buy"}},"type":"object","required":["model_family","cutoff_quarter"],"title":"BuyMintIn"},"ChallengeIn":{"properties":{"address":{"type":"string","maxLength":42,"minLength":42,"title":"Address"}},"type":"object","required":["address"],"title":"ChallengeIn"},"CheckoutIn":{"properties":{"email":{"type":"string","maxLength":320,"minLength":3,"title":"Email"},"usd_amount":{"type":"number","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Usd Amount"}},"type":"object","required":["email","usd_amount"],"title":"CheckoutIn"},"EncodeIn":{"properties":{"text":{"anyOf":[{"type":"string","maxLength":40000},{"type":"null"}],"title":"Text","description":"Text to encode. Provide this or `texts`, not both."},"texts":{"anyOf":[{"items":{"type":"string","maxLength":40000},"type":"array","maxItems":50},{"type":"null"}],"title":"Texts","description":"Multiple texts, joined as one document. Provide this or `text`, not both. Each item and the joined total are still bounded by the same character cap as `text`."},"reader":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reader","description":"Your reader model (e.g. 'claude', 'gemini', 'qwen2.5-vl', 'gpt-4o'). If omitted, inferred from the 'X-Reader-Model' request header or the User-Agent; an unidentified caller is treated as pixel-billed (text)."},"substrate":{"type":"string","title":"Substrate","description":"'auto' (default; picks the cheapest legible substrate for `reader`) | 'text' | 'glyph'.","default":"auto"},"verbatim":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Verbatim","description":"Set true if this text must stay exact (code, hashes, quotes) — auto then never picks glyph, which paraphrases. None auto-detects fenced code blocks."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Glyph density tier override for substrate='glyph': '6x' | '10x' | '15x'. Ignored for substrate='auto' — the picker's own tier is used there so the claimed token estimate always matches the rendered artifact."}},"type":"object","title":"EncodeIn"},"GlyphIn":{"properties":{"cutoff":{"type":"string","format":"date-time","title":"Cutoff","description":"ISO8601 — your model's training cutoff"},"query":{"type":"string","maxLength":512,"minLength":1,"title":"Query"},"k":{"type":"integer","maximum":20.0,"minimum":1.0,"title":"K","default":6},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Density tier: '6x' | '10x' | '15x'. Default '10x'."},"mode":{"type":"string","title":"Mode","description":"'combined' (all pieces on shared pages, token-efficient) or 'per_piece' (one image per result).","default":"combined"},"sources":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sources","description":"Optional source filter, same semantics as /query."}},"type":"object","required":["cutoff","query"],"title":"GlyphIn"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Hit":{"properties":{"id":{"type":"string","title":"Id"},"source":{"type":"string","title":"Source"},"url":{"type":"string","title":"Url"},"published_at":{"type":"string","title":"Published At"},"title":{"type":"string","title":"Title"},"text":{"type":"string","title":"Text"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"severity_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Severity Score"},"affected":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Affected"}},"type":"object","required":["id","source","url","published_at","title","text"],"title":"Hit"},"MintEvidenceIn":{"properties":{"chunk_id":{"type":"string","title":"Chunk Id","description":"LanceDB row id Fillin will verify exists"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Convenience copy of the source URL"}},"type":"object","required":["chunk_id"],"title":"MintEvidenceIn"},"MintIn":{"properties":{"model_family":{"type":"string","title":"Model Family","description":"e.g. 'claude-opus-4-7', 'gpt-5'"},"cutoff_quarter":{"type":"string","title":"Cutoff Quarter","description":"e.g. '2026-Q1' — coarse for fungibility"},"query":{"type":"string","title":"Query","description":"The original question the agent asked Fillin"},"query_embedding":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Query Embedding","description":"Optional 384-d MiniLM embedding of the query, for cluster routing"},"evidence":{"items":{"$ref":"#/components/schemas/MintEvidenceIn"},"type":"array","title":"Evidence","description":"Fillin chunk_ids the reasoning cites. Every id must resolve in the corpus."},"reasoning_graph":{"items":{"$ref":"#/components/schemas/MintReasoningStepIn"},"type":"array","title":"Reasoning Graph","description":"Typed reasoning steps. Free-text is rejected — typed traces are the moat."},"conclusion":{"type":"string","title":"Conclusion"},"list_price_usdc":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"List Price Usdc","description":"Price the minter wants to resell at. NULL = mint but don't list."}},"type":"object","required":["model_family","cutoff_quarter","query","evidence","reasoning_graph","conclusion"],"title":"MintIn"},"MintReasoningStepIn":{"properties":{"claim":{"type":"string","title":"Claim"},"evidence_chunk_id":{"type":"string","title":"Evidence Chunk Id","description":"Must appear in `evidence`"},"confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence"},"derived_claim":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Derived Claim"}},"type":"object","required":["claim","evidence_chunk_id","confidence"],"title":"MintReasoningStepIn"},"ProbeIn":{"properties":{"cutoff":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cutoff","description":"ISO8601 training cutoff. Optional. Documents with published_at strictly after this instant are returned. Defaults to 90 days ago when both cutoff and model_id are omitted. An explicit cutoff wins if model_id is also set."},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"Catalog model id (for example claude-sonnet-5, gpt-5.4, gemini-2.5-pro, llama-4-scout, grok-4.6). When cutoff is omitted, retrieval uses that model's training cutoff. Unknown ids are rejected."},"query":{"type":"string","maxLength":512,"minLength":1,"title":"Query"}},"type":"object","required":["query"],"title":"ProbeIn"},"QueryIn":{"properties":{"cutoff":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cutoff","description":"ISO8601 training cutoff. Documents with published_at strictly after this instant are returned. Optional when model_id is set; an explicit cutoff wins if both are sent."},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"Catalog model id (for example claude-sonnet-5, gpt-5.4, gemini-2.5-pro, llama-4-scout, grok-4.6). Resolves to that model's training cutoff when cutoff is omitted. See data/model_cutoffs.json."},"query":{"type":"string","maxLength":512,"minLength":1,"title":"Query","description":"What topic / question"},"k":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"K","default":10},"glyph":{"type":"boolean","title":"Glyph","description":"If true, also return the result pieces rendered as a photo glyph (a dense, VLM-readable image) under the `glyph` field. Lets a vision model read results as one image. See /v1/glyph for image bytes.","default":false},"glyph_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Glyph Tier","description":"Glyph density tier: '6x' | '10x' | '15x'. Default '10x'."},"sources":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sources","description":"Optional list of source names to restrict retrieval. Each must be a known source from the ingest registry (e.g. 'cves', 'papers', 'frontier', 'arena', 'arxiv', 'rss', 'hackernews', 'github_releases'). When omitted, all sources are searched. Pricing is unchanged: a filtered /query is billed at the flat /query rate. For per-slice pricing, use the dedicated /query/{slice} routes."},"substrate":{"type":"string","title":"Substrate","description":"Delivery substrate for POST /v1/retrieve: 'text' | 'glyph' | 'answer' | 'auto'. 'auto' runs one retrieval and returns whichever substrate is cheapest for your reader model's token billing (text on Claude/GPT pixel billing, dense glyph on Gemini/Qwen flat-tile billing, a synthesized answer for weak tool-callers). Ignored by /query, /answer, /v1/glyph.","default":"text"},"reader":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reader","description":"Your reader model, used by substrate='auto' to pick the cheapest legible form (e.g. 'claude', 'gemini', 'qwen2.5-vl', 'gpt-4o', 'llama-3.3'). If omitted, the server auto-detects it from the 'X-Reader-Model' request header (declare it once at the transport layer) or the User-Agent; an unidentified caller is treated as pixel-billed (the safe default — auto returns text rather than overclaim a saving). Ignored unless substrate='auto'."},"verbatim":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Verbatim","description":"For substrate='auto': set true if you need exact/verbatim text or code (auto then never picks glyph, which paraphrases). None auto-detects from the result sources/content. Ignored unless substrate='auto'."}},"type":"object","required":["query"],"title":"QueryIn"},"QueryOut":{"properties":{"cutoff":{"type":"string","title":"Cutoff"},"query":{"type":"string","title":"Query"},"gap_days":{"type":"number","title":"Gap Days"},"results":{"items":{"$ref":"#/components/schemas/Hit"},"type":"array","title":"Results"},"top_score":{"type":"number","title":"Top Score","default":0.0},"corpus_match":{"type":"string","title":"Corpus Match","default":"none"},"glyph":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Glyph"},"substrate_estimate":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Substrate Estimate"},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"},"cutoff_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cutoff Source"},"model_cutoff":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Cutoff"},"agent_next":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Agent Next"}},"type":"object","required":["cutoff","query","gap_days","results"],"title":"QueryOut"},"SliceQueryIn":{"properties":{"cutoff":{"type":"string","format":"date-time","title":"Cutoff","description":"ISO8601 — your model's training cutoff"},"query":{"type":"string","maxLength":512,"minLength":1,"title":"Query"},"k":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"K","default":10},"min_severity":{"anyOf":[{"type":"number","maximum":10.0,"minimum":0.0},{"type":"null"}],"title":"Min Severity"}},"type":"object","required":["cutoff","query"],"title":"SliceQueryIn","description":"Request body for the dedicated /query/{slice} routes.\n\nSame shape as QueryIn minus the `sources` field — the slice is fixed by\nthe route, so allowing a `sources` override would defeat the per-slice\npricing model."},"SubscribeIn":{"properties":{"email":{"type":"string","maxLength":320,"minLength":3,"title":"Email"}},"type":"object","required":["email"],"title":"SubscribeIn"},"SubscriptionCreateIn":{"properties":{"topic_filter":{"additionalProperties":true,"type":"object","title":"Topic Filter","description":"Match predicate (AND across keys). Allowed keys: source: list[str], min_severity: float in [0,10], keywords: list[str] (case-insensitive substring on title/text), affected_ecosystem: list[str] (only matches CVE rows)."},"delivery_kind":{"type":"string","title":"Delivery Kind","description":"'sse' or 'webhook'"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url","description":"Required when delivery_kind='webhook'. Must be http(s)."}},"type":"object","required":["delivery_kind"],"title":"SubscriptionCreateIn"},"TrialSignupIn":{"properties":{"email":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"title":"Email"}},"type":"object","title":"TrialSignupIn"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}