Docs
API and MCP server
Everything a person can do in the app, an agent or a script can do here, under the same rules. The REST API and the MCP server are one set of operations: each MCP tool is a REST endpoint.
Auth
Create a key under Settings → API keys, read-only or read-and-write. Send it as Authorization: Bearer aeo_….
Quickstart
List your offerings
curl -s https://getkeats.com/api/v1/offerings \ -H "Authorization: Bearer $KEATS_API_KEY"
Read the week
curl -s https://getkeats.com/api/v1/offerings/$OFFERING/read \ -H "Authorization: Bearer $KEATS_API_KEY"
Get a brief for the top card
curl -s https://getkeats.com/api/v1/actions/$ACTION/brief \ -H "Authorization: Bearer $KEATS_API_KEY"
Report the work live (starts the evaluation)
curl -s -X POST https://getkeats.com/api/v1/actions/$ACTION/complete \
-H "Authorization: Bearer $KEATS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url":"https://example.com/new-page","publishedAt":"2026-11-12","notes":"New page answering the question"}'The full spec: /api/v1/openapi.json (OpenAPI 3.1).
MCP
Streamable HTTP at https://getkeats.com/mcp, the same keys. Claude Code:
claude mcp add --transport http keats https://getkeats.com/mcp --header "Authorization: Bearer aeo_…"
Other clients:
{
"mcpServers": {
"keats": {
"type": "http",
"url": "https://getkeats.com/mcp",
"headers": {
"Authorization": "Bearer aeo_…"
}
}
}
}Prompts: weekly_review, work_action, tune_prompts. Resources: aeo://offerings/{id}/read and aeo://offerings/{id}/answers.
Rules
- Auth: send a workspace key as
Authorization: Bearer aeo_…. Make keys in the app under Settings → API keys (owners and admins). A key works in its own workspace only; another workspace's ids answer 404, as if they didn't exist. Read-only keys get 403 on writes. - Errors are JSON:
{"error": {"code", "message", "hint"}}. The hint says what to do next. Codes: invalid_input 400, unauthorized and key_revoked 401, forbidden 403, not_found 404, method_not_allowed 405, conflict 409 (the app's rules refuse it now, e.g. a card can't jump the board), plan_required 402 (the workspace's trial hasn't started: a person opens the error'surlto start it with a card), plan_limit 402 (the plan has no room for what you're adding, or adding is paused; the message has the numbers and the hint the fix), idempotency_mismatch 422, rate_limited 429, internal 500. - Rate limits: 120 requests and 30 writes a minute per key (MCP counts each request, and each write tool). Over a limit you get 429 with Retry-After; every REST response carries X-RateLimit-Limit, -Remaining and -Reset.
- Inputs are strict: a field an operation doesn't take is refused by name (invalid_input), never ignored.
- Lists return
{"data": [...], "nextCursor"}; passcursor=<nextCursor>for the next page andlimit(1–200, default 50). - Writes take an optional
Idempotency-Keyheader: a retry with the same key and body gets the first response again (for 24 hours); the same key with a different body is refused. - Long work returns a job, never a held connection: add_brand, read_site_again, prepare_offerings and run_now. Poll GET /api/v1/jobs/{jobId} (get_job) every 30–60 seconds; each job says what to call next.
- Plans: tracked questions and brands count against the workspace's plan (get_plan, get_usage). Every write made with a key is recorded: the key, the operation and what it acted on.
Operations
| Tool | Endpoint | Does |
|---|---|---|
| search | GET /api/v1/search | Search the workspace |
| get_brand_read | GET /api/v1/brands/{brandId}/read | The brand's portfolio read |
| get_weekly_read | GET /api/v1/offerings/{offeringId}/read | The weekly read |
| list_actions | GET /api/v1/offerings/{offeringId}/actions | List action cards, ranked |
| list_brand_actions | GET /api/v1/brands/{brandId}/actions | List a brand's action cards, every offering |
| get_summary | GET /api/v1/brands/{brandId}/summary | The week's summary, for a ticket comment |
| get_brief | GET /api/v1/actions/{actionId}/brief | Get a content brief for a card |
| explain_prompt | GET /api/v1/prompts/{promptId}/explain | Explain a prompt |
| list_brands | GET /api/v1/brands | List brands |
| get_brand | GET /api/v1/brands/{brandId} | Get a brand |
| get_catalog | GET /api/v1/brands/{brandId}/catalog | Read a brand's catalog |
| get_coverage_plan | GET /api/v1/brands/{brandId}/coverage | The brand's coverage plan |
| list_not_tracking | GET /api/v1/brands/{brandId}/not-tracking | List what the brand leaves out |
| get_search_console_status | GET /api/v1/brands/{brandId}/search-console | Search Console: status and how to connect |
| list_offerings | GET /api/v1/offerings | List offerings |
| get_offering | GET /api/v1/offerings/{offeringId} | Get an offering |
| list_prompts | GET /api/v1/offerings/{offeringId}/prompts | List prompts with results |
| check_prompts | GET /api/v1/offerings/{offeringId}/prompts/check | Check an offering's prompts |
| suggest_prompts | GET /api/v1/offerings/{offeringId}/prompts/suggest | Prompts from the offering's real searches |
| list_competitors | GET /api/v1/brands/{brandId}/competitors | List competitors |
| list_runs | GET /api/v1/offerings/{offeringId}/runs | List runs |
| read_by_engine | GET /api/v1/offerings/{offeringId}/read/engines | The read by engine |
| read_by_prompt | GET /api/v1/offerings/{offeringId}/read/prompts | The read by prompt |
| list_answers | GET /api/v1/offerings/{offeringId}/answers | List answers |
| list_citations | GET /api/v1/offerings/{offeringId}/citations | Citations by domain or page |
| brands_named | GET /api/v1/offerings/{offeringId}/brands-named | Brands named |
| get_action | GET /api/v1/actions/{actionId} | Get an action card |
| list_evaluations | GET /api/v1/offerings/{offeringId}/evaluations | List evaluations |
| get_trend | GET /api/v1/offerings/{offeringId}/trend | The offering's trend over the weeks |
| get_mentions | GET /api/v1/offerings/{offeringId}/mentions | Mentions across AI answers, past four weeks |
| get_job | GET /api/v1/jobs/{jobId} | Get a job |
| list_jobs | GET /api/v1/jobs | List jobs |
| get_plan | GET /api/v1/plan | The workspace's plan |
| get_usage | GET /api/v1/usage | The workspace's usage against its plan |
| list_notifications | GET /api/v1/notifications | List the workspace's notifications |
| get_setup | GET /api/v1/setup | The first-run checklist |
| get_email_preferences | GET /api/v1/email-preferences | Who gets the weekly email |
| get_report | GET /api/v1/report | The shareable report, as data |
| list_report_links | GET /api/v1/report-links | List shared report links |
| export_report_pdf | GET /api/v1/report.pdf | The report as a PDF |
| export_questions_csv | GET /api/v1/offerings/{offeringId}/questions.csv | Questions, answers, sources and rivals as CSV |
| get_workspace | GET /api/v1/workspace | Get the workspace |
| export_workspace | GET /api/v1/workspace/export | Export the workspace's data |
| list_audit_log | GET /api/v1/audit-log | List the audit log |
| add_brand | POST /api/v1/brands | Add a brand |
| check_search_console | POST /api/v1/brands/{brandId}/search-console/check | Search Console: check the connection or choose the property |
| disconnect_search_console | POST /api/v1/brands/{brandId}/search-console/disconnect | Search Console: disconnect |
| track_offerings | POST /api/v1/brands/{brandId}/track | Set offerings' tracking levels |
| add_not_tracking | POST /api/v1/brands/{brandId}/not-tracking | Leave an offering or a phrasing out |
| remove_not_tracking | POST /api/v1/not-tracking/{entryId}/remove | Take an entry off the not-tracking list |
| read_site_again | POST /api/v1/brands/{brandId}/read-site | Read the site again |
| prepare_offerings | POST /api/v1/brands/{brandId}/prepare | Pick offerings to track |
| decline_offering | POST /api/v1/offerings/{offeringId}/decline | Don't track an offering |
| retry_offering | POST /api/v1/offerings/{offeringId}/retry | Try an offering's preparation again |
| diagnose_again | POST /api/v1/offerings/{offeringId}/diagnose | Diagnose the latest read again |
| start_tracking | POST /api/v1/brands/{brandId}/start-tracking | Finish setup: start tracking |
| update_offering | PATCH /api/v1/offerings/{offeringId} | Change an offering's settings |
| add_prompt | POST /api/v1/offerings/{offeringId}/prompts | Add a prompt |
| add_prompts | POST /api/v1/offerings/{offeringId}/prompts/bulk | Add prompts in bulk |
| edit_prompt | PATCH /api/v1/prompts/{promptId} | Edit a prompt |
| approve_all_prompts | POST /api/v1/offerings/{offeringId}/prompts/approve-all | Approve all proposed prompts of an offering |
| approve_prompts | POST /api/v1/prompts/approve | Approve prompts |
| reject_prompts | POST /api/v1/prompts/reject | Reject proposed prompts |
| retire_prompt | POST /api/v1/prompts/{promptId}/retire | Retire a prompt |
| retire_prompts | POST /api/v1/prompts/retire | Retire prompts in bulk |
| add_competitor | POST /api/v1/brands/{brandId}/competitors | Add a competitor |
| update_competitor | PATCH /api/v1/competitors/{competitorId} | Change a competitor |
| review_competitors | POST /api/v1/competitors/review | Review competitors in one call |
| run_now | POST /api/v1/offerings/{offeringId}/runs | Run a read now |
| refresh_mentions | POST /api/v1/offerings/{offeringId}/mentions/refresh | Pull mentions across AI answers again |
| delete_imported_history | POST /api/v1/offerings/{offeringId}/history/delete-imported | Delete an offering's legacy imported history |
| link_ticket | POST /api/v1/actions/{actionId}/ticket | Link a card to its ticket |
| accept_action | POST /api/v1/actions/{actionId}/accept | Accept a card |
| dismiss_action | POST /api/v1/actions/{actionId}/dismiss | Dismiss a card |
| move_action | POST /api/v1/actions/{actionId}/move | Move a card |
| complete_action | POST /api/v1/actions/{actionId}/complete | Report a card's work done |
| record_external_work | POST /api/v1/offerings/{offeringId}/work | Record work done outside a card |
| mark_notifications_read | POST /api/v1/notifications/read | Mark notifications read |
| dismiss_setup | POST /api/v1/setup/dismiss | Hide or show the first-run checklist |
| dismiss_sample | POST /api/v1/sample/dismiss | Hide or show the sample brand |
| update_email_preferences | PATCH /api/v1/email-preferences | Turn your weekly email on or off |
| send_weekly_email_preview | POST /api/v1/email-preferences/preview | Send me a preview of the weekly email |
| create_report_link | POST /api/v1/report-links | Share a report by link |
| revoke_report_link | POST /api/v1/report-links/{linkId}/revoke | Turn off a report link |
| rename_workspace | PATCH /api/v1/workspace | Rename the workspace |
| delete_workspace | POST /api/v1/workspace/delete | Delete the workspace |