{
  "openapi": "3.1.0",
  "info": {
    "title": "enso.bot Public API",
    "version": "1.0.0",
    "summary": "Public read-only REST API for enso - the agentic growth lab.",
    "description": "Read-only endpoints exposing enso's company info, blog posts, Agentic Lab research experiments, and open roles. Designed for AI agents and integrations. No authentication is required for the /api/public/v1/* endpoints. For a richer, tool-based interface see the MCP server at https://enso.bot/mcp.",
    "contact": {
      "name": "enso",
      "url": "https://enso.bot/contact",
      "email": "hello@enso.bot"
    },
    "license": {
      "name": "Public content",
      "url": "https://enso.bot/terms"
    }
  },
  "servers": [
    {
      "url": "https://enso.bot",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "enso developer resources",
    "url": "https://enso.bot/developers"
  },
  "security": [],
  "components": {
    "securitySchemes": {
      "contentApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Required for landing-page content operations."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 with Dynamic Client Registration for authenticated MCP calls at /mcp. Public REST endpoints require no auth.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://rsxyvyanjlbjrajqrrps.supabase.co/auth/v1/authorize",
            "tokenUrl": "https://rsxyvyanjlbjrajqrrps.supabase.co/auth/v1/token",
            "scopes": {
              "openid": "OpenID Connect sign-in",
              "email": "Access to the user's email",
              "profile": "Access to basic profile info"
            }
          }
        }
      }
    },
    "schemas": {
      "Company": {
        "type": "object"
      },
      "BlogPost": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Experiment": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "excerpt": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "readTime": {
            "type": "string"
          },
          "surface": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Role": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "isNew": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          }
        }
      },
      "PageBlock": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "type",
              "title",
              "sub"
            ],
            "properties": {
              "type": {
                "const": "hero"
              },
              "eyebrow": {
                "type": "string",
                "maxLength": 120
              },
              "title": {
                "type": "string",
                "maxLength": 90
              },
              "sub": {
                "type": "string",
                "maxLength": 220,
                "description": "Must clearly state the target ICP."
              },
              "bullets": {
                "type": "array",
                "maxItems": 5,
                "items": {
                  "type": "string",
                  "maxLength": 100
                }
              },
              "ctaLabel": {
                "type": "string",
                "maxLength": 40
              },
              "ctaHref": {
                "type": "string",
                "description": "A site path or absolute https URL."
              },
              "imageUrl": {
                "type": "string",
                "format": "uri",
                "description": "Absolute https URL only."
              },
              "imageAlt": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "logos"
              },
              "title": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "items"
            ],
            "properties": {
              "type": {
                "const": "stats"
              },
              "items": {
                "type": "array",
                "minItems": 1,
                "maxItems": 4,
                "items": {
                  "type": "object",
                  "required": [
                    "value",
                    "label"
                  ],
                  "properties": {
                    "value": {
                      "type": "string",
                      "maxLength": 24
                    },
                    "label": {
                      "type": "string",
                      "maxLength": 80
                    }
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "items"
            ],
            "properties": {
              "type": {
                "enum": [
                  "features",
                  "steps"
                ]
              },
              "title": {
                "type": "string"
              },
              "lede": {
                "type": "string"
              },
              "items": {
                "type": "array",
                "minItems": 1,
                "maxItems": 8,
                "items": {
                  "type": "object",
                  "required": [
                    "title",
                    "body"
                  ],
                  "properties": {
                    "title": {
                      "type": "string",
                      "maxLength": 80
                    },
                    "body": {
                      "type": "string",
                      "maxLength": 320
                    }
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "quote"
            ],
            "properties": {
              "type": {
                "const": "quote"
              },
              "quote": {
                "type": "string",
                "maxLength": 500
              },
              "who": {
                "type": "string"
              },
              "company": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "markdown"
            ],
            "properties": {
              "type": {
                "const": "richtext"
              },
              "title": {
                "type": "string"
              },
              "markdown": {
                "type": "string",
                "maxLength": 4000
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "items"
            ],
            "properties": {
              "type": {
                "const": "faq"
              },
              "title": {
                "type": "string"
              },
              "items": {
                "type": "array",
                "minItems": 1,
                "maxItems": 12,
                "items": {
                  "type": "object",
                  "required": [
                    "q",
                    "a"
                  ],
                  "properties": {
                    "q": {
                      "type": "string"
                    },
                    "a": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "leadform"
              },
              "title": {
                "type": "string"
              },
              "sub": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "title"
            ],
            "properties": {
              "type": {
                "const": "cta"
              },
              "title": {
                "type": "string",
                "maxLength": 120
              },
              "sub": {
                "type": "string"
              },
              "ctaLabel": {
                "type": "string",
                "maxLength": 40
              },
              "ctaHref": {
                "type": "string"
              }
            }
          }
        ],
        "discriminator": {
          "propertyName": "type"
        }
      },
      "SitePageInput": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "blocks"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "maxLength": 80
          },
          "title": {
            "type": "string",
            "maxLength": 60
          },
          "description": {
            "type": "string",
            "maxLength": 160
          },
          "og_image_url": {
            "type": "string",
            "format": "uri"
          },
          "cta_label": {
            "type": "string",
            "maxLength": 40
          },
          "cta_href": {
            "type": "string"
          },
          "noindex": {
            "type": "boolean"
          },
          "is_published": {
            "type": "boolean",
            "default": true
          },
          "blocks": {
            "type": "array",
            "minItems": 1,
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/PageBlock"
            },
            "description": "The first block must be the page's only hero. Include hero subcopy naming the ICP."
          }
        }
      }
    }
  },
  "paths": {
    "/api/public/content/pages": {
      "post": {
        "summary": "Create or replace an on-brand landing page",
        "operationId": "publishLandingPage",
        "description": "Publishes immediately after schema and brand quality validation. The first block must be the only hero and its subcopy must state a clear ICP. Styling and customer logos are supplied by enso.",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SitePageInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Published"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Schema or brand quality validation failed"
          }
        }
      },
      "get": {
        "summary": "List generated landing pages",
        "operationId": "listLandingPages",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Page list"
          }
        }
      }
    },
    "/api/public/content/pages/generate": {
      "post": {
        "summary": "Generate an on-brand landing page from a brief (AI copy + hero visual)",
        "operationId": "generateLandingPage",
        "description": "Send a brief instead of blocks. enso writes the copy against the block registry and the brand rules, renders a hero visual with GPT image 2 anchored on the current brand style, runs the same quality gate as POST /pages (retrying once with the failures fed back to the writer), and saves the page as a draft unless publish=true.",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slug",
                  "topic",
                  "icp"
                ],
                "properties": {
                  "slug": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "topic": {
                    "type": "string",
                    "maxLength": 300,
                    "description": "What the page is about"
                  },
                  "icp": {
                    "type": "string",
                    "maxLength": 160,
                    "description": "Who the page is for, max 12 words"
                  },
                  "goal": {
                    "type": "string",
                    "maxLength": 300
                  },
                  "offer": {
                    "type": "string",
                    "maxLength": 600
                  },
                  "proof": {
                    "type": "array",
                    "maxItems": 8,
                    "items": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "description": "The only facts the writer may state. No proof means no stats or quote blocks."
                  },
                  "cta_label": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "cta_href": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "tone": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "sections": {
                    "type": "array",
                    "maxItems": 10,
                    "items": {
                      "type": "string"
                    }
                  },
                  "generate_image": {
                    "type": "boolean",
                    "default": true
                  },
                  "publish": {
                    "type": "boolean",
                    "default": false,
                    "description": "Draft by default so copy and visual can be reviewed."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Page authored"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Invalid brief, or the generated page failed the quality gate twice"
          },
          "502": {
            "description": "Authoring model failed"
          }
        }
      }
    },
    "/api/public/content/pages/{slug}": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "Read a generated landing page",
        "operationId": "getLandingPage",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Page"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "patch": {
        "summary": "Update a generated landing page",
        "operationId": "updateLandingPage",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SitePageInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "422": {
            "description": "Schema or brand quality validation failed"
          }
        }
      },
      "delete": {
        "summary": "Unpublish a generated landing page",
        "operationId": "unpublishLandingPage",
        "security": [
          {
            "contentApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Unpublished"
          }
        }
      }
    },
    "/api/public/v1/company": {
      "get": {
        "summary": "Get enso company overview",
        "operationId": "getCompany",
        "responses": {
          "200": {
            "description": "Company info",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/blog": {
      "get": {
        "summary": "List blog posts",
        "operationId": "listBlogPosts",
        "responses": {
          "200": {
            "description": "List of blog posts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "posts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogPost"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/research": {
      "get": {
        "summary": "List Agentic Lab research experiments",
        "operationId": "listResearch",
        "responses": {
          "200": {
            "description": "List of experiments",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "experiments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Experiment"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/research/{slug}": {
      "get": {
        "summary": "Get a single research experiment",
        "operationId": "getResearch",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Experiment detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "experiment": {
                      "$ref": "#/components/schemas/Experiment"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/careers": {
      "get": {
        "summary": "List open roles",
        "operationId": "listCareers",
        "responses": {
          "200": {
            "description": "List of roles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "roles": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Role"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/careers/{slug}": {
      "get": {
        "summary": "Get a single role",
        "operationId": "getCareer",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Role detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "$ref": "#/components/schemas/Role"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "summary": "MCP (Model Context Protocol) server endpoint",
        "description": "JSON-RPC over HTTP endpoint for the enso MCP server. Supports Streamable HTTP transport. See /.well-known/oauth-protected-resource for auth metadata.",
        "operationId": "mcpInvoke",
        "security": [
          {
            "oauth2": [
              "openid",
              "email",
              "profile"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "MCP JSON-RPC response"
          }
        }
      }
    }
  }
}