{
  "openapi": "3.1.0",
  "info": {
    "title": "VertoDigital Agent API",
    "version": "1.0.0",
    "description": "Public, anonymous, rate-limited API surface for AI agents interacting with VertoDigital. Covers a health check and a contact-enquiry endpoint. For read access to site content, agents should prefer /llms.txt, the /markdown/{path} mirror, and the VertoDigital MCP server at https://mcp.vertodigital.com/mcp, which are not duplicated here.",
    "termsOfService": "https://vertodigital.com/terms",
    "contact": {
      "name": "VertoDigital",
      "url": "https://vertodigital.com/contact",
      "email": "paul.green@vertodigital.com"
    }
  },
  "servers": [
    { "url": "https://vertodigital.com" }
  ],
  "security": [],
  "externalDocs": {
    "description": "LLM-readable site index",
    "url": "https://vertodigital.com/llms.txt"
  },
  "tags": [
    { "name": "meta", "description": "Service status" },
    { "name": "contact", "description": "Contact and enquiry submission" },
    { "name": "content", "description": "Existing read-only content surfaces" }
  ],
  "paths": {
    "/agent/health": {
      "get": {
        "operationId": "getHealth",
        "tags": ["meta"],
        "summary": "Service health check",
        "responses": {
          "200": {
            "description": "Service is reachable",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HealthResponse" }
              }
            }
          }
        }
      }
    },
    "/agent/contact": {
      "post": {
        "operationId": "submitEnquiry",
        "tags": ["contact"],
        "summary": "Submit a contact enquiry on behalf of a user",
        "description": "Anonymous, rate-limited (5 requests/minute and 50 requests/day per caller IP). No authentication required. Returns 202 once the enquiry is accepted for delivery; delivery itself (CRM + internal notification) is best-effort and not guaranteed by this response.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ContactRequest" },
              "example": {
                "fromName": "Ada Lovelace",
                "fromEmail": "ada@example.com",
                "organization": "Analytical Engines Ltd",
                "topic": "sales",
                "message": "We'd like to discuss a marketing analytics engagement.",
                "agentId": "agent-123"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Enquiry accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContactAccepted" }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidationError" }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "413": {
            "description": "Request body too large",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the caller may retry",
                "schema": { "type": "integer" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RateLimited" }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "502": {
            "description": "Upstream delivery error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getSiteIndex",
        "tags": ["content"],
        "summary": "LLM-readable index of all pages on vertodigital.com",
        "responses": {
          "200": {
            "description": "Plain-text site index",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/markdown/{path}": {
      "get": {
        "operationId": "getPageAsMarkdown",
        "tags": ["content"],
        "summary": "Fetch any vertodigital.com page as clean markdown",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "Page slug, e.g. \"about\" or \"case-studies/ironscales\""
          }
        ],
        "responses": {
          "200": {
            "description": "Markdown mirror of the page",
            "content": { "text/markdown": { "schema": { "type": "string" } } }
          },
          "404": {
            "description": "No markdown mirror exists for this path"
          }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "operationId": "getApiCatalog",
        "tags": ["meta"],
        "summary": "RFC 9727 API catalog",
        "responses": {
          "200": {
            "description": "Linkset document",
            "content": {
              "application/linkset+json": { "schema": { "type": "object" } }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ContactRequest": {
        "type": "object",
        "required": ["fromName", "fromEmail", "message"],
        "properties": {
          "fromName": { "type": "string", "minLength": 1, "maxLength": 100 },
          "fromEmail": { "type": "string", "format": "email", "maxLength": 254 },
          "organization": { "type": "string", "maxLength": 100 },
          "topic": {
            "type": "string",
            "enum": ["assessment", "services", "partnership", "press", "careers", "general"],
            "default": "general"
          },
          "message": { "type": "string", "minLength": 10, "maxLength": 2000 },
          "agentId": {
            "type": "string",
            "maxLength": 100,
            "description": "Self-asserted identifier for the calling agent. Not verified."
          }
        }
      },
      "ContactAccepted": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "const": "accepted" },
          "reference": { "type": "string", "pattern": "^enq_[0-9a-f]{16}$" },
          "receivedAt": { "type": "string", "format": "date-time" }
        }
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "const": "invalid_request" },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": { "type": "string" },
                "message": { "type": "string" }
              }
            }
          }
        }
      },
      "RateLimited": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "const": "rate_limited" },
          "message": { "type": "string" },
          "retryAfter": { "type": "integer", "description": "Seconds" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string" },
          "message": { "type": "string" }
        }
      },
      "HealthResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "enum": ["ok", "degraded"] },
          "service": { "type": "string" },
          "version": { "type": "string" },
          "time": { "type": "string", "format": "date-time" },
          "endpoints": { "type": "object" }
        }
      }
    }
  }
}
