This is the full developer documentation for recomention # Introduction > What the API does, its base URL, and where to start. recomention answers one question: **do AI engines recommend your product?** It asks ChatGPT, Claude, Perplexity, Gemini, Grok and Google AI Overview the questions your buyers ask, several times each, and reports how often each engine named you, who it named instead, which sources it read, and what to fix. The API gives your code and your agents the same thing the website gives a person: * **Public rankings** — who the engines name for a category, with counts. No key needed. * **Reports** — start one for a product, poll it, then read every number and every answer as JSON. * **The Distribution Kit** — a finished report as Markdown files your agent can act on. ## Base URL [Section titled “Base URL”](#base-url) ```text https://api.recomention.com/v1 ``` Every endpoint is under `/v1`. Requests and responses are JSON over HTTPS. The machine-readable description is the [API reference](/reference/), generated from an OpenAPI 3.1 document. ## Where to start [Section titled “Where to start”](#where-to-start) 1. [Quickstart](/quickstart/) — create a key and make your first call in two minutes. 2. [Authentication](/authentication/) — how keys work and how to keep them safe. 3. [Reports](/guides/reports/) — start, poll, read, and fetch the kit. 4. [MCP server](/mcp/) — the same tools inside Claude Code, Cursor or Codex. ## Reading the numbers honestly [Section titled “Reading the numbers honestly”](#reading-the-numbers-honestly) AI engines are not deterministic, so every result is a rate, not a verdict: * Quote counts as **“named in n of m answers”**, never as yes or no. * An engine under `enginesSkipped` **did not run** — it is never an engine that left you out, and it never counts as zero. * An answer with `failed: true` is in no count. A failed call is not a miss. * A report with `simulated: true` is test data with made-up answers. Draw no conclusions from it. * Every report is a dated snapshot. Say the date when you quote it. ## Help [Section titled “Help”](#help) * Service status: * Email: * Product and pricing: [recomention.com](https://www.recomention.com) # Agent plan & your own keys > Run reports on your own provider keys (Bring Your Own Key) with the Agent plan. With the **Agent plan**, reports run on your own provider accounts: you send your provider keys with a start, and every engine call in that report uses them. Your keys pay the providers; the plan buys the runs, the dashboard and the history, within published limits. Prices and the current limits are on the [developers page](https://www.recomention.com/developers#pricing). Note Bring Your Own Key can be switched off on a server. When it is, a start with `funding: "byok"` returns `403` and nothing runs; use `funding: "credits"` instead. ## Start a report on your keys [Section titled “Start a report on your keys”](#start-a-report-on-your-keys) ```bash curl -X POST https://api.recomention.com/v1/reports \ -H "Authorization: Bearer $RECOMENTION_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(openssl rand -hex 16)" \ -d '{ "domain": "example.com", "category": "meeting scheduling", "description": "Booking links for sales teams", "plan": "FULL", "funding": "byok", "providerKeys": { "OPENAI": "sk-…", "PERPLEXITY": "pplx-…" } }' ``` `providerKeys` takes any of `OPENAI`, `ANTHROPIC`, `PERPLEXITY`, `GEMINI`, `GROK` and `AI_OVERVIEW` (a SERP API key in `login:password` form). * **Bring the keys you have.** Any subset works. An engine you send no key for is listed under `enginesSkipped`, never counted as an engine that left you out. * **One of OpenAI, Anthropic or Gemini is required.** One of them writes the questions and reads the answers. * **Keys go with `funding: "byok"` only.** Sending `providerKeys` with `funding: "credits"` is refused and nothing starts. ## How your keys are treated [Section titled “How your keys are treated”](#how-your-keys-are-treated) * **Used for that one report, then gone.** Your keys are held in memory while the report runs. They are never written to our database or our logs, and no response or error message ever repeats them. * **Locked while queued.** The queued job carries your keys encrypted. The other half of the lock is destroyed when the report ends, and it expires after a day regardless, so the queued copy can never be read again. * **Only your keys.** Every model call in a BYOK report uses the keys you sent, or a method that calls no model at all. We never fall back to ours. * **A rejected key is stated, not scored.** If a provider refuses your key, that engine shows as skipped with the reason “provider rejected the key”. It never counts as an engine that didn’t name you. * **What we keep:** that the report was BYOK, and which engines you sent a key for. ## Limits [Section titled “Limits”](#limits) The plan has published limits instead of “fair use”: | `limit` | What it bounds | | ----------------- | ------------------------------------ | | `projects` | Brands (domains) per billing period. | | `reportsPerMonth` | Reports per billing period. | | `perDay` | Reports in any 24 hours. | | `concurrent` | Reports running at once. | A refusal names the limit. Without an active plan a start returns `402` with `limit: "plan"`. Past a limit it returns `429` with the limit’s name, plus `Retry-After` and `retryAfterSeconds` when the wait is knowable (`perDay`, and the period limits when the period’s end is known; never `concurrent`). Nothing is queued and nothing is charged. See [plan limits](/rate-limits/#plan-limits-named-in-limit). ## On your dashboard [Section titled “On your dashboard”](#on-your-dashboard) Each report started on your keys joins the dashboard project for its domain, so every run sits in one place. You can also store provider keys in a project’s settings and run reports from the dashboard, and Track runs on your own keys at no extra charge. ## With the MCP server [Section titled “With the MCP server”](#with-the-mcp-server) Put your provider keys in the MCP server’s environment (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, `DATAFORSEO_API_KEY`), not in a prompt. See [MCP server](/mcp/). # Authentication > API keys, the Bearer header, and keeping keys safe. Rankings are public. Everything under `/v1/reports` needs an API key. ## Send the key as a Bearer token [Section titled “Send the key as a Bearer token”](#send-the-key-as-a-bearer-token) ```http Authorization: Bearer rmk_… ``` ```bash curl https://api.recomention.com/v1/reports -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` A missing, malformed, unknown or revoked key gets `401` with a `WWW-Authenticate: Bearer` header and an [error body](/errors/). ## Keys are shown once [Section titled “Keys are shown once”](#keys-are-shown-once) Create keys at [recomention.com/account](https://www.recomention.com/account) → **Developers**. * **Shown once.** When you create a key it is displayed one time. Only a fingerprint of it is stored, so nobody can show it to you again. Lost one? Revoke it and create another. * **Recognisable.** Every key starts with `rmk_`, so a leaked key is easy to spot in a log or a secret scanner. The account page shows the first few characters of each key so you can tell them apart. * **Up to 10 active keys** per account. * **Revocable.** A revoked key stops working within about a minute. The key stays listed, marked revoked. ## A key reads only its own account [Section titled “A key reads only its own account”](#a-key-reads-only-its-own-account) A report belonging to another account answers `404`, exactly like a report that does not exist. You cannot tell the two apart, by design. ## Starting reports needs a verified email [Section titled “Starting reports needs a verified email”](#starting-reports-needs-a-verified-email) The report link is emailed to the account’s address, so a start from an account whose email is not confirmed gets `403`. Sign in once with the email link or a verified Google/Apple account. ## Keeping keys safe [Section titled “Keeping keys safe”](#keeping-keys-safe) * **One key per agent or machine**, so you can revoke one without breaking the others. Each key also has its own [rate limit](/rate-limits/). * Keep keys in environment variables or a secret manager, never in a repository. * In an MCP client config, the key goes in the server’s `env`; see [MCP server](/mcp/). * If a key might have leaked, revoke it first and investigate after. # Changelog > Changes to the API, the MCP server and these docs. ## API v1 on its own host [Section titled “API v1 on its own host”](#api-v1-on-its-own-host) **`https://api.recomention.com/v1`** is the base URL for API v1. * Every endpoint is under `/v1`: rankings, reports, report status, the report itself and the Distribution Kit. See the [API reference](/reference/). * Report starts accept an `Idempotency-Key` header, as well as the body field `idempotencyKey`. See [idempotency](/rate-limits/#idempotency-retry-a-start-safely). * Rate-limit `429` responses carry `Retry-After` and `RateLimit-*` headers; plan-limit `429`s name the `limit` instead. See [the two kinds of 429](/rate-limits/#when-you-hit-one). * The OpenAPI 3.1 description is published, and the [API reference](/reference/) is generated from it. ### Deprecated: `https://www.recomention.com/api/v1` [Section titled “Deprecated: https://www.recomention.com/api/v1”](#deprecated-httpswwwrecomentioncomapiv1) The original base, `https://www.recomention.com/api/v1`, still answers as an alias of v1, so existing scripts keep working. It is deprecated: move to `https://api.recomention.com/v1`. The paths are the same after the base — `https://www.recomention.com/api/v1/reports` becomes `https://api.recomention.com/v1/reports`. Responses from the old base carry a `Deprecation` header and a `Link: <…>; rel="successor-version"` header pointing at the same endpoint on the new host. The old base never redirects, because a cross-origin redirect would drop your `Authorization` header. A removal date will be announced here first. ## MCP server [Section titled “MCP server”](#mcp-server) * **stdio:** `@recomention/mcp` for Claude Code, Cursor and Codex, with four agent skills. Publishing to npm soon. See [MCP server](/mcp/). * **Hosted:** planned at `https://mcp.recomention.com/mcp`. Not live yet. ## Docs [Section titled “Docs”](#docs) * These docs launched at , with [llms.txt](/llms.txt) and [llms-full.txt](/llms-full.txt) for agents and a Copy Markdown button on every guide. # Errors > The JSON error envelope and what each status code means. Every error is JSON with one required field: ```json { "error": "Send a valid API key as `Authorization: Bearer `." } ``` `error` is a sentence meant for a person. It never repeats a value you sent, so it is safe to log. Some errors add fields: | Field | When | Meaning | | ------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `fields` | `400` | The request fields to fix, e.g. `["domain"]` or `["seedPrompts"]`. | | `retryAfterSeconds` | `429` | How long to wait, when that is knowable. The `Retry-After` header says the same. Absent for the `concurrent` plan limit. | | `limit` | `402`, `429` on a start | Which [Agent plan](/agent-plan/) limit refused it: `plan`, `projects`, `reportsPerMonth`, `perDay` or `concurrent`. | | `status` | `409` | The report’s current status, when that is the reason. | Match on the status code and these fields, not on the wording of `error`, which may change. ## Status codes [Section titled “Status codes”](#status-codes) | Code | Meaning | What to do | | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | `200` | OK. On a start: an earlier start with the same idempotency key, returned again (`reused: true`). | — | | `202` | Report started. | Poll its `statusUrl`. | | `400` | Invalid request: a missing or malformed field, a seed question that names the product, an engine outside the plan, or provider keys sent with `funding: "credits"`. | Fix the `fields` and resend. | | `401` | Missing, malformed, unknown or revoked key, or the key’s account no longer exists. | Check the key. See [Authentication](/authentication/). | | `402` | No funding: no agency credit left, or no active Agent plan for a start on your own keys. | Buy credits or start the plan in your account. | | `403` | Not allowed: unverified email, own-key reports not enabled, or a kit for an unpaid report. | Read `error`. | | `404` | No such ranking or report — or a report in another account, which answers the same. | Check the slug and the key. | | `409` | Not yet possible: the kit before the report is `COMPLETE`, or a retried credit start whose credit is already back in your balance (the report could not be queued, or it ran, failed and was refunded). | Wait for the kit; for a start, send a new start with a new idempotency key. | | `413` | Body larger than 32 KB. | Send less. | | `429` | Too many requests (with `Retry-After`), or an Agent plan limit (with `limit`). | See [the two kinds of 429](/rate-limits/#when-you-hit-one). | | `503` | A dependency is briefly unavailable. On a report start the outcome is **unknown**: see below. | Retry after `Retry-After` seconds. On a start, retry with the **same** idempotency key. | ## Refused starts cost nothing [Section titled “Refused starts cost nothing”](#refused-starts-cost-nothing) A `4xx` refusal of `POST /v1/reports` — validation, funding, or a limit — happens before anything is spent or queued. ## A 503 on a start is an unknown outcome [Section titled “A 503 on a start is an unknown outcome”](#a-503-on-a-start-is-an-unknown-outcome) A `503` (or a timeout, or a dropped connection) on `POST /v1/reports` does **not** prove that nothing happened: the start may have gone through and the report may still be running. Treat it as unknown: 1. Retry the start with the **same** `Idempotency-Key` and the same body. If the first attempt went through, you get it back (`200`, `reused: true`) and nothing new is spent. 2. Or check `GET /v1/reports` for the report before deciding. **Never retry an unknown outcome with a new idempotency key**: that can start, and pay for, a second report. See [idempotency](/rate-limits/#idempotency-retry-a-start-safely). ## When a running report fails [Section titled “When a running report fails”](#when-a-running-report-fails) If a credit-funded report starts and then fails, its credit normally returns to your balance automatically. Automatic returns are limited to 3 per account in any 30 days for reports that started; past that, the failed report’s credit is held for review and support decides. Reports that never started cost nothing and do not count toward the limit. # Rankings > The public AI rankings — who the engines name for a category, with counts. No key needed. Rankings are recomention‘s public research: for a category such as “accounting software”, the same buyer questions are put to every engine, and every brand named is counted. They are the same data as the [AI rankings pages](https://www.recomention.com/ai-rankings) on the website, and they need no API key. ## List the rankings [Section titled “List the rankings”](#list-the-rankings) ```bash curl https://api.recomention.com/v1/rankings ``` ```json { "rankings": [ { "slug": "accounting-software", "category": "accounting software", "month": "2026-10", "prompts": ["What is the best accounting software for a small business?"], "checkedAt": "2026-10-03T09:12:00.000Z", "engines": ["OPENAI", "ANTHROPIC", "PERPLEXITY", "GEMINI", "GROK"], "top": [{ "name": "QuickBooks", "domain": "quickbooks.intuit.com", "mentions": 41 }], "answers": 75, "url": "https://www.recomention.com/ai-rankings/accounting-software" } ] } ``` Each entry is a category’s latest month: the questions asked, the engines, the five brands named most, and `answers`, the number of answers counted. `mentions` is always out of `answers`, so quote it as “named in 41 of 75 answers”. ## Get one ranking [Section titled “Get one ranking”](#get-one-ranking) ```bash curl https://api.recomention.com/v1/rankings/accounting-software ``` The full ranking adds every brand named with its mention count and average position, and every answer verbatim (`answers[]`, each with the question index, engine and run). Further fields may be added over time; ignore the ones you don’t use. The numbers in these examples are illustrative; the list endpoint has the real ones. ## Use them before you spend [Section titled “Use them before you spend”](#use-them-before-you-spend) A ranking is free evidence. Before starting a paid report for a product, check whether a ranking already covers its category and where the product appears in it. The [MCP server](/mcp/)’s skills do this automatically. ## Caching [Section titled “Caching”](#caching) Ranking responses are cacheable for five minutes (`Cache-Control: public, max-age=300`). Rankings change monthly, so there is no reason to poll them. # Reports > Start a report, poll its status, read the result, and fetch the Distribution Kit. A report asks each engine your buyers’ questions several times and records every answer. The flow is always the same: 1. **Start** — `POST /v1/reports` 2. **Poll** — `GET /v1/reports/{slug}/status`, about once a minute 3. **Read** — `GET /v1/reports/{slug}` when the status is `COMPLETE` 4. **Act** — `GET /v1/reports/{slug}/kit` for Markdown files your agent can work from ## 1. Start [Section titled “1. Start”](#1-start) ```bash curl -X POST https://api.recomention.com/v1/reports \ -H "Authorization: Bearer $RECOMENTION_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(openssl rand -hex 16)" \ -d '{ "domain": "example.com", "category": "meeting scheduling", "description": "Booking links for sales teams", "plan": "FULL", "funding": "credits" }' ``` | Field | Required | | | ---------------- | --------- | -------------------------------------------------------------------------------------------------------- | | `domain` | yes | The product’s domain. | | `category` | yes | What buyers search for, in their words. | | `description` | yes | One line on what the product does. | | `funding` | yes | `"credits"` or `"byok"`. See below. | | `plan` | no | `QUICK`, `FULL` (default) or `DEEP`. A credit runs `FULL`. | | `brand` | no | The product’s name, if it differs from the domain. | | `engines` | no | A subset of the plan’s engines: `OPENAI`, `ANTHROPIC`, `PERPLEXITY`, `GEMINI`, `GROK`, `AI_OVERVIEW`. | | `seedPrompts` | no | Questions you want asked (up to the plan’s question count). The rest are written for you. | | `providerKeys` | byok only | Your provider keys. See [Agent plan & your own keys](/agent-plan/). | | `idempotencyKey` | no | Same as the `Idempotency-Key` header. See [idempotency](/rate-limits/#idempotency-retry-a-start-safely). | **No seed question may name the product.** The point is to see whether the engines name it unprompted, so such a request is refused with `400`. ### Funding [Section titled “Funding”](#funding) Nothing starts without funding the server can verify: * **`"credits"`** spends one agency credit on a `FULL` report. Buy credits from your account on [recomention.com](https://www.recomention.com). * **`"byok"`** runs on your own provider keys and needs the [Agent plan](/agent-plan/). The response: ```json { "slug": "Xq3vR8tLmN2pK7wA", "status": "PENDING", "reused": false, "funding": "credits", "url": "https://www.recomention.com/r/Xq3vR8tLmN2pK7wA", "statusUrl": "https://api.recomention.com/v1/reports/Xq3vR8tLmN2pK7wA/status" } ``` `202` means a new report started. `200` with `reused: true` means you retried with the same idempotency key and got the original back; nothing new was spent. The report link is also emailed to the account. ## 2. Poll the status [Section titled “2. Poll the status”](#2-poll-the-status) ```bash curl https://api.recomention.com/v1/reports/Xq3vR8tLmN2pK7wA/status \ -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` ```json { "status": { "slug": "Xq3vR8tLmN2pK7wA", "status": "RUNNING", "simulated": false, "progress": { "answersStored": 41, "answersPlanned": 90 }, "overallScore": null, "error": null } } ``` | Status | Meaning | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `PENDING` | Queued. | | `RUNNING` | Asking the engines. `progress` counts answers stored against answers planned. | | `COMPLETE` | Done. Read it. | | `FAILED` | It did not finish. `error` says so. A credit-funded report’s credit normally returns automatically, up to 3 returns in 30 days for started reports; past that it is held for review ([details](/errors/#when-a-running-report-fails)). | Reports take several minutes. Poll **about once a minute**, and do not start a second report for the same product while one is running. ## 3. Read the report [Section titled “3. Read the report”](#3-read-the-report) ```bash curl https://api.recomention.com/v1/reports/Xq3vR8tLmN2pK7wA \ -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` The report JSON has the same data the report page shows: | Field | | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `overallScore` | 0–100, once `COMPLETE`. | | `engines[]` | Per engine: `runsMentioned` of `runsTotal` answers named the product, `promptsMentioned` of `promptsTotal` questions, and the average position when named. | | `enginesSkipped[]` | Engines that did not run, each with a `reason` such as “provider rejected the key”. | | `competitors[]` | Who was named instead, with their share of answers. | | `sources[]` | The domains the engines cited, how often, and whether the product’s own site is among them. | | `actionPlan[]` | The fix list: what to do, why, and how much effort. | | `questions[]` | Every question and every answer, verbatim, with the brands and citations in each. | ### Rules for reading it [Section titled “Rules for reading it”](#rules-for-reading-it) * **Quote rates, not verdicts.** “ChatGPT named it in 4 of 9 answers”, not “ChatGPT recommends it”. * **`enginesSkipped` is not a zero.** A skipped engine did not run. Say why; never describe it as an engine that left the product out. * **`failed: true` answers are in no count.** A failed call is excluded from every number, never treated as “not mentioned”. * **`noAnswer`** means the engine gave nothing to score (for example, Google showed no AI Overview). It is not a miss either. * **`simulated: true`** is test data with made-up answers. Say so first and draw no conclusions. * **Date it.** Every report is a snapshot; quote `completedAt` with the numbers. ## 4. Fetch the Distribution Kit [Section titled “4. Fetch the Distribution Kit”](#4-fetch-the-distribution-kit) ```bash curl https://api.recomention.com/v1/reports/Xq3vR8tLmN2pK7wA/kit \ -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` The kit is a set of Markdown files built from the finished report, with no extra model call: what the product is and the buyer questions, who the engines name instead, the measured result per engine, the third-party pages, communities and videos the engines cite for a rival and not for you, and a channel plan ranked by those citations, each channel with a first task. ```json { "kit": { "slug": "Xq3vR8tLmN2pK7wA", "brand": "Example", "domain": "example.com", "simulated": false, "files": [{ "path": "product.md", "content": "# Example\n…" }] } } ``` The kit comes with a paid report (`403` otherwise) and only once it is `COMPLETE` (`409` before, with the current `status`). Every count keeps its denominator, and nothing in it promises traffic: a later report shows whether the answers moved. ## List your reports [Section titled “List your reports”](#list-your-reports) ```bash curl https://api.recomention.com/v1/reports -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` Your reports, newest first, up to 100. Reports on your own keys join the dashboard project for their domain, so every run sits in one place in your account. # MCP server > Use the API from Claude Code, Cursor or Codex through the Model Context Protocol. Ask your coding agent *“is my product recommended by ChatGPT for meeting scheduling?”* and let it find out. The recomention MCP server gives Claude Code, Cursor, Codex and other MCP clients tools to read rankings, start a report, wait for it, and read the result. It is a thin client for the [JSON API](/) and holds no state. It uses the same [API key](/authentication/). Publishing soon The stdio server, `@recomention/mcp`, is **not on npm yet**, so the install commands below will fail with “not found” until it is published. Until then, everything the server does is available through the [JSON API](/guides/reports/) with the same key. The [changelog](/changelog/) will say when the package is listed. ## Install (stdio) — once published [Section titled “Install (stdio) — once published”](#install-stdio--once-published) The server runs locally through `npx` and reads your key from its environment, so the key never passes through the model’s context. Replace `rmk_…` with your key, and never commit a config that contains it. ### Claude Code [Section titled “Claude Code”](#claude-code) ```bash claude mcp add recomention \ --env RECOMENTION_API_KEY=rmk_… \ -- npx -y @recomention/mcp ``` ### Cursor [Section titled “Cursor”](#cursor) `~/.cursor/mcp.json` (the same JSON works for most JSON-configured clients): ```json { "mcpServers": { "recomention": { "command": "npx", "args": ["-y", "@recomention/mcp"], "env": { "RECOMENTION_API_KEY": "rmk_…" } } } } ``` ### Codex [Section titled “Codex”](#codex) `~/.codex/config.toml`: ```toml [mcp_servers.recomention] command = "npx" args = ["-y", "@recomention/mcp"] env = { RECOMENTION_API_KEY = "rmk_…" } ``` Restart or reload MCP servers, then ask the agent to call `recomention_rankings_list` to confirm it works. ### Environment [Section titled “Environment”](#environment) | Variable | | | | ------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `RECOMENTION_API_KEY` | required for reports | From your account → Developers. Shown once. | | `RECOMENTION_BASE_URL` | optional | Defaults to `https://api.recomention.com`. Leave it unset unless told otherwise. | | `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, `DATAFORSEO_API_KEY` | optional | Only for `funding: "byok"`. See [Agent plan & your own keys](/agent-plan/). Read from the server’s environment, never from a tool argument. | ### Or let the agent set itself up [Section titled “Or let the agent set itself up”](#or-let-the-agent-set-itself-up) Once the package is published, your account’s Developers card shows a **Copy setup prompt** button. Paste the prompt into your agent and it installs the server and asks you for the key. ## Tools [Section titled “Tools”](#tools) | Tool | Cost | What it does | | ------------------------------ | ---------- | --------------------------------------------------------------------------------------- | | `recomention_rankings_list` | free | List the public AI rankings. No key needed. | | `recomention_rankings_get` | free | One ranking: who the engines name for a category, with counts. | | `recomention_suggest_prompts` | free | Buyer questions worth checking, from templates. No model call. Never names the product. | | `recomention_report_start` | **spends** | Start a report, funded by an agency credit or by your own provider keys. | | `recomention_report_status` | free | Where a report is: queued, running, finished or failed. | | `recomention_report_get` | free | A finished report as JSON: scores, competitors, sources, fix list, every answer. | | `recomention_distribution_kit` | free | A finished report as Markdown files: where to get mentioned and a channel plan. | | `recomention_reports_list` | free | Your reports, newest first. | `recomention_report_start` is the only tool that spends anything. A well-behaved agent asks you before calling it and says which funding it will use; the skills below do. ## Skills [Section titled “Skills”](#skills) The package ships agent skills in the slash-command style. Copy a folder from its `skills/` directory into `.claude/skills/` (Claude Code) or your agent’s equivalent: * **`ai-visibility-check`** — check one product end to end: free rankings first, draft questions with you, confirm spend, start, wait, summarise honestly. * **`fix-list-review`** — turn a finished report into a prioritised, honest plan of work. * **`competitor-watch`** — compare who the engines name in a category, from public rankings and your reports. * **`distribution-kit`** — read a finished report’s kit and work through its channel plan, one channel at a time. ## Hosted MCP — coming soon [Section titled “Hosted MCP — coming soon”](#hosted-mcp--coming-soon) A hosted server is planned, so you can connect without running anything locally: ```text https://mcp.recomention.com/mcp ``` It will speak Streamable HTTP and authenticate with the same API key as a Bearer token. It is not live yet; use the stdio server above until the [changelog](/changelog/) announces it. # Quickstart > Create an API key and make your first calls. ## 1. Try a public endpoint [Section titled “1. Try a public endpoint”](#1-try-a-public-endpoint) Rankings are public, so this works before you have a key: ```bash curl https://api.recomention.com/v1/rankings ``` You get every category’s latest ranking: the questions asked, the engines, and the five brands named most, with counts. ## 2. Create an API key [Section titled “2. Create an API key”](#2-create-an-api-key) 1. Sign in at [recomention.com/account](https://www.recomention.com/account) with Google, Apple or a one-time email link. 2. Open **Developers** and create a key. Give it a name that says where it will live, such as “laptop” or “CI”. 3. Copy it now. **The key is shown once.** It starts with `rmk_`. Put it in your shell’s environment, not in a file you might commit: ```bash export RECOMENTION_API_KEY="rmk_…" ``` ## 3. List your reports [Section titled “3. List your reports”](#3-list-your-reports) ```bash curl https://api.recomention.com/v1/reports \ -H "Authorization: Bearer $RECOMENTION_API_KEY" ``` A new account returns `{"reports": []}`. A `401` means the key is missing, mistyped or revoked; see [Authentication](/authentication/). ## 4. Start a report [Section titled “4. Start a report”](#4-start-a-report) Starting a report spends money: an agency credit, or calls on your own provider keys. The body says which, and nothing runs without it. ```bash curl -X POST https://api.recomention.com/v1/reports \ -H "Authorization: Bearer $RECOMENTION_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(openssl rand -hex 16)" \ -d '{ "domain": "example.com", "category": "meeting scheduling", "description": "Booking links for sales teams", "plan": "FULL", "funding": "credits" }' ``` The answer is `202` with the report’s `slug` and a `statusUrl`. A report takes several minutes; poll the status about once a minute, then read it. The [Reports guide](/guides/reports/) walks through every step. ## Next [Section titled “Next”](#next) * [Errors](/errors/) — what each status code means. * [Rate limits & idempotency](/rate-limits/) — retry safely. * [MCP server](/mcp/) — let your coding agent do all of this. # Rate limits & idempotency > Request limits, the two kinds of 429, and retrying a report start safely. ## Limits [Section titled “Limits”](#limits) | Limit | Applies to | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **60 requests per minute** | Each API key, across all endpoints. | | **10 report starts per hour** | Each API key, on `POST /v1/reports`, on top of the per-minute limit. | | Plan limits | Starts on your own provider keys are also bounded by the [Agent plan](/agent-plan/): brands, reports per billing period, reports in any 24 hours, and reports at once. | Rate-limit windows are fixed: a per-minute budget resets at the start of each minute. Requests without a valid key (public rankings, a missing or mistyped key) are limited per client address instead. ## When you hit one [Section titled “When you hit one”](#when-you-hit-one) There are two kinds of `429`. Tell them apart by the `limit` field. ### Rate limits: wait and retry [Section titled “Rate limits: wait and retry”](#rate-limits-wait-and-retry) Over the per-minute or per-hour budget, you get `429` with a JSON [error](/errors/), `retryAfterSeconds` in the body, and these headers: | Header | Meaning | | --------------------- | ------------------------------------------- | | `Retry-After` | Seconds to wait before retrying. | | `RateLimit-Limit` | Requests allowed in the window. | | `RateLimit-Remaining` | Requests left in the window (`0` on a 429). | | `RateLimit-Reset` | Seconds until the window resets. | Wait `Retry-After` seconds, then retry. ### Plan limits: named in `limit` [Section titled “Plan limits: named in limit”](#plan-limits-named-in-limit) A start refused by an Agent plan limit is a `429` whose body names the limit in `limit`. It never carries `RateLimit-*` headers. Whether it says when to retry depends on the limit: | `limit` | `Retry-After` and `retryAfterSeconds` | When it lifts | | ----------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------- | | `perDay` | Yes | When the oldest start in the last 24 hours turns 24 hours old. | | `reportsPerMonth`, `projects` | Yes, when the billing period’s end is known | At the next billing period. | | `concurrent` | **Never** | When one of your running reports finishes. Poll its status, then start again. | Without an active Agent plan, a start is refused with `402` and `limit: "plan"`, also with no retry time. Don’t retry plan limits in a loop. Nothing was queued and nothing was charged. ### Polling without burning the budget [Section titled “Polling without burning the budget”](#polling-without-burning-the-budget) A report takes several minutes. Poll `GET /v1/reports/{slug}/status` about **once a minute**; faster polling only spends your budget. Honour `Retry-After` and back off on repeated `429`s. ## Idempotency: retry a start safely [Section titled “Idempotency: retry a start safely”](#idempotency-retry-a-start-safely) Starting a report spends money, and networks fail. Send an idempotency key with every start so a retry can never spend twice: ```bash curl -X POST https://api.recomention.com/v1/reports \ -H "Authorization: Bearer $RECOMENTION_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 9f1c2e7a4b6d8e0f1a2b3c4d" \ -d '{"domain":"example.com","category":"meeting scheduling","description":"Booking links for sales teams","plan":"FULL","funding":"credits"}' ``` * The key is 16–128 characters of letters, digits, `-` and `_`. Generate a random one per start (for example `openssl rand -hex 16`). * Send it as the `Idempotency-Key` header or as `idempotencyKey` in the body. If you send both, they must match. * **Same key, same body → the first start.** The response is `200` with `reused: true` and the original `slug`. Nothing new is spent. * **A key identifies one start together with its body.** The same key with a different body is a different start. Reuse a key only to retry the *same* request; a new report needs a new key. * **`providerKeys` are not part of that fingerprint.** Retrying a BYOK start with the same idempotency key and corrected provider keys returns the first report, which ran (or failed) with the old keys. To run again with different keys, use a new idempotency key. * **If the first start’s credit was returned** — it could not be queued, or it ran, failed and was refunded — a retry with the same key gets `409` instead of a replay. Send a new start with a new key. * **Keys are scoped to your account.** The same string sent from another account is that account’s own, separate request. * Without a key, every request is a new start. After a `503`, a timeout or a dropped connection, the outcome of a start is unknown. Retry with the **same** key, or check `GET /v1/reports`. Never retry with a new key, which could start a second report. See [Errors](/errors/#a-503-on-a-start-is-an-unknown-outcome).