{
  "openapi": "3.1.0",
  "info": {
    "title": "Sitefire public API",
    "version": "1.0.0",
    "summary": "Machine-readable surface of sitefire.ai: demo booking, content mirrors, and discovery files.",
    "description": "Sitefire is the marketing suite for the agentic web (GEO: Generative Engine Optimization). This specification covers the public, keyless API of the sitefire.ai website: booking a product demo programmatically, and retrieving every page as clean markdown. The Sitefire product itself is exposed to agents through the Sitefire MCP server (Streamable HTTP) at https://app.sitefire.ai/api/mcp - see https://sitefire.ai/docs/mcp. Errors from /api/* endpoints are structured JSON: {\"error\": {\"code\", \"message\", \"resolution\"}}.",
    "contact": {
      "name": "Sitefire",
      "email": "info@sitefire.ai",
      "url": "https://sitefire.ai/contact"
    }
  },
  "servers": [{ "url": "https://sitefire.ai" }],
  "paths": {
    "/api/book-demo/slots": {
      "get": {
        "operationId": "listDemoSlots",
        "summary": "List open demo slots for a day",
        "description": "Returns the start times still open for a Sitefire intro demo on the given day, as ISO 8601 timestamps in the requested timezone. Pass one of them to bookDemo. No API key required.",
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": true,
            "description": "Calendar day to list, in YYYY-MM-DD format.",
            "schema": { "type": "string", "format": "date", "example": "2026-09-01" }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA timezone the returned start times should be expressed in. Defaults to UTC.",
            "schema": { "type": "string", "default": "UTC", "example": "America/New_York" }
          }
        ],
        "responses": {
          "200": {
            "description": "Open slots for the requested day (empty array when the day is fully booked or in the past).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["date", "timezone", "slots"],
                  "properties": {
                    "date": { "type": "string", "format": "date" },
                    "timezone": { "type": "string" },
                    "slots": {
                      "type": "array",
                      "items": { "type": "string", "format": "date-time" },
                      "description": "ISO 8601 start times bookable via bookDemo."
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "502": { "$ref": "#/components/responses/UpstreamError" }
        }
      }
    },
    "/api/book-demo": {
      "post": {
        "operationId": "bookDemo",
        "summary": "Book a Sitefire demo",
        "description": "Books a 30-minute Sitefire intro demo at a start time returned by listDemoSlots. The attendee receives a calendar invitation by email. No API key required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "email", "time"],
                "properties": {
                  "name": { "type": "string", "description": "Attendee's full name.", "example": "Ada Lovelace" },
                  "email": { "type": "string", "format": "email", "description": "Attendee's email address; the calendar invitation is sent here.", "example": "ada@example.com" },
                  "time": { "type": "string", "format": "date-time", "description": "A start time returned by listDemoSlots." },
                  "timezone": { "type": "string", "default": "UTC", "description": "IANA timezone of the attendee.", "example": "America/New_York" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The demo is booked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["booked", "start", "attendee"],
                  "properties": {
                    "booked": { "type": "boolean", "const": true },
                    "start": { "type": "string", "format": "date-time" },
                    "timezone": { "type": "string" },
                    "attendee": {
                      "type": "object",
                      "properties": {
                        "name": { "type": "string" },
                        "email": { "type": "string", "format": "email" }
                      }
                    },
                    "reference": { "type": ["string", "null"], "description": "Booking reference, when the scheduler returns one." },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "409": {
            "description": "The slot is no longer available; list slots again and retry.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": { "$ref": "#/components/responses/UpstreamError" }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsIndex",
        "summary": "Site index for LLMs",
        "description": "llms.txt: what Sitefire is, when to use it, developer resources, and a link per page to its markdown mirror.",
        "responses": {
          "200": {
            "description": "The index, as plain text markdown.",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLlmsFullContent",
        "summary": "Full site content for LLMs",
        "description": "Every documentation page concatenated as plain markdown, for single-fetch ingestion.",
        "responses": {
          "200": {
            "description": "The full content, as plain text markdown.",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/{page}.md": {
      "get": {
        "operationId": "getPageMarkdown",
        "summary": "Markdown mirror of a page",
        "description": "Every public page has a markdown twin at its path plus '.md' (the homepage's is /index.md). The same representation is served at the canonical URL via content negotiation: request any page with 'Accept: text/markdown'. Responses carry 'Vary: Accept'.",
        "parameters": [
          {
            "name": "page",
            "in": "path",
            "required": true,
            "description": "Page path without leading slash, e.g. 'index', 'pricing', 'docs/quick-start', 'blog/query-fan-out'.",
            "schema": { "type": "string", "example": "pricing" }
          }
        ],
        "responses": {
          "200": {
            "description": "The page as markdown.",
            "content": { "text/markdown": { "schema": { "type": "string" } } }
          },
          "404": {
            "description": "No page exists at this path; the body is a short markdown pointer to /llms.txt and /sitemap.xml.",
            "content": { "text/markdown": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/changelog.json": {
      "get": {
        "operationId": "getChangelog",
        "summary": "Product changelog as JSON",
        "description": "Machine-readable Sitefire product changelog, newest first.",
        "responses": {
          "200": {
            "description": "Changelog entries, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": ["slug", "date", "title", "url"],
                    "properties": {
                      "slug": { "type": "string" },
                      "date": { "type": "string", "format": "date" },
                      "title": { "type": "string" },
                      "description": { "type": "string" },
                      "url": { "type": "string", "format": "uri" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "XML sitemap",
        "description": "Every indexable page with its last-modified date where one is declared.",
        "responses": {
          "200": {
            "description": "The sitemap.",
            "content": { "application/xml": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/feed.xml": {
      "get": {
        "operationId": "getBlogFeed",
        "summary": "Blog RSS feed",
        "description": "RSS 2.0 feed of the Sitefire blog.",
        "responses": {
          "200": {
            "description": "The feed.",
            "content": { "application/xml": { "schema": { "type": "string" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "resolution"],
            "properties": {
              "code": { "type": "string", "description": "Stable machine-readable error code, e.g. invalid_date, slot_unavailable, not_found." },
              "message": { "type": "string", "description": "What went wrong." },
              "resolution": { "type": "string", "description": "How to fix or retry the request." }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A request parameter is missing or malformed; the error body says which and how to fix it.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "UpstreamError": {
        "description": "The scheduling provider is unavailable; retry shortly or book at https://pulse.cal.com/sitefire/intro.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
