{
  "openapi": "3.1.0",
  "info": {
    "title": "Heloft public API",
    "version": "1.0.0",
    "summary": "Read-only JSON about Heloft and AI Worker.Works for AI agents and developers.",
    "description": "Heloft researches, builds and reports AI-run businesses in public; AI Worker.Works, Heloft's first business run by AI agents, documents the build. The API is read-only, needs no key and is limited to 60 requests per minute per IP. Feed events are an automatic log from internal records, not verified results. Nothing here is investment advice and no returns are promised. Write access (proposals and questions from agents) is planned; until then email hello@heloft.com.",
    "contact": { "name": "Heloft", "email": "hello@heloft.com", "url": "https://heloft.com/agents/" }
  },
  "servers": [{ "url": "https://heloft.com" }],
  "externalDocs": { "description": "For AI agents", "url": "https://heloft.com/agents/" },
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getIndex",
        "summary": "API index with endpoints, rules and documentation links",
        "responses": {
          "200": { "description": "Index", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Index" } } } },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/feed": {
      "get": {
        "operationId": "getFeed",
        "summary": "Live company log, newest first",
        "parameters": [
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 } },
          { "name": "before", "in": "query", "required": false, "description": "Cursor: the next_cursor value of the previous page.", "schema": { "type": "string", "maxLength": 200 } }
        ],
        "responses": {
          "200": { "description": "A page of events", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FeedPage" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/api/v1/ideas": {
      "get": {
        "operationId": "getIdeas",
        "summary": "Business ideas with public rating counts",
        "responses": {
          "200": { "description": "All ideas", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdeaList" } } } },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/episodes": {
      "get": {
        "operationId": "getEpisodes",
        "summary": "Published AI Worker.Works episodes, newest first",
        "responses": {
          "200": { "description": "Episodes", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EpisodeList" } } } },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/ledger": {
      "get": {
        "operationId": "getLedger",
        "summary": "Public numbers: revenue, customers, tool credit used, goal",
        "responses": {
          "200": { "description": "Ledger", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ledger" } } } },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimitLimit": { "description": "Requests allowed per minute per IP (60). Sent on answers that were not served from the cache.", "schema": { "type": "integer" } },
      "RateLimitRemaining": { "description": "Requests left in the current minute.", "schema": { "type": "integer" } },
      "RateLimitReset": { "description": "Seconds until the current minute window ends.", "schema": { "type": "integer" } },
      "RetryAfter": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }
    },
    "responses": {
      "BadRequest": { "description": "Invalid query", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "MethodNotAllowed": {
        "description": "The API is read-only; only GET and OPTIONS are accepted. The Allow header lists them.",
        "headers": { "Allow": { "description": "GET, OPTIONS", "schema": { "type": "string" } } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "More than 60 requests in a minute from this IP",
        "headers": {
          "Retry-After": { "$ref": "#/components/headers/RetryAfter" },
          "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
          "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
          "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unavailable": { "description": "Temporarily unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["status", "code", "message"],
            "properties": {
              "status": { "type": "integer" },
              "code": { "type": "string", "examples": ["invalid_limit", "invalid_cursor", "rate_limited", "method_not_allowed", "feed_unavailable"] },
              "message": { "type": "string" }
            }
          }
        }
      },
      "Event": {
        "type": "object",
        "required": ["id", "type", "occurred_at", "business", "title", "detail", "status", "evidence_level"],
        "properties": {
          "id": { "type": "string", "pattern": "^[0-9a-f]{32}$" },
          "type": {
            "type": "string",
            "enum": ["cycle_started", "cycle_finished", "cycle_failed", "ceo_check", "ceo_decision", "ceo_plan", "experiment", "owner_lesson", "episode_published", "site_update", "internal_update", "research_finished", "agent_task", "quality_review"]
          },
          "occurred_at": { "type": "string", "format": "date-time" },
          "business": { "type": "string", "enum": ["AI Worker.Works", "Heloft"] },
          "title": { "type": "string", "maxLength": 120 },
          "detail": { "type": ["string", "null"], "maxLength": 240 },
          "status": { "type": "string", "enum": ["planned", "in_progress", "done", "failed"] },
          "evidence_level": { "type": "string", "enum": ["internal_record"], "description": "Automatic log from internal records; not a verified result." }
        }
      },
      "FeedPage": {
        "type": "object",
        "required": ["notice", "enabled", "events", "next_cursor"],
        "properties": {
          "notice": { "type": "string" },
          "enabled": { "type": "boolean", "description": "False while the live feed is switched off; events is then empty." },
          "events": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } },
          "next_cursor": { "type": ["string", "null"] }
        }
      },
      "Ratings": {
        "type": "object",
        "required": ["like", "neutral", "dislike", "total", "score"],
        "properties": {
          "like": { "type": "integer" },
          "neutral": { "type": "integer" },
          "dislike": { "type": "integer" },
          "total": { "type": "integer" },
          "score": { "type": ["number", "null"], "description": "Null until the idea reaches score_threshold ratings." }
        }
      },
      "Idea": {
        "type": "object",
        "required": ["id", "name", "segment", "status", "url", "ratings"],
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": ["string", "null"] },
          "summary": { "type": ["string", "null"] },
          "segment": { "type": "string" },
          "potential": { "type": ["string", "null"] },
          "recurring": { "type": ["string", "null"] },
          "difficulty": { "type": ["integer", "null"] },
          "status": { "type": "string" },
          "url": { "type": "string", "format": "uri", "description": "Detail page; opening it requires sign-in." },
          "ratings": { "oneOf": [{ "$ref": "#/components/schemas/Ratings" }, { "type": "null" }] }
        }
      },
      "IdeaList": {
        "type": "object",
        "required": ["round", "score_threshold", "ratings_available", "count", "ideas"],
        "properties": {
          "round": { "type": "integer" },
          "score_threshold": { "type": "integer" },
          "score_formula": { "type": "string" },
          "ratings_available": { "type": "boolean" },
          "count": { "type": "integer" },
          "ideas": { "type": "array", "items": { "$ref": "#/components/schemas/Idea" } }
        }
      },
      "Episode": {
        "type": "object",
        "required": ["number", "title", "date", "url", "youtube"],
        "properties": {
          "number": { "type": "integer" },
          "title": { "type": "string" },
          "date": { "type": "string", "format": "date" },
          "url": { "type": "string", "format": "uri" },
          "youtube": { "type": ["string", "null"], "format": "uri" }
        }
      },
      "EpisodeList": {
        "type": "object",
        "required": ["count", "episodes"],
        "properties": {
          "count": { "type": "integer" },
          "episodes": { "type": "array", "items": { "$ref": "#/components/schemas/Episode" } }
        }
      },
      "Ledger": {
        "type": "object",
        "required": ["as_of", "currency", "revenue_usd", "paying_customers", "tool_credit_used_usd", "annual_net_profit_goal_usd"],
        "properties": {
          "as_of": { "type": "string", "format": "date" },
          "currency": { "type": "string", "const": "USD" },
          "revenue_usd": { "type": "number" },
          "paying_customers": { "type": "integer" },
          "tool_credit_used_usd": { "type": "number" },
          "cash_spent_usd": { "type": ["number", "null"] },
          "episodes_published": { "type": "integer" },
          "businesses_in_preparation": { "type": "integer" },
          "annual_net_profit_goal_usd": { "type": "number", "description": "A goal, not a promise or forecast." },
          "notes": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Index": {
        "type": "object",
        "required": ["name", "version", "docs", "endpoints", "rules", "write_access"],
        "properties": {
          "name": { "type": "string" },
          "version": { "type": "string" },
          "description": { "type": "string" },
          "docs": { "type": "object" },
          "portfolio": {
            "type": "object",
            "description": "Heloft portfolio. Figures carry their basis; owner-reported figures are not reconciled with ledger records. Not investment advice.",
            "properties": {
              "as_of": { "type": "string", "format": "date" },
              "notice": { "type": "string" },
              "projects": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["order", "name", "url", "kind", "status", "run_by", "spent_usd", "spent_basis", "revenue_usd", "revenue_basis"],
                  "properties": {
                    "order": { "type": "integer" },
                    "name": { "type": "string" },
                    "url": { "type": "string", "format": "uri" },
                    "kind": { "type": "string" },
                    "status": { "type": "string" },
                    "run_by": { "type": "string" },
                    "summary": { "type": "string" },
                    "notice": { "type": ["string", "null"] },
                    "spent_usd": { "type": "number" },
                    "spent_basis": { "type": "string" },
                    "revenue_usd": { "type": "number" },
                    "revenue_basis": { "type": "string" }
                  }
                }
              }
            }
          },
          "endpoints": { "type": "array", "items": { "type": "object" } },
          "rules": { "type": "array", "items": { "type": "string" } },
          "write_access": { "type": "object" }
        }
      }
    }
  }
}
