Your AI visibility data,
in your own tools.
Optimz has a REST API and an MCP server, so an agency can pull every client's AI visibility numbers into its own dashboards and AI tools.
Developers
Access
An owner or admin creates an API key in Settings → API & agents. It is shown once; Optimz stores only its hash. Send it as Authorization: Bearer optimz_live_…. AI apps like Claude and ChatGPT connect with OAuth instead: a person signs in and picks the agency and the access level.
| Read onlyoptimz:read | Read every client's numbers, answers, actions, audits, content and reports. |
| Read and writeoptimz:write | Also create clients, track questions, competitors and keywords, run audits, update actions, draft content and build reports. |
| Adminoptimz:admin | Also archive, approve and publish content, revoke share links and invite people. Destructive MCP tools ask for confirmation. |
Every call runs with the same checks as the app: your role, plan limits, daily limits and the plan's monthly usage limit. A key acts as the admin who created it and stops working when it is revoked or that person stops being an admin; an app acts as the person who connected it, within their current role. Every change made through the API is listed in the agent activity log in Settings. REST calls are server to server: never put a key in a web page.
REST API
Base URL https://www.optimz.com/api/v1. JSON only. The full schema is the OpenAPI document.
curl -H "Authorization: Bearer $OPTIMZ_API_KEY" \
https://www.optimz.com/api/v1/clientscurl -H "Authorization: Bearer $OPTIMZ_API_KEY" \
"https://www.optimz.com/api/v1/clients/<client-id>/visibility?weeks=4&engine=chatgpt"| Endpoint | Scope | What it does |
|---|---|---|
| GET /clients | read | List the agency's active clients |
| POST /clients | write | Add a client from its website, like the setup wizard |
| GET /clients/{clientId} | read | One client |
| PATCH /clients/{clientId} | write | Edit a client's name, domain or industry |
| DELETE /clients/{clientId} | admin | Archive a client (its history is kept; restore it in the app) |
| GET /clients/{clientId}/questions | read | The client's tracked buyer questions |
| POST /clients/{clientId}/questions | write | Track a new question |
| GET /clients/{clientId}/questions/paused | read | Questions paused because AI engines couldn't answer them well, with the reason |
| GET /clients/{clientId}/questions/metrics | read | Mention and recommendation per question and engine, with n and 95% CI |
| POST /clients/{clientId}/questions/{questionId}/resume | write | Resume a paused question, or track a rewrite instead |
| DELETE /clients/{clientId}/questions/{questionId} | admin | Stop asking a question (its answers are kept) |
| GET /clients/{clientId}/competitors | read | The brand and each tracked competitor side by side |
| POST /clients/{clientId}/competitors | write | Track a competitor |
| DELETE /clients/{clientId}/competitors/{competitorId} | admin | Stop tracking a competitor (past measurements are kept) |
| GET /clients/{clientId}/competitors/suggestions | read | Competitors AI answers keep naming that aren't tracked yet |
| POST /clients/{clientId}/competitors/suggestions/{suggestionId}/accept | write | Track a suggested competitor |
| POST /clients/{clientId}/competitors/suggestions/{suggestionId}/dismiss | write | Dismiss a suggested competitor (not suggested again) |
| GET /clients/{clientId}/keywords | read | Tracked SEO keywords with their latest Google position |
| POST /clients/{clientId}/keywords | write | Track SEO keywords (rank checks are queued for this week) |
| DELETE /clients/{clientId}/keywords/{keywordId} | admin | Stop tracking a keyword (its history is kept) |
| GET /clients/{clientId}/connections | read | Every data source of the client: what's live, what's missing and the link to fix it |
| GET /clients/{clientId}/connections/tag | read | The client's AI traffic tag snippet for the site's <head> |
| POST /clients/{clientId}/connections/tag/check | write | Check the homepage for the tag |
| POST /clients/{clientId}/connections/health-check | write | Run the data health checks now |
| GET /clients/{clientId}/audit | read | The latest completed site audit and its issues |
| POST /clients/{clientId}/audits | write | Start a site audit |
| GET /clients/{clientId}/audits/{auditId} | read | One audit's status, and its issues once completed |
| GET /clients/{clientId}/actions | read | Action Center items, best score first (the top 500) |
| GET /clients/{clientId}/actions/{actionId} | read | One action: evidence grade, fix plan and a self-contained prompt for an AI agent |
| PATCH /clients/{clientId}/actions/{actionId} | write | Change an action's status, owner or notes |
| POST /clients/{clientId}/actions/{actionId}/fix-plan | write | Write a new evidence-based fix plan for an action |
| GET /clients/{clientId}/content | read | Articles and refreshes (the newest 200) and this month's usage |
| POST /clients/{clientId}/content | write | Create an article and write its brief |
| GET /clients/{clientId}/content/{itemId} | read | One article: status, brief and draft |
| POST /clients/{clientId}/content/{itemId}/draft | write | Write (or rewrite) the article's draft from its brief |
| POST /clients/{clientId}/content/{itemId}/transition | write | Submit for review, approve (admin), reject or reopen an article |
| POST /clients/{clientId}/content/{itemId}/publish | admin | Publish an approved article to the client's CMS |
| GET /clients/{clientId}/brand-voice | read | The client's brand voice (tone, audience, dos, don'ts, sourced facts) |
| PUT /clients/{clientId}/brand-voice | write | Replace the client's brand voice |
| GET /clients/{clientId}/reports | read | The client's frozen reports, newest first |
| POST /clients/{clientId}/reports | write | Freeze a client report for the last 1 or 4 weeks |
| POST /clients/{clientId}/reports/{reportId}/share | write | Create the report's public link (shown once; replaces an older link) |
| DELETE /clients/{clientId}/reports/{reportId}/share | admin | Stop sharing a report (the old link shows not found) |
| GET /clients/{clientId}/visibility | read | Mention, recommendation, coverage, share of voice and position, with n and 95% CI |
| GET /clients/{clientId}/trends | read | Week-by-week mention, recommendation, coverage and share of voice with n and 95% CI |
| GET /clients/{clientId}/answers | read | The AI answers behind the numbers, newest first |
| GET /clients/{clientId}/answers/{answerId} | read | One answer: raw text, citations, searches and parsed mentions |
| GET /clients/{clientId}/citations | read | The domains AI answers cite, grouped, with how often and whether they're the client's |
| GET /clients/{clientId}/fanout | read | The web searches AI engines ran to answer the client's questions |
| GET /usage | read | Plan usage in units: clients, questions, articles and audits against their limits |
| GET /team | read | The agency's members and their roles |
| POST /team/invites | admin | Invite someone to the agency by email |
Lists return { data, next_cursor }: pass cursor=<next_cursor> with the same filters for the next page (limit 1–100, default 50). Actions list the top 500 and content the newest 200.
Add a question (write access):
curl -X POST -H "Authorization: Bearer $OPTIMZ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "What is the best CRM for a 10-person sales team?"}' \
https://www.optimz.com/api/v1/clients/<client-id>/questionsCreating an article (POST …/content with a question_id or action_id) counts against the client's monthly article cap each time it succeeds, so don't blindly retry a 201. A person still reviews and approves every article in Optimz before anything is published.
Numbers you can check
Every rate carries what it was computed from: k of n answers, the proportion, and its Wilson 95% confidence interval. With no answers, value is null, not 0%.
"mention": {
"k": 41,
"n": 72,
"value": 0.569,
"ci_low": 0.455,
"ci_high": 0.677,
"ci_label": "95% CI 46–68%",
"reliability": "early_estimate",
"plain": "Based on 72 answers · Early estimate"
}Engines are named with what was measured, e.g. ChatGPT · API with web search, Google AI Overviews · Google results page, or Simulated for demo data. Answers where the surface showed no AI answer are listed with surface_shown: false and never counted.
MCP server
Ask your agent "how is our AEO?", "what should we fix first for Acme?" or "add printthesheet.com as a client". The server is https://www.optimz.com/api/mcp (streamable HTTP).
Claude: Settings → Connectors → Add custom connector, paste the URL and sign in. ChatGPT: Settings → Connectors → Create, paste the URL, OAuth. Sign-in uses OAuth 2.1 with PKCE and dynamic client registration (discovery at /.well-known/oauth-protected-resource/api/mcp).
Claude Code, with an API key:
claude mcp add --transport http optimz https://www.optimz.com/api/mcp \
--header "Authorization: Bearer $OPTIMZ_API_KEY"Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"optimz": {
"command": "npx",
"args": [
"-y", "mcp-remote", "https://www.optimz.com/api/mcp",
"--header", "Authorization: Bearer ${OPTIMZ_API_KEY}"
],
"env": { "OPTIMZ_API_KEY": "optimz_live_…" }
}
}
}Cursor (.cursor/mcp.json):
{
"mcpServers": {
"optimz": {
"url": "https://www.optimz.com/api/mcp",
"headers": { "Authorization": "Bearer optimz_live_…" }
}
}
}Destructive tools (archiving, revoking a share link) first answer with a confirmation token and what they would do; the agent calls again with confirm once you agree. Data sources that need a sign-in (Google, Microsoft, your host) are connected by a person: check_connections returns the link.
| aeo_briefing | read | How AI visibility is doing: per client the latest week vs the week before (mention, recommendation, coverage, share of voice with n and 95% CI, and whether each change is significant), by engine, the top 5 open actions with evidence grades, data sources still missing (with connect links for a person) and next steps, plus a narrative. Omit client_id for every client. |
| whats_next | read | The most valuable open actions across every client, ranked by score, then evidence grade, then lower effort, plus each client's missing data sources. |
| explain | read | Explains a metric or concept (mention, recommendation, coverage, share_of_voice, position, confidence_interval, evidence_grade, score), or one action (action_id + client_id). |
| compare_competitors | read | The brand against each tracked competitor, ranked by mention rate with n and 95% CI, and which competitors are clearly ahead. |
| suggest_setup | read | Optional. Offers files the person may add to their own repo or site: the AEO check GitHub workflow (checks every preview deployment and comments on the PR) or a client's AI visit tag for the site's <head>. It never applies or writes anything: show the files to the person and apply them only if they say yes. |
| list_clients | read | List the agency's active clients |
| create_client | write | Add a client from its website, like the setup wizard |
| get_client | read | One client |
| update_client | write | Edit a client's name, domain or industry |
| archive_client | admin ✱ | Archive a client (its history is kept; restore it in the app) |
| list_questions | read | The client's tracked buyer questions |
| add_question | write | Track a new question |
| list_paused_questions | read | Questions paused because AI engines couldn't answer them well, with the reason |
| get_question_metrics | read | Mention and recommendation per question and engine, with n and 95% CI |
| resume_question | write | Resume a paused question, or track a rewrite instead |
| archive_question | admin ✱ | Stop asking a question (its answers are kept) |
| list_competitors | read | The brand and each tracked competitor side by side |
| add_competitor | write | Track a competitor |
| archive_competitor | admin ✱ | Stop tracking a competitor (past measurements are kept) |
| list_competitor_suggestions | read | Competitors AI answers keep naming that aren't tracked yet |
| accept_competitor_suggestion | write | Track a suggested competitor |
| dismiss_competitor_suggestion | write | Dismiss a suggested competitor (not suggested again) |
| list_keywords | read | Tracked SEO keywords with their latest Google position |
| track_keywords | write | Track SEO keywords (rank checks are queued for this week) |
| archive_keyword | admin ✱ | Stop tracking a keyword (its history is kept) |
| check_connections | read | Every data source of the client: what's live, what's missing and the link to fix it |
| get_tag_snippet | read | The client's AI traffic tag snippet for the site's <head> |
| check_tag | write | Check the homepage for the tag |
| run_health_checks | write | Run the data health checks now |
| get_audit | read | The latest completed site audit and its issues |
| start_audit | write | Start a site audit |
| get_audit_status | read | One audit's status, and its issues once completed |
| list_actions | read | Action Center items, best score first (the top 500) |
| get_action | read | One action: evidence grade, fix plan and a self-contained prompt for an AI agent |
| update_action | write | Change an action's status, owner or notes |
| generate_fix_plan | write | Write a new evidence-based fix plan for an action |
| list_content | read | Articles and refreshes (the newest 200) and this month's usage |
| create_content_brief | write | Create an article and write its brief |
| get_content | read | One article: status, brief and draft |
| generate_draft | write | Write (or rewrite) the article's draft from its brief |
| transition_content | write | Submit for review, approve (admin), reject or reopen an article |
| publish_content | admin | Publish an approved article to the client's CMS |
| get_brand_voice | read | The client's brand voice (tone, audience, dos, don'ts, sourced facts) |
| save_brand_voice | write | Replace the client's brand voice |
| list_reports | read | The client's frozen reports, newest first |
| create_report | write | Freeze a client report for the last 1 or 4 weeks |
| share_report | write | Create the report's public link (shown once; replaces an older link) |
| revoke_report_share | admin ✱ | Stop sharing a report (the old link shows not found) |
| get_visibility | read | Mention, recommendation, coverage, share of voice and position, with n and 95% CI |
| get_trends | read | Week-by-week mention, recommendation, coverage and share of voice with n and 95% CI |
| get_answers | read | The AI answers behind the numbers, newest first |
| get_answer | read | One answer: raw text, citations, searches and parsed mentions |
| get_citations | read | The domains AI answers cite, grouped, with how often and whether they're the client's |
| get_fanout | read | The web searches AI engines ran to answer the client's questions |
| get_usage | read | Plan usage in units: clients, questions, articles and audits against their limits |
| list_team | read | The agency's members and their roles |
| invite_member | admin | Invite someone to the agency by email |
✱ asks for confirmation first.
Errors and limits
Errors are { "error": { "code", "message" } }. Limits per key or connected app: 120 requests and 10 writes per minute; bodies up to 64 KB.
| 401 | Missing, invalid, expired or revoked key or token, or its creator is no longer an admin. |
| 403 | The key or app lacks the scope (read, write, admin), or your role doesn't allow it. |
| 404 | Unknown endpoint, or a client or item that isn't in your agency. |
| 409 | A plan limit (limit), a duplicate (duplicate, with the existing id), the month's plan usage limit (budget), or not available for this client. |
| 422 | The question quality check flagged it: use a rewrite, or send confirmed: true. |
| 429 | Rate limited (wait for Retry-After), or a daily limit was reached (daily_limit). |