{
  "openapi": "3.1.0",
  "info": {
    "title": "MBio Public Interaction API",
    "version": "4.0.0",
    "description": "Consent-aware interaction endpoints used by published MBio pages. These endpoints are browser-facing and rate limited."
  },
  "servers": [{"url": "https://mbio.one"}],
  "paths": {
    "/api/events": {
      "post": {
        "summary": "Record an allowlisted public-page event",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Event"}}}},
        "responses": {"200": {"description": "Recorded or deduplicated"}, "422": {"description": "Invalid event"}, "429": {"description": "Rate limited"}}
      }
    },
    "/api/pages/{slug}/leads": {
      "post": {
        "summary": "Submit a consent-backed lead",
        "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Lead"}}}},
        "responses": {"200": {"description": "Lead accepted"}, "419": {"description": "CSRF token expired"}, "422": {"description": "Invalid or missing consent"}, "429": {"description": "Rate limited"}}
      }
    },
    "/api/pages/{slug}/forms/{block}": {
      "post": {
        "summary": "Submit a consent-backed conversion block",
        "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "block", "in": "path", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/ConversionSubmission"}}}},
        "responses": {"200": {"description": "Submission accepted; gated forms may return a guarded download URL"}, "403": {"description": "Workspace usage limit reached"}, "419": {"description": "CSRF token expired"}, "422": {"description": "Validation, consent or abuse check failed"}, "429": {"description": "Rate limited"}}
      }
    },
    "/api/pages/{slug}/bookings/{block}": {
      "post": {
        "summary": "Request an available service time",
        "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "block", "in": "path", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/BookingRequest"}}}},
        "responses": {"200": {"description": "Booking request created"}, "409": {"description": "Time was already requested"}, "419": {"description": "CSRF token expired"}, "422": {"description": "Invalid time, consent or abuse check failed"}}
      }
    },
    "/api/pages/{slug}/products/{block}/checkout": {
      "post": {
        "summary": "Create a free order or pending external checkout handoff",
        "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "block", "in": "path", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/CheckoutRequest"}}}},
        "responses": {"200": {"description": "Order created or idempotently returned"}, "419": {"description": "CSRF token expired"}, "422": {"description": "Invalid consent or abuse check failed"}}
      }
    },
    "/api/pages/{slug}/chat": {
      "post": {
        "summary": "Ask a published page's consent-gated AI assistant",
        "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChatMessage"}}}},
        "responses": {"200": {"description": "Grounded response or deterministic fallback"}, "419": {"description": "CSRF token expired"}, "422": {"description": "Invalid message or missing consent"}, "429": {"description": "Rate limited"}}
      }
    }
  },
  "components": {
    "schemas": {
      "Event": {
        "type": "object",
        "required": ["page_id", "event", "event_id"],
        "properties": {
          "page_id": {"type": "string", "format": "uuid"},
          "event": {"type": "string", "enum": ["page_viewed", "block_impression", "block_clicked", "form_started", "form_submitted", "goal_completed", "product_viewed", "checkout_started", "order_completed", "booking_requested"]},
          "event_id": {"type": "string", "minLength": 8, "maxLength": 80},
          "consent": {"type": "boolean", "default": false},
          "properties": {"type": "object", "additionalProperties": false, "properties": {"block_id": {"type": "string"}, "block_type": {"type": "string"}, "form_type": {"type": "string"}, "goal": {"type": "string"}, "product_id": {"type": "string"}, "service_id": {"type": "string"}, "utm_campaign": {"type": "string", "pattern": "^[a-z0-9_]{1,100}$"}}}
        }
      },
      "Lead": {
        "type": "object",
        "required": ["email", "consent", "_token"],
        "properties": {"name": {"type": "string", "maxLength": 100}, "email": {"type": "string", "format": "email", "maxLength": 190}, "message": {"type": "string", "maxLength": 2000}, "consent": {"type": "boolean"}, "_token": {"type": "string"}, "captcha_id": {"type": "string", "format": "uuid"}, "captcha_answer": {"type": "string"}, "g-recaptcha-response": {"type": "string"}, "form_started_at": {"type": "integer"}, "website": {"type": "string", "description": "Honeypot; must remain empty."}}
      },
      "ConversionSubmission": {
        "allOf": [{"$ref": "#/components/schemas/Lead"}],
        "description": "May include server-allowlisted field_<name> properties declared by the published block."
      },
      "BookingRequest": {
        "allOf": [{"$ref": "#/components/schemas/Lead"}, {"type": "object", "required": ["starts_at"], "properties": {"phone": {"type": "string", "maxLength": 40}, "starts_at": {"type": "string", "format": "date-time"}, "notes": {"type": "string", "maxLength": 1000}}}]
      },
      "CheckoutRequest": {
        "allOf": [{"$ref": "#/components/schemas/Lead"}],
        "description": "event_id is used as the idempotency key. Paid products return an external HTTPS checkout URL; MBio does not assert settlement."
      },
      "ChatMessage": {
        "type": "object",
        "required": ["message", "consent"],
        "properties": {"message": {"type": "string", "maxLength": 1000}, "consent": {"type": "boolean"}, "session_token": {"type": "string", "pattern": "^[a-f0-9]{32}$"}}
      }
    }
  }
}
