{
  "openapi": "3.1.0",
  "info": {
    "title": "talogen.dev API",
    "version": "1.0.0",
    "summary": "Read-only JSON API for Tal Ogen's portfolio",
    "description": "Public, read-only API exposing Tal Ogen's professional profile, featured projects, autonomous agents, and machine-readable candidate profile. No authentication, no cost. The same data is available over MCP (streamable HTTP) at https://talogen.dev/mcp, which also offers a contact_recruiter write action. Rate limiting: a soft per-instance limit advertised in RateLimit-Policy / RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset response headers, with Retry-After on 429; most reads are served from the CDN edge cache (Cache-Control s-maxage) and never count. Pagination: list endpoints take limit and offset and return total and a next URL (null on the last page). Versioning: the /api/v1 prefix is stable; any breaking change ships as /api/v2 with at least 90 days of overlap, announced via RFC 8594 Sunset headers on the deprecated version.",
    "contact": {
      "name": "Tal Ogen",
      "email": "tal.ogen.p@gmail.com",
      "url": "https://talogen.dev/contact"
    },
    "license": { "name": "All content public", "identifier": "CC-BY-4.0" }
  },
  "servers": [{ "url": "https://talogen.dev" }],
  "security": [],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "API index",
        "description": "Lists every endpoint with a one-line description, plus links to the OpenAPI spec, developer portal, and MCP server.",
        "responses": {
          "200": {
            "description": "Endpoint directory.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiIndex" } } }
          }
        }
      }
    },
    "/api/v1/profile": {
      "get": {
        "operationId": "getProfile",
        "summary": "Get profile",
        "description": "Tal Ogen's professional profile: headline, summary, about paragraphs, contact details (email, LinkedIn, GitHub), capability categories, and key strengths.",
        "responses": {
          "200": {
            "description": "The profile.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Profile" } } }
          }
        }
      }
    },
    "/api/v1/candidate": {
      "get": {
        "operationId": "getCandidate",
        "summary": "Get candidate profile",
        "description": "Machine-readable hiring facts: availability status, target roles, experience, location and remote policy, work authorization, languages.",
        "responses": {
          "200": {
            "description": "The candidate profile (same document as /.well-known/candidate.json).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Candidate" } } }
          }
        }
      }
    },
    "/api/v1/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List projects",
        "description": "Summaries of Tal Ogen's featured software projects. Use getProjectById for full problem/solution/result detail.",
        "parameters": [
          { "$ref": "#/components/parameters/Tag" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          {
            "name": "flagship",
            "in": "query",
            "description": "Set to true to return only the flagship project(s).",
            "schema": { "type": "string", "enum": ["true"] }
          }
        ],
        "responses": {
          "200": {
            "description": "Project summaries, paginated.",
            "headers": { "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" } },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ItemList" } } }
          },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/projects/{id}": {
      "get": {
        "operationId": "getProjectById",
        "summary": "Get project detail",
        "description": "Full detail for one project or agent by id: problem, solution, result, link, tags, image.",
        "parameters": [{ "$ref": "#/components/parameters/Id" }],
        "responses": {
          "200": {
            "description": "The project or agent.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Item" } } }
          },
          "404": {
            "description": "Unknown id. The error hint lists all valid ids.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/v1/agents": {
      "get": {
        "operationId": "listAgents",
        "summary": "List autonomous agents",
        "description": "Summaries of the autonomous AI agents Tal Ogen has designed and built. Use getAgentById for full detail.",
        "parameters": [
          { "$ref": "#/components/parameters/Tag" },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" }
        ],
        "responses": {
          "200": {
            "description": "Agent summaries, paginated.",
            "headers": { "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" } },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ItemList" } } }
          },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/api/v1/agents/{id}": {
      "get": {
        "operationId": "getAgentById",
        "summary": "Get agent detail",
        "description": "Full detail for one autonomous agent by id (equivalent to getProjectById).",
        "parameters": [{ "$ref": "#/components/parameters/Id" }],
        "responses": {
          "200": {
            "description": "The agent.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Item" } } }
          },
          "404": {
            "description": "Unknown id. The error hint lists all valid ids.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Id": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Project or agent id from listProjects / listAgents, e.g. 'human-for-ai'.",
        "schema": { "type": "string", "pattern": "^[\\w-]{1,100}$" }
      },
      "Tag": {
        "name": "tag",
        "in": "query",
        "description": "Only items whose tags contain this text (case-insensitive), e.g. 'MCP' or 'healthcare'.",
        "schema": { "type": "string" }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Page size, 1-100 (default 100).",
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 100 }
      },
      "Offset": {
        "name": "offset",
        "in": "query",
        "description": "Zero-based index of the first item to return (default 0). Follow the response's `next` URL for the following page.",
        "schema": { "type": "integer", "minimum": 0, "default": 0 }
      }
    },
    "headers": {
      "RateLimit-Remaining": {
        "description": "Requests remaining in the current per-instance window. Companions: RateLimit-Policy, RateLimit-Limit, RateLimit-Reset.",
        "schema": { "type": "integer" }
      }
    },
    "responses": {
      "TooManyRequests": {
        "description": "Per-instance soft rate limit exceeded. Honor Retry-After; CDN-cached reads are unaffected.",
        "headers": {
          "Retry-After": { "description": "Seconds until the window resets.", "schema": { "type": "integer" } },
          "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimit-Remaining" }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "ApiIndex": {
        "type": "object",
        "description": "Directory of every API endpoint.",
        "properties": {
          "name": { "type": "string" },
          "version": { "type": "string" },
          "description": { "type": "string" },
          "openapi": { "type": "string", "format": "uri" },
          "documentation": { "type": "string", "format": "uri" },
          "mcp": { "type": "string", "format": "uri" },
          "endpoints": { "type": "object", "additionalProperties": { "type": "string" } }
        }
      },
      "Profile": {
        "type": "object",
        "description": "Professional profile.",
        "properties": {
          "name": { "type": "string" },
          "headline": { "type": "string" },
          "tagline": { "type": "string" },
          "summary": { "type": "string" },
          "about": { "type": "array", "items": { "type": "string" } },
          "contact": {
            "type": "object",
            "properties": {
              "email": { "type": "string", "format": "email" },
              "linkedin": { "type": "string", "format": "uri" },
              "github": { "type": "string", "format": "uri" }
            }
          },
          "website": { "type": "string", "format": "uri" },
          "flagshipProject": { "type": "string", "format": "uri" },
          "skillCategories": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "category": { "type": "string" },
                "items": { "type": "array", "items": { "type": "string" } }
              }
            }
          },
          "skills": { "type": "array", "items": { "type": "string" } },
          "aiTools": { "type": "array", "items": { "type": "string" } },
          "strengths": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": { "title": { "type": "string" }, "detail": { "type": "string" } }
            }
          }
        }
      },
      "Candidate": {
        "type": "object",
        "description": "Machine-readable hiring facts (schema owned by /.well-known/candidate.json).",
        "additionalProperties": true
      },
      "ItemSummary": {
        "type": "object",
        "description": "One project or agent, summary form.",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "flagship": { "type": "boolean" },
          "link": { "type": ["string", "null"], "format": "uri" },
          "problem": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } }
        },
        "required": ["id", "title"]
      },
      "ItemList": {
        "type": "object",
        "description": "One page of items. `next` is the URL of the following page, or null on the last page.",
        "properties": {
          "count": { "type": "integer", "description": "Items in this page." },
          "total": { "type": "integer", "description": "Items matching the filters across all pages." },
          "limit": { "type": "integer" },
          "offset": { "type": "integer" },
          "next": { "type": ["string", "null"], "format": "uri", "description": "URL of the next page; null when this is the last page." },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/ItemSummary" } }
        },
        "required": ["count", "total", "next", "items"]
      },
      "Item": {
        "type": "object",
        "description": "Full detail for one project or agent.",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "flagship": { "type": "boolean" },
          "link": { "type": ["string", "null"], "format": "uri" },
          "problem": { "type": "string" },
          "solution": { "type": "string" },
          "result": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } },
          "image": { "type": ["string", "null"], "format": "uri" }
        },
        "required": ["id", "title"],
        "additionalProperties": true
      },
      "Error": {
        "type": "object",
        "description": "Structured error. Every non-2xx API response has this shape.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "examples": ["not_found", "method_not_allowed"] },
              "message": { "type": "string" },
              "hint": { "type": "string", "description": "How to recover — e.g. the list of valid ids." }
            },
            "required": ["code", "message"]
          }
        },
        "required": ["error"]
      }
    }
  }
}
