{"openapi":"3.1.0","info":{"title":"Horizon API","version":"1.0.0","description":"Full-depth, key-gated access to Horizon's aggregated AI-industry corpus — LLM-scored news, semantic search, a cited RAG answer endpoint, an incremental delta feed, regional lenses (china, eu, south-america), briefing history, and webhooks. Authenticate with an API key: `Authorization: Bearer hzn_live_...` (mint one at https://horizon.alchemylab.sh/api-keys). Rate limit 120 req/min; monthly quota by plan (Standard 10k, Pro 100k) — every response carries X-RateLimit-* and X-Quota-* headers, and GET /api/v1/usage reports the current state. The free, no-auth tiers (/api/public REST + /api/mcp MCP server) are described in https://horizon.alchemylab.sh/llms.txt. Cite \"Horizon\" and link back when you use this content.","contact":{"url":"https://horizon.alchemylab.sh"}},"servers":[{"url":"https://horizon.alchemylab.sh"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"search","description":"Query the corpus"},{"name":"feed","description":"Incremental polling"},{"name":"answers","description":"Synthesized cited answers"},{"name":"briefings","description":"Daily briefing history"},{"name":"webhooks","description":"Push subscriptions"},{"name":"account","description":"Usage & quota"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Horizon API key (`hzn_live_...`), minted at https://horizon.alchemylab.sh/api-keys."}},"schemas":{"ContentItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"source":{"type":"string","enum":["hackernews","reddit","twitter","bluesky","rss","arxiv","huggingface","lobsters","modelscope"]},"url":{"type":"string","nullable":true},"title":{"type":"string"},"body":{"type":"string","nullable":true},"author":{"type":"string","nullable":true},"publishedAt":{"type":"string","format":"date-time"},"relevanceScore":{"type":"number","nullable":true,"description":"0–1 AI-relevance score."},"trendingScore":{"type":"number","nullable":true},"topics":{"type":"array","items":{"type":"string","enum":["models","tools","use-cases","regulation","research","funding","opinion","tutorial"]}},"clusterSize":{"type":"integer","description":"How many near-duplicate stories this representative stands for."}},"required":["id","source","title","publishedAt"]}},"responses":{"Unauthorized":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"RateLimited":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"BadRequest":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"paths":{"/api/v1/search":{"get":{"tags":["search"],"operationId":"searchContent","summary":"Full-text search over the corpus","description":"Full-depth search (the free tier returns only a 3-item teaser). Near-duplicate stories are collapsed to one representative per cluster by default.","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search terms (title + body)."},{"name":"source","in":"query","schema":{"type":"string","enum":["hackernews","reddit","twitter","bluesky","rss","arxiv","huggingface","lobsters","modelscope"]},"description":"Filter to one ingestion source."},{"name":"topic","in":"query","schema":{"type":"string","enum":["models","tools","use-cases","regulation","research","funding","opinion","tutorial"]},"description":"Filter to one topic tag."},{"name":"region","in":"query","schema":{"type":"string","enum":["china","eu","south-america"]},"description":"Filter to a regional lens."},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Only items published on/after this date (ISO)."},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Only items published on/before this date (ISO)."},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0}},{"name":"collapse","in":"query","schema":{"type":"boolean","default":true},"description":"Collapse near-duplicate clusters; pass false for every matching row."}],"responses":{"200":{"description":"Matching items, most-trending first.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ContentItem"}},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}}},"attribution":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/feed":{"get":{"tags":["feed"],"operationId":"getDeltaFeed","summary":"Incremental delta feed","description":"Poll for newly-added items without re-fetching. Pass the returned nextCursor back as `since` on the next call. Full bodies, up to 200 items/page.","parameters":[{"name":"since","in":"query","schema":{"type":"string"},"description":"Opaque cursor from a previous nextCursor. Omit on the first call to start from the latest."},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":200}}],"responses":{"200":{"description":"Items oldest→newest plus a forward cursor.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ContentItem"}},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/ask":{"post":{"tags":["answers"],"operationId":"askHorizon","summary":"Synthesized, cited answer (RAG)","description":"Ask a natural-language question and get a synthesized answer grounded only in Horizon's recent corpus, with inline [n] citations. One call instead of search-then-read.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"question":{"type":"string","minLength":3,"maxLength":500,"description":"e.g. 'what did OpenAI ship this week?'"},"days":{"type":"integer","default":14,"minimum":1,"maximum":90,"description":"How many days back to retrieve over."},"limit":{"type":"integer","description":"Max sources to retrieve."}},"required":["question"]}}}},"responses":{"200":{"description":"Answer with citations.","content":{"application/json":{"schema":{"type":"object","properties":{"question":{"type":"string"},"answer":{"type":"string","description":"Prose with inline [n] citation markers."},"citations":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer"},"title":{"type":"string"},"url":{"type":"string","nullable":true},"source":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"}}}},"retrieved":{"type":"integer","description":"How many sources were retrieved."},"attribution":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"Answer synthesis temporarily unavailable."}}}},"/api/v1/related":{"get":{"tags":["search"],"operationId":"getRelated","summary":"Semantic 'more like this'","description":"The most semantically similar recent items to a given one, over the embeddings.","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"An item id from search/feed."},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"minimum":1,"maximum":25}}],"responses":{"200":{"description":"Similar items with a similarity score.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ContentItem"},{"type":"object","properties":{"similarity":{"type":"number","description":"Cosine similarity, 0–1."}}}]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/briefings":{"get":{"tags":["briefings"],"operationId":"listBriefings","summary":"Daily briefing history","description":"The complete daily-briefing archive (no 7-day cap, unlike the free tier).","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"limit","in":"query","schema":{"type":"integer","default":30}}],"responses":{"200":{"description":"Briefings, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"briefings":{"type":"array","items":{"type":"object"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/usage":{"get":{"tags":["account"],"operationId":"getUsage","summary":"Rate-limit & quota self-check","description":"Your key's current rate-limit and monthly-quota state, so you can pace yourself.","responses":{"200":{"description":"Current usage.","content":{"application/json":{"schema":{"type":"object","properties":{"rateLimit":{"type":"object","properties":{"limit":{"type":"integer"},"remaining":{"type":"integer"},"resetSeconds":{"type":"integer"},"window":{"type":"string"}}},"quota":{"type":"object","description":"{ unmetered: true } on unmetered keys, otherwise limit/used/remaining/resetsAt."},"usageThisMonth":{"type":"object","description":"Per-endpoint request counts for the current calendar month.","properties":{"month":{"type":"string","description":"YYYY-MM"},"byEndpoint":{"type":"object","additionalProperties":{"type":"integer"},"description":"endpoint → request count, e.g. { search: 120, ask: 30 }"}}},"attribution":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/webhooks":{"get":{"tags":["webhooks"],"operationId":"listWebhooks","summary":"List your webhooks","responses":{"200":{"description":"Your registered webhooks.","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"type":"object"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["webhooks"],"operationId":"createWebhook","summary":"Register a webhook","description":"Newly-matched items (by topic/entity/keyword, or all) are POSTed to your URL, HMAC-signed. The signing secret is returned once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"topics":{"type":"array","items":{"type":"string"}},"entities":{"type":"array","items":{"type":"string"}},"keywords":{"type":"array","items":{"type":"string"}}},"required":["url"]}}}},"responses":{"201":{"description":"Created (signing secret included once).","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/webhooks/{id}":{"delete":{"tags":["webhooks"],"operationId":"deleteWebhook","summary":"Delete a webhook","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/BadRequest"}}}},"/api/v1/webhooks/{id}/test":{"post":{"tags":["webhooks"],"operationId":"testWebhook","summary":"Fire a signed test event","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Test event delivered."},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}