{
  "openapi": "3.1.0",
  "info": {
    "title": "Hanging Context public read API",
    "version": "2026-10-15",
    "summary": "Free, keyless JSON, Markdown and feeds for Hanging Context stories.",
    "description": "Hanging Context publishes fresh context for agents. Stories are rebuilt every 12 hours. Each claim cites a Synorb Manifest. Every endpoint here is a read. No key is necessary. The same stories are also available through the MCP server at https://hangingcontext.com/mcp.",
    "termsOfService": "https://hangingcontext.com/terms/reuse/",
    "contact": {
      "name": "Hanging Context",
      "email": "team@synorb.com",
      "url": "https://hangingcontext.com/contact/"
    },
    "license": {
      "name": "Hanging Context reuse terms",
      "url": "https://hangingcontext.com/terms/reuse/"
    }
  },
  "servers": [
    {
      "url": "https://hangingcontext.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "stories",
      "description": "Stories and lists of stories."
    },
    {
      "name": "ask",
      "description": "Ask a question in plain words."
    },
    {
      "name": "feeds",
      "description": "Feeds for readers that poll."
    },
    {
      "name": "policy",
      "description": "Reuse terms."
    }
  ],
  "security": [],
  "paths": {
    "/editions/latest.json": {
      "get": {
        "operationId": "getLatestStories",
        "tags": [
          "stories"
        ],
        "summary": "Get the latest stories",
        "description": "Get the stories from the last 12 hours and the last 24 hours. The reply also lists the topics and the feed URLs.",
        "responses": {
          "200": {
            "description": "The latest stories.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LatestStories"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/n/{topic}/index.json": {
      "get": {
        "operationId": "getTopicStories",
        "tags": [
          "stories"
        ],
        "summary": "Get the stories of one topic",
        "description": "Get the recent stories of one topic, newest first.",
        "parameters": [
          {
            "name": "topic",
            "in": "path",
            "required": true,
            "description": "Topic slug. Get the slugs from the id of each topic in /editions/latest.json.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$",
              "example": "artificial-intelligence"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stories in the topic.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoryList"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/stories/{date}/{slug}/index.json": {
      "get": {
        "operationId": "getStory",
        "tags": [
          "stories"
        ],
        "summary": "Get one story as JSON",
        "description": "Get one story with its sections, key facts and cited Manifests.",
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "description": "Story date in UTC, as YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-10-15"
            }
          },
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Story slug, from the url field of a story list.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{3,80}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The story.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Story"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/stories/{date}/{slug}/index.md": {
      "get": {
        "operationId": "getStoryMarkdown",
        "tags": [
          "stories"
        ],
        "summary": "Get one story as Markdown",
        "description": "Get one story as Markdown. Each paragraph cites Manifest ids.",
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "description": "Story date in UTC, as YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-10-15"
            }
          },
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Story slug, from the url field of a story list.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{3,80}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The story as Markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/roundups/index.json": {
      "get": {
        "operationId": "listRoundups",
        "tags": [
          "stories"
        ],
        "summary": "List the roundups",
        "description": "List the recent roundups. A roundup groups related stories.",
        "responses": {
          "200": {
            "description": "The recent roundups.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/ask": {
      "get": {
        "operationId": "askQuestionGet",
        "tags": [
          "ask"
        ],
        "summary": "Ask a question (GET)",
        "description": "Answer a question from recent stories. The reply copies facts word for word. It uses no LLM. The protocol is NLWeb. Send Accept: text/event-stream or stream=true to stream.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "The question, in plain words. The name q is also accepted.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 500
            }
          },
          {
            "name": "stream",
            "in": "query",
            "required": false,
            "description": "Set to true to get text/event-stream.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AskAnswer"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many calls from this address. Wait, then call again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "askQuestionPost",
        "tags": [
          "ask"
        ],
        "summary": "Ask a question (POST)",
        "description": "Answer a question from recent stories. The reply copies facts word for word. It uses no LLM. Set prefer.streaming to true to get text/event-stream.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AskAnswer"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many calls from this address. Wait, then call again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/editions/feed.json": {
      "get": {
        "operationId": "getJsonFeed",
        "tags": [
          "feeds"
        ],
        "summary": "Get the JSON Feed",
        "description": "Get all stories as a JSON Feed, newest first.",
        "responses": {
          "200": {
            "description": "A JSON Feed document.",
            "content": {
              "application/feed+json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/editions/feed.xml": {
      "get": {
        "operationId": "getRssFeed",
        "tags": [
          "feeds"
        ],
        "summary": "Get the RSS feed",
        "description": "Get all stories as an RSS feed, newest first.",
        "responses": {
          "200": {
            "description": "An RSS document.",
            "content": {
              "application/rss+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/editions/atom.xml": {
      "get": {
        "operationId": "getAtomFeed",
        "tags": [
          "feeds"
        ],
        "summary": "Get the Atom feed",
        "description": "Get all stories as an Atom feed, newest first.",
        "responses": {
          "200": {
            "description": "An Atom document.",
            "content": {
              "application/atom+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/reuse.json": {
      "get": {
        "operationId": "getReuseTerms",
        "tags": [
          "policy"
        ],
        "summary": "Get the reuse terms",
        "description": "Get the reuse terms for stories in machine-readable form.",
        "responses": {
          "200": {
            "description": "The reuse terms.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReuseTerms"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is JSON, Markdown or HTML, chosen by the Accept header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "The JSON error body.",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A short error code.",
            "example": "empty_question"
          },
          "message": {
            "type": "string",
            "description": "What is wrong."
          },
          "next_step": {
            "type": "string",
            "description": "What to do next."
          },
          "retry_after": {
            "type": "integer",
            "description": "Seconds to wait. Only for code 429."
          }
        }
      },
      "StorySummary": {
        "type": "object",
        "description": "A story in a list.",
        "required": [
          "slug",
          "url",
          "headline",
          "published_at"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "json": {
            "type": "string",
            "format": "uri"
          },
          "markdown": {
            "type": "string",
            "format": "uri"
          },
          "headline": {
            "type": "string"
          },
          "dek": {
            "type": "string"
          },
          "beat": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "trust": {
            "type": "string"
          },
          "source_count": {
            "type": "integer"
          },
          "cited_manifest_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      },
      "StoryList": {
        "type": "object",
        "description": "A list of stories.",
        "required": [
          "stories"
        ],
        "properties": {
          "schema": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "id": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "story_count": {
            "type": "integer"
          },
          "stories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StorySummary"
            }
          }
        },
        "additionalProperties": true
      },
      "LatestStories": {
        "type": "object",
        "description": "The latest stories, the topics and the feeds.",
        "required": [
          "stories",
          "generated_at"
        ],
        "properties": {
          "description": {
            "type": "string"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "stories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StorySummary"
            }
          },
          "published_last_24h": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StorySummary"
            }
          },
          "newsrooms": {
            "type": "array",
            "description": "The topics. Use id as the topic slug.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "json": {
                  "type": "string",
                  "format": "uri"
                },
                "description": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          },
          "feeds": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        },
        "additionalProperties": true
      },
      "Story": {
        "type": "object",
        "description": "One story with the Manifests it cites.",
        "required": [
          "slug",
          "url",
          "headline",
          "published_at",
          "sections",
          "cited_manifest_ids"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "headline": {
            "type": "string"
          },
          "dek": {
            "type": "string"
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "key_facts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "text": {
                  "type": "string"
                },
                "manifest_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "additionalProperties": true
            }
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "unresolved": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cited_manifest_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "manifests": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "reuse": {
            "$ref": "#/components/schemas/ReuseTerms"
          }
        },
        "additionalProperties": true
      },
      "ReuseTerms": {
        "type": "object",
        "description": "The reuse terms for stories.",
        "properties": {
          "version": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "attribution": {
            "type": "string"
          },
          "link_rule": {
            "type": "string"
          },
          "keep_ids_rule": {
            "type": "string"
          },
          "no_endorsement": {
            "type": "string"
          },
          "license_url": {
            "type": "string",
            "format": "uri"
          },
          "machine_url": {
            "type": "string",
            "format": "uri"
          }
        },
        "additionalProperties": true
      },
      "AskRequest": {
        "type": "object",
        "description": "An NLWeb question.",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "The question."
          },
          "prefer": {
            "type": "object",
            "properties": {
              "streaming": {
                "type": "boolean",
                "description": "Set to true for text/event-stream."
              }
            }
          },
          "topic": {
            "type": "string",
            "description": "Only search this topic slug."
          },
          "days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "default": 7
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "default": 5
          }
        }
      },
      "AskAnswer": {
        "type": "object",
        "description": "An NLWeb answer. Each result is a fact copied word for word from a story.",
        "required": [
          "_meta",
          "query",
          "results"
        ],
        "properties": {
          "_meta": {
            "type": "object",
            "required": [
              "response_type",
              "version"
            ],
            "properties": {
              "response_type": {
                "type": "string",
                "example": "answer"
              },
              "version": {
                "type": "string"
              },
              "protocol": {
                "type": "string"
              },
              "uses_llm": {
                "type": "boolean"
              }
            }
          },
          "query": {
            "type": "string"
          },
          "no_match": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "datePublished": {
                  "type": "string"
                },
                "manifest_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "additionalProperties": true
            }
          },
          "next_step": {
            "type": "string"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
