{"openapi":"3.1.0","info":{"title":"Ezeo","version":"0.3.0","description":"Ezeo is an SEO and AI-visibility platform. These tools read the signed-in user's Ezeo projects. Call list_projects first when you do not know which project the user means; every other tool takes a project id, name or domain. To help a user set up a website, go in this order: list_projects, add_site (when the site is not there yet), get_setup_status, then get_connection_steps for each source it says is missing. add_site takes one of the plan's sites and starts a paid homepage read: ask the user what they are growing (store, business, blog or agency), show its preview, and pass the confirmation_code only after they explicitly say yes. A null figure means Ezeo has not measured it, never zero. Say \"not measured\" rather than inventing a number. request_articles spends the project's content allowance: show the user its preview and pass the confirmation_code only after they explicitly say yes. list_waiting_runs answers \"what needs my attention?\" across every project in one call. For conversion-rate (CRO) and A/B work: list_cro_hypotheses, then get_variant_brief for a design-ready brief you can take into the user's Figma or Paper connector. The same tools are available over MCP at https://ezeo.ai/mcp."},"servers":[{"url":"https://ezeo.ai/mcp"}],"security":[{"ezeoOAuth":["email","profile"]}],"paths":{"/tools/list_projects":{"post":{"operationId":"list_projects","summary":"List projects","description":"List the Ezeo projects (websites) the signed-in user can access, with id, name and domain.","x-openai-isConsequential":false,"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/add_site":{"post":{"operationId":"add_site","summary":"Add a site","description":"Add the user's website to Ezeo from an address they paste, the same way the Ezeo sign-up wizard does: the project, its brand profile, and one quick read of the homepage (brand name, description and audience found with confidence; the platform and analytics tags the homepage HTML shows). Takes one of the plan's sites and starts a paid read, so it is always two steps: call WITHOUT confirmation_code (and with the persona the user chose) to get a preview that writes nothing, show it to the user, and only after they explicitly agree call again with the same url and persona plus the confirmation_code. Never confirm on the user's behalf. Safe to repeat: a site already in the user's organization is returned, never added twice. Client accounts and accounts without an organization are refused.","x-openai-isConsequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"The site address as the user wrote it, e.g. \"acme.com\" or \"https://www.acme.com/shop\". Ezeo keeps the domain only."},"persona":{"type":"string","enum":["store","business","blog","agency"],"description":"What the user is growing, as the wizard asks: store (online store), business (business or SaaS site), blog, or agency (client sites). Ask the user; do not guess."},"confirmation_code":{"type":"string","description":"The code from the preview. Pass it only after the user has explicitly confirmed the preview."},"lang":{"type":"string","enum":["en","es"],"description":"Language of the copy returned (default en)."}},"required":["url"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_setup_status":{"post":{"operationId":"get_setup_status","summary":"Setup status","description":"What is set up on a project and what to do next, in the terms of the app's \"Finish setting up\" checklist: whether Ezeo has read the site, which sources are connected (Search Console and GA4 are recommended; Microsoft Clarity is recommended, not needed), tracked keywords, the first site audit, the team, and the plan or trial with its site limit. `next` names the next step and the tool or page that does it. null means Ezeo could not read it for this account, never zero or not done.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"lang":{"type":"string","enum":["en","es"],"description":"Language of the copy returned (default en)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_connection_steps":{"post":{"operationId":"get_connection_steps","summary":"Connection steps","description":"The plain steps to connect one data source to a project, in the Ezeo app's own words: Search Console, Google Analytics 4 or Merchant Center (add Ezeo's Google service account, returned here, as a user in that product, then save the property in Ezeo), or Microsoft Clarity (a project id and a Data Export token). Includes the Google page that opens the right screen and the Ezeo page where the property is saved. Ezeo cannot connect a source for the user; walk them through these steps.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"source":{"type":"string","enum":["search_console","google_analytics","clarity","merchant_center"],"description":"The data source to connect."},"lang":{"type":"string","enum":["en","es"],"description":"Language of the copy returned (default en)."}},"required":["project","source"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_project_overview":{"post":{"operationId":"get_project_overview","summary":"Project overview","description":"Search Console clicks, impressions and average position, GA4 site sessions, and when each data source last synced, for one project over the last N days. Search Console lags about 4 days, so its window ends 4 days ago.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"days":{"type":"integer","minimum":1,"maximum":90,"description":"Window length in days (default 28)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_keyword_rankings":{"post":{"operationId":"get_keyword_rankings","summary":"Keyword rankings","description":"Tracked keyword rankings for a project: a top-3/10/20 summary, the best-ranked keywords, and the biggest moves since the previous check. Positions are Google organic positions (1-100); null means the keyword was not found in the checked results.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"How many keywords to list in each section (default 20)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_quick_wins":{"post":{"operationId":"get_quick_wins","summary":"Quick wins","description":"Ezeo's quick-win queue: tracked keywords ranking in positions 4-15, most Search Console impressions first, one row per ranking page. ctr_gap_pct is the expected CTR for that position minus the actual CTR, in percentage points: a positive gap is clicks the page is missing. Window: the last 28 days Search Console has reported.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"How many keywords to return (default 10)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_weekly_readout":{"post":{"operationId":"get_weekly_readout","summary":"Weekly readout","description":"The project's weekly readout: Ezeo's written summary of what regressed, quick wins, AI-visibility movement and conversion signals for one week. Returns the latest week unless week_start is given.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"week_start":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Monday of the week, YYYY-MM-DD (optional)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/list_articles":{"post":{"operationId":"list_articles","summary":"List articles","description":"Articles Ezeo has written or is writing for a project, newest first, with status, target keyword, QA score and published URL.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"status":{"type":"string","description":"Only articles in this status (e.g. draft, approved, published)."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"How many articles (default 20)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_content_ideas":{"post":{"operationId":"get_content_ideas","summary":"Content ideas","description":"The project's content topic backlog, highest opportunity score (0-100) first: each idea is a named topic with its angle, target reader, primary keyword and overlap risk with existing pages. This is what request_articles writes from.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"status":{"type":"string","description":"Only ideas in this status (candidate, approved, briefed, drafted, published, refresh, rejected, backlog, archived)."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"How many ideas (default 20)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_sync_status":{"post":{"operationId":"get_sync_status","summary":"Sync status","description":"Whether a project's data is flowing: every scheduled data sync (Search Console, GA4, rankings, ...) with its frequency, last and next run, retry count and last error, any service whose circuit breaker has tripped, and the last 10 sync attempts. Check this before trusting a figure that looks stale.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/list_waiting_runs":{"post":{"operationId":"list_waiting_runs","summary":"Runs waiting for a person","description":"Every article pipeline run waiting for a person (approval, revision, publish, or parked with a reason) across all projects the user can see, with project name and article title. Answers \"what needs my attention in Ezeo?\" in one call.","x-openai-isConsequential":false,"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/list_cro_hypotheses":{"post":{"operationId":"list_cro_hypotheses","summary":"A/B test hypotheses","description":"The project's A/B test hypotheses (conversion-rate ideas), highest ICE score first: each names a page, the element to change, the current state, the proposed change, the success metric and its status (hypothesis, validated, running, completed, rejected). Use get_variant_brief with an id for the full design brief.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"status":{"type":"string","enum":["hypothesis","validated","running","completed","rejected"],"description":"Only hypotheses in this status (optional)."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"How many hypotheses (default 20)."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_cro_audit":{"post":{"operationId":"get_cro_audit","summary":"Latest CRO audit","description":"The project's latest completed conversion-rate (CRO) audit: the page audited, scores, findings and quick wins, plus which engine wrote it (an automated one-page HTML scan, or Ezeo Intelligence / the Ezeo team) and what that means for how far to trust it.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/get_variant_brief":{"post":{"operationId":"get_variant_brief","summary":"Variant design brief","description":"A design-ready brief for one A/B hypothesis: the page and element, current state (A), proposed change (B), success metric, the last 30 days of evidence for that page (Microsoft Clarity friction, GA4 landing-page purchases when measured, matching CRO audit findings), and step-by-step design handoff instructions. Returned as JSON plus a `markdown` version. Hand it to a Figma or Paper connector to design variant B; Ezeo does not create the design itself.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"hypothesis_id":{"type":"string","description":"The hypothesis id from list_cro_hypotheses."}},"required":["project","hypothesis_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}},"/tools/request_articles":{"post":{"operationId":"request_articles","summary":"Request articles","description":"Ask Ezeo to write new articles for a project. SPENDS the project's content allowance, one unit per article. Always two steps: first call WITHOUT confirmation_code to get a preview (nothing is spent), show that preview to the user, and only after the user explicitly agrees call again with the same project and count plus the confirmation_code from the preview. Never confirm on the user's behalf. Only members of the organization that owns the project can request.","x-openai-isConsequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id, or part of its name or domain (e.g. \"equipmaxx\"). Use list_projects to see the options."},"count":{"type":"integer","minimum":1,"maximum":10,"description":"How many articles (default 1)."},"confirmation_code":{"type":"string","description":"The code from the preview. Pass it only after the user has explicitly confirmed the preview."}},"required":["project"],"additionalProperties":false}}}},"responses":{"200":{"description":"The tool result. `result` is the JSON the MCP tool returns (or `{ text }` for a text document such as the weekly readout).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolResponse"}}}},"400":{"description":"The tool refused the input (unknown or ambiguous project, missing argument). `error` says what to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolError"}}}},"401":{"description":"Missing, expired or revoked token."}}}}},"components":{"securitySchemes":{"ezeoOAuth":{"type":"oauth2","description":"Sign in with your Ezeo account. Tools see exactly the projects you see in the Ezeo app.","flows":{"authorizationCode":{"authorizationUrl":"https://nnzukmaididuhuxsaotn.supabase.co/auth/v1/oauth/authorize","tokenUrl":"https://nnzukmaididuhuxsaotn.supabase.co/auth/v1/oauth/token","scopes":{"email":"Ezeo account email","profile":"Ezeo account profile"}}}}},"schemas":{"ToolResponse":{"type":"object","properties":{"tool":{"type":"string"},"result":{"type":"object","additionalProperties":true}},"required":["tool","result"]},"ToolError":{"type":"object","properties":{"tool":{"type":"string"},"error":{"type":"string"}},"required":["error"]}}}}