# FreshlyCited docs (full text) > Every page of the FreshlyCited API & MCP docs hub in one Markdown file, for AI assistants. MCP server: https://freshlycited.com/mcp · REST: https://freshlycited.com/api/v1 · OpenAPI: https://freshlycited.com/openapi.json --- # FreshlyCited API & MCP docs FreshlyCited asks Google to crawl your new and updated pages and backlinks, re-checks them on day 1, 3 and 7, and shows you which ones Google has indexed. Google sets the pace; a link still not indexed after day 7 gets its credit back. Everything in the app is available to AI agents through an **MCP server** and to your own code through a **REST API**: run visibility checks, push the links Google can't see, notify Bing through IndexNow, and share before/after reports. Being crawled and indexed is the first step to showing up in search results and AI answers. FreshlyCited can't guarantee indexing, rankings or AI citations; it makes the request and reports exactly what the checks find. ## Start here 1. [Quickstart](https://freshlycited.com/docs/quickstart): connect a client and run your first check in about five minutes. 2. Pick your client: [Claude Code](https://freshlycited.com/docs/clients/claude-code), [Claude Desktop](https://freshlycited.com/docs/clients/claude-desktop), [Claude.ai](https://freshlycited.com/docs/clients/claude-ai), [ChatGPT](https://freshlycited.com/docs/clients/chatgpt), [Cursor](https://freshlycited.com/docs/clients/cursor), [VS Code](https://freshlycited.com/docs/clients/vscode) or [Windsurf](https://freshlycited.com/docs/clients/windsurf). 3. Ask your agent to call `get_started`. It reads your account and suggests the next step. ## Endpoints | What | URL | | --- | --- | | MCP server (Streamable HTTP) | `https://freshlycited.com/mcp` | | REST API | `https://freshlycited.com/api/v1` | | OpenAPI 3.1 spec | [https://freshlycited.com/openapi.json](https://freshlycited.com/openapi.json) | | These docs as one text file | [https://freshlycited.com/llms-full.txt](https://freshlycited.com/llms-full.txt) | Every docs page also has a Markdown version: add `.md` to its URL, for example [/docs/quickstart.md](https://freshlycited.com/docs/quickstart.md). ## What you can do - **Visibility checks** (`check_index`): ask whether Google shows each URL (1 check credit per URL; Live checks 5). - **Pushes** (`submit_index_job`): get URLs crawled. Each URL reserves 1 index credit, used only if Google indexes it: we re-check on day 1, 3 and 7 and give the credit back automatically if it isn't indexed by day 7. A free pre-flight flags 404s, noindex, robots.txt blocks, redirects and canonicals pointing elsewhere before anything is reserved. With `smart: true` FreshlyCited checks first (1 check credit per URL) and only pushes the ones Google doesn't show yet. - **Bing & Copilot via IndexNow**: verify your site once and every push also notifies Bing, Copilot and the other IndexNow engines, free ([IndexNow API docs](https://freshlycited.com/docs/indexnow)). - **Proof**: automatic re-checks on day 1, 3 and 7 (credit back if a link still isn't indexed after day 7), a before/after visibility lift, CSV export and a [shareable client report](https://freshlycited.com/docs/recipes/share-client-report). - **Agencies**: client workspaces, credit allocation, members and per-client API keys. The full list of 49 tools is in the [MCP tool reference](https://freshlycited.com/docs/tools), generated from the live server. ## Authentication in one paragraph Scripts and most MCP clients use an **API key** (`Authorization: Bearer ipk_…`), created under **API keys** in the app. Claude.ai, ChatGPT and other connectors use **OAuth 2.1**: you sign in to FreshlyCited, pick a workspace and access level, and the app gets a short-lived token. Details: [Authentication](https://freshlycited.com/docs/authentication) and [Rate limits](https://freshlycited.com/docs/rate-limits). --- Source: https://freshlycited.com/docs --- # Quickstart: FreshlyCited MCP in 5 minutes This guide connects an AI client to FreshlyCited, checks a few of your pages and pushes the ones Google can't see yet. ## 1. Get access [Request an invite](https://freshlycited.com/sign-up) (FreshlyCited is invite-only for now; with your invite you sign up with Google or an email link, and new accounts start on Free: 10 free links to try, then 100 free checks a month). To use an API key instead of signing in through OAuth, open **API keys** in the app and create one. It's shown once and starts with `ipk_`. ## 2. Connect your client The MCP server URL is the same everywhere: ```text https://freshlycited.com/mcp ``` For Claude Code, one command does it: ```bash claude mcp add --transport http freshlycited https://freshlycited.com/mcp ``` Then type `/mcp` in Claude Code and choose FreshlyCited to sign in. Other clients: [Claude Desktop](https://freshlycited.com/docs/clients/claude-desktop), [Claude.ai](https://freshlycited.com/docs/clients/claude-ai), [ChatGPT](https://freshlycited.com/docs/clients/chatgpt), [Cursor](https://freshlycited.com/docs/clients/cursor), [VS Code](https://freshlycited.com/docs/clients/vscode), [Windsurf](https://freshlycited.com/docs/clients/windsurf). ## 3. Ask for a starting point Ask your agent: *"Use FreshlyCited's get_started tool and tell me what to do first."* It returns your role, workspace, credit balance and tailored next steps. ## 4. Check a few pages > A visibility check costs 1 check credit per URL and tells you, per URL, whether Google shows it. ```json { "name": "check_index", "arguments": { "urls": ["https://example.com/new-post", "https://example.com/pricing"] } } ``` The same with the REST API: ```bash curl -X POST https://freshlycited.com/api/v1/check \ -H "Authorization: Bearer ipk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"urls":["https://example.com/new-post","https://example.com/pricing"]}' ``` Standard checks can take a few minutes. Poll `get_job_status` with the returned `id` until the outcome says how many are seen. ## 5. Push the invisible ones ```json { "name": "send_unindexed_to_indexer", "arguments": { "job_id": "job_…" } } ``` That starts a push with only the URLs Google can't see; FreshlyCited re-checks them on day 1, 3 and 7. You can also push any list directly with `submit_index_job` and `smart: true`. ## 6. Optional: notify Bing too [Verify your site for IndexNow](https://freshlycited.com/docs/recipes/verify-site-indexnow) once. From then on every push also notifies Bing, Copilot and the other IndexNow engines, free. ## Next - [MCP tool reference](https://freshlycited.com/docs/tools) and [REST API reference](https://freshlycited.com/docs/api) - [Recipes](https://freshlycited.com/docs/recipes) for common workflows - [AGENTS.md snippet](https://freshlycited.com/docs/agents-md) so your coding agent uses FreshlyCited after it ships pages --- Source: https://freshlycited.com/docs/quickstart --- # Connect Claude Code to FreshlyCited MCP Claude Code connects to remote MCP servers over HTTP. FreshlyCited supports both ways Claude Code can sign in: OAuth (recommended) and an API key header. ## Add the server (OAuth) ```bash claude mcp add --transport http freshlycited https://freshlycited.com/mcp ``` Start Claude Code, type `/mcp`, pick **freshlycited** and choose to authenticate. Your browser opens the FreshlyCited consent screen: sign in, choose the workspace and the access level (full or read-only), and allow. Claude Code stores and refreshes the token for you. ## Add the server with an API key ```bash claude mcp add --transport http freshlycited https://freshlycited.com/mcp \ --header "Authorization: Bearer ipk_YOUR_KEY" ``` API keys are created under **API keys** in the FreshlyCited app and shown once. A key only sees its own workspace and the clients under it, with the key's role. ## Choose the scope - `--scope local` (default): only you, only this project. - `--scope project`: written to `.mcp.json` in the repository so your team gets it too. Use OAuth here, or reference an environment variable; never commit a key. - `--scope user`: available in all your projects. ```bash claude mcp add --transport http --scope user freshlycited https://freshlycited.com/mcp ``` ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. Tip: paste the [AGENTS.md snippet](https://freshlycited.com/docs/agents-md) into your repository so Claude Code checks and pushes new pages after it ships them. --- Source: https://freshlycited.com/docs/clients/claude-code --- # Connect Claude Desktop to FreshlyCited MCP There are two ways to use FreshlyCited in Claude Desktop: as a custom connector with OAuth (no key to manage), or as a local bridge with an API key. ## Recommended: add a custom connector Claude Desktop shares connectors with Claude.ai. In Claude Desktop open **Settings › Connectors**, choose **Add custom connector**, name it FreshlyCited and paste: ```text https://freshlycited.com/mcp ``` Click **Connect**. The FreshlyCited consent screen opens: sign in, pick the workspace and access level, and allow. Full steps and plan notes: [Claude.ai connector](https://freshlycited.com/docs/clients/claude-ai). ## Alternative: claude_desktop_config.json with an API key `claude_desktop_config.json` only runs local servers, so a remote server goes through the `mcp-remote` bridge (needs Node.js). Open **Settings › Developer › Edit Config** and add: ```json { "mcpServers": { "freshlycited": { "command": "npx", "args": [ "-y", "mcp-remote", "https://freshlycited.com/mcp", "--header", "Authorization:${AUTH_HEADER}" ], "env": { "AUTH_HEADER": "Bearer ipk_YOUR_KEY" } } } } ``` Keep `Authorization:${AUTH_HEADER}` exactly as written, without spaces around the colon: the key itself lives in `env`. Restart Claude Desktop afterwards. API keys are created under **API keys** in the FreshlyCited app and shown once. A key only sees its own workspace and the clients under it, with the key's role. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/claude-desktop --- # Add FreshlyCited as a Claude.ai connector Claude.ai can use remote MCP servers as **custom connectors**. FreshlyCited signs you in with OAuth, so there's no key to paste. ## Steps 1. In Claude.ai open **Customize › Connectors**. 2. Click **+ Add**, then **Add custom connector**. 3. Name: `FreshlyCited`. Remote MCP server URL: `https://freshlycited.com/mcp`. 4. Click **Connect**. You land on the FreshlyCited consent screen. 5. Sign in, choose the workspace (your agency or one client) and the access level: **Full access** (push and check, spends credits) or **Read-only**. Click **Allow**. 6. In a chat, open the tools menu and make sure FreshlyCited is enabled. ## Plans Custom connectors are available on Free (one custom connector), Pro, Max, Team and Enterprise plans. On Team and Enterprise an Owner adds the connector under **Organization settings › Connectors**; members then connect their own FreshlyCited login. ## What Claude sees The connection acts as you, in the workspace you chose, with your role there (or read-only). Revoke it any time in FreshlyCited under **API keys › Connected apps**, or remove the connector in Claude. Claude uses the callback `https://claude.ai/api/mcp/auth_callback`. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/claude-ai --- # Connect ChatGPT to FreshlyCited MCP ChatGPT can add remote MCP servers that use OAuth. Availability depends on your plan and workspace settings, and on some plans an admin has to turn on developer mode first. ## Steps 1. On chatgpt.com (web) open **Plugins** (Apps) and click **+**, then **Add custom MCP server**. 2. Name: `FreshlyCited`. Server URL: `https://freshlycited.com/mcp`. 3. Authentication: **OAuth**. 4. Accept the notice and create it. ChatGPT opens the FreshlyCited consent screen. 5. Sign in, choose the workspace and access level (Full access or Read-only), and click **Allow**. 6. Enable FreshlyCited in a chat and ask: *"Check which of these URLs Google can see: …"*. ## Notes - ChatGPT registers itself automatically (client metadata document or dynamic registration), so there's no client ID to copy. - The connection acts as you in the chosen workspace. Revoke it under **API keys › Connected apps** in FreshlyCited. - Spending tools ask for confirmation above 1,000 credits per call, so ChatGPT will check with you before large pushes. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/chatgpt --- # Connect Cursor to FreshlyCited MCP Cursor connects to remote MCP servers over HTTP and supports OAuth, so you can sign in with your FreshlyCited login or use an API key from an environment variable. ## One-click install Open this link on a computer with Cursor installed: [Add FreshlyCited to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=freshlycited&config=eyJ1cmwiOiJodHRwczovL2ZyZXNobHljaXRlZC5jb20vbWNwIn0%3D). Cursor shows the server and asks you to confirm; it signs in with OAuth the first time a tool runs. ## mcp.json (OAuth) Add FreshlyCited to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (this project): ```json { "mcpServers": { "freshlycited": { "url": "https://freshlycited.com/mcp" } } } ``` ## mcp.json with an API key Keep the key in an environment variable instead of the file: ```json { "mcpServers": { "freshlycited": { "url": "https://freshlycited.com/mcp", "headers": { "Authorization": "Bearer ${env:FRESHLYCITED_API_KEY}" } } } } ``` ```bash export FRESHLYCITED_API_KEY=ipk_YOUR_KEY ``` API keys are created under **API keys** in the FreshlyCited app and shown once. A key only sees its own workspace and the clients under it, with the key's role. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/cursor --- # Connect VS Code to FreshlyCited MCP VS Code (Copilot agent mode) supports remote HTTP MCP servers with OAuth or headers. ## Install link Open [Install FreshlyCited in VS Code](vscode:mcp/install?%7B%22name%22%3A%22freshlycited%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Ffreshlycited.com%2Fmcp%22%7D) or run: ```bash code --add-mcp '{"name":"freshlycited","type":"http","url":"https://freshlycited.com/mcp"}' ``` VS Code asks you to sign in with OAuth the first time the server starts. ## .vscode/mcp.json (OAuth) ```json { "servers": { "freshlycited": { "type": "http", "url": "https://freshlycited.com/mcp" } } } ``` ## .vscode/mcp.json with a prompted API key VS Code prompts for the key once and stores it securely, so it never lands in the file: ```json { "inputs": [ { "type": "promptString", "id": "freshlycited-key", "description": "FreshlyCited API key", "password": true } ], "servers": { "freshlycited": { "type": "http", "url": "https://freshlycited.com/mcp", "headers": { "Authorization": "Bearer ${input:freshlycited-key}" } } } } ``` API keys are created under **API keys** in the FreshlyCited app and shown once. A key only sees its own workspace and the clients under it, with the key's role. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/vscode --- # Connect Windsurf to FreshlyCited MCP Windsurf (now part of Devin Desktop) reads remote MCP servers from its `mcp_config.json`. Open Windsurf's MCP settings to find and edit the file, then add: ```json { "mcpServers": { "freshlycited": { "serverUrl": "https://freshlycited.com/mcp", "headers": { "Authorization": "Bearer ${env:FRESHLYCITED_API_KEY}" } } } } ``` Set the variable before starting Windsurf: ```bash export FRESHLYCITED_API_KEY=ipk_YOUR_KEY ``` Windsurf also supports OAuth for remote servers: leave out `headers` and it opens the FreshlyCited consent screen when the server first connects. API keys are created under **API keys** in the FreshlyCited app and shown once. A key only sees its own workspace and the clients under it, with the key's role. ## Check it works Ask: *"Call FreshlyCited's get_started tool."* You should see your workspace, role and credit balance. If the client says it can't connect, see [Authentication](https://freshlycited.com/docs/authentication) for what each error means. --- Source: https://freshlycited.com/docs/clients/windsurf --- # Authentication: API keys and OAuth 2.1 FreshlyCited accepts two kinds of credentials. Use an **API key** for scripts, CI and MCP clients where you can set a header. Use **OAuth** for connectors like Claude.ai and ChatGPT, where you sign in instead of pasting a secret. | | API key | OAuth 2.1 | | --- | --- | --- | | Best for | Scripts, REST, Claude Code, Cursor, VS Code | Claude.ai, ChatGPT, Claude Desktop connectors, any MCP client that supports OAuth | | Works on | REST API and MCP | MCP only (`/mcp`) | | Acts as | The key (its workspace and role) | You, in the workspace you pick on the consent screen | | Lifetime | Until revoked | Access token 1 hour, refresh token 30 days (rotated) | | Revoke | **API keys** page | **API keys › Connected apps**, or `/oauth/revoke` | ## API keys Create a key under **API keys** in the app (admins and owners). The secret starts with `ipk_` and is shown once. Send it as a bearer token: ```bash curl https://freshlycited.com/api/v1/me -H "Authorization: Bearer ipk_YOUR_KEY" ``` `X-Api-Key: ipk_…` works too. A key belongs to one workspace (your agency or a client) and sees only that workspace and the clients under it. Its role decides what it can do: `client_viewer` keys are read-only. Each key can have its own [rate limits and daily credit cap](https://freshlycited.com/docs/rate-limits). ## OAuth 2.1 for connectors FreshlyCited implements the MCP authorization spec, so compliant clients discover everything from the server URL: 1. The client calls `https://freshlycited.com/mcp` without a token and gets **401** with `WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp", scope="mcp"`. 2. It reads the [protected resource metadata](https://freshlycited.com/.well-known/oauth-protected-resource/mcp) (RFC 9728), which names FreshlyCited as the authorization server. 3. It reads the [authorization server metadata](https://freshlycited.com/.well-known/oauth-authorization-server) (RFC 8414). 4. It identifies itself with a **Client ID Metadata Document** (an https `client_id` URL) or registers through **dynamic client registration** at `/oauth/register` (RFC 7591). 5. It sends you to `/oauth/authorize` with **PKCE S256** and `resource=https://freshlycited.com/mcp` (RFC 8707). 6. You sign in with your normal FreshlyCited login and see the consent screen: pick the **workspace** and the **access level**. 7. The client exchanges the code at `/oauth/token` and calls the MCP server with `Authorization: Bearer fca_…`. ### Scopes | Scope | Access | | --- | --- | | `mcp` | Full access with your role in the chosen workspace: push links, run checks (spends credits), manage clients if your role allows | | `mcp:read` | Read-only: pushes, checks, results, credits and reports. Tools that change anything return 403 | ### Tokens - Access tokens (`fca_…`) last **1 hour** and only work on `/mcp`; they're bound to that resource and rejected by the REST API. - Refresh tokens (`fcr_…`) last **30 days** and rotate on every use. If an old refresh token is used again, the whole connection is revoked for safety. - The authorization response includes `iss` (RFC 9207). Redirect URIs must match exactly, except loopback URIs (`http://127.0.0.1` / `localhost`), where the port may differ. - Revoke with `POST /oauth/revoke` (RFC 7009), or disconnect the app under **API keys › Connected apps**. Removing you from the workspace also cuts the connection off. ## Errors | Status | Meaning | | --- | --- | | 401 | No credentials, an unknown or revoked key, or an expired access token. MCP responses include `WWW-Authenticate` so OAuth clients can sign in again. | | 403 | Your role (or a read-only connection) doesn't allow this, or the account is waiting for approval | | 429 | [Rate limit](https://freshlycited.com/docs/rate-limits) reached: wait for `Retry-After` seconds | --- Source: https://freshlycited.com/docs/authentication --- # Rate limits, 429s and credit guards Limits keep one runaway agent from draining your credits or the service. They apply per **API key** and per **OAuth connection**, and depend on your plan; using the app in your browser isn't metered. ## Limits by plan | Surface | Free | Agency plans | Resets | | --- | --- | --- | --- | | REST API | 60 requests an hour, **read-only** (GET) | 600 requests a minute | when the window ends | | MCP (AI assistants) | not included | 60 calls a minute per key (Agency Pro and Scale) | 60 seconds after the first call | On Free, requests that change something (POST, PATCH, PUT, DELETE) return **403** with an upgrade hint; use the app instead. Admins can lower a key's per-minute rate (`rate_per_min`) and give it a daily cap (`rate_per_day`, resets 00:00 UTC) under **API keys**, or with `update_api_key`. REST and MCP are counted separately. ## What counts - Every REST request and every MCP HTTP request counts **1**. - MCP tools that spend credits (`submit_index_job`, `check_index`, `retry_job`, `send_unindexed_to_indexer`) weigh **5** in total. ## When you hit a limit The response is **429** with a `Retry-After` header (seconds). REST errors include `error.retry_after` and `error.details` (`code: "rate_limited"`, the plan and the limit); MCP returns a JSON-RPC error. Successful API-key responses carry `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `X-RateLimit-Window` (minute or hour). ```http HTTP/1.1 429 Too Many Requests Retry-After: 23 RateLimit-Limit: 60 RateLimit-Remaining: 0 ``` Agents should wait `Retry-After` seconds and retry once, not loop. ## Plan limits (403 / 429 with an upgrade hint) Features that aren't on your plan return **403** with `error.details.code = "plan_required"` and `required_plan`; limits you're over return **429** with `error.details.code = "plan_limit"`. Both carry the `feature` (for example `max_urls_per_job`, `workspaces`, `seats`, `live_checks`, `mcp`, `concurrent_jobs`) and an `upgrade_url`. Free allows 50 URLs per push or check and 3 running at a time. ## Credit guards - **Two kinds of credits:** index credits (1 per URL pushed, charged only if it gets indexed; the credit comes back automatically if it isn't indexed after 7 days) and check credits (1 per Standard check, 5 per Live check). Not enough of either returns **402** with `error.details.kind`. - **Confirmation:** an MCP call that would spend more than 1,000 credits returns `needs_confirmation` with the estimate instead of running. Ask the user, then call again with `confirm_spend: true`. - **Daily credit cap per key:** set `daily_credit_cap` on a key and calls that would take it over the cap for the UTC day return 429 with a plain explanation. - **Hard limits:** 10,000 URLs per job on paid plans; a job never spends more credits than your balance (402 otherwise). --- Source: https://freshlycited.com/docs/rate-limits --- # Bing & Copilot via IndexNow: verify your site **IndexNow** is an open protocol for telling search engines "this page changed". One notice is shared between the participating engines: **Bing** (which also powers Copilot and Bing's AI answers), **Yandex**, **Seznam**, **Naver** and **Yep**. FreshlyCited sends IndexNow notices for your verified sites on every push, **free**, alongside the Google push. > IndexNow doesn't reach Google, and it isn't a channel into ChatGPT or Perplexity. It tells the participating engines a URL changed so they can recrawl it sooner; they still decide what to index. ## How it works 1. **Add your site** (Bing & Copilot page in the app, `add_indexnow_site`, or `POST /api/v1/indexnow/sites`). Add each exact hostname you use: `example.com` and `www.example.com` are different sites to IndexNow. 2. **Publish the key file.** FreshlyCited generates a key. Put a plain-text file containing only the key at `https:///.txt`. If you can't write to the root, set a **key location** such as `https://example.com/seo/.txt`; it then only covers URLs under `/seo/`. 3. **Verify.** FreshlyCited fetches the file and checks it contains exactly the key. The check is safe by design: only public http(s) addresses, a few seconds and a few kilobytes at most, and redirects must stay on your host. 4. **Push as usual.** URLs on a verified, switched-on site go to IndexNow (`api.indexnow.org`) in the same push, up to 10,000 per request and one host per request. ## What we send, and when - Only URLs whose host matches one of **your verified sites**. Backlinks on other people's sites are never sent to IndexNow (they go to Google only). - **Changed content only:** a URL sent to IndexNow in the last 24 hours isn't resent, unless you explicitly push it again (**Push again**, `retry_job`, `send_unindexed_to_indexer`, or `indexnow_force: true`). - Each link records its IndexNow result in the push: **Sent to Bing (IndexNow): received** (`accepted`, HTTP 200), **received, key pending** (`submitted`, HTTP 202: the engines are still validating your key), **error** with the HTTP code (403 key not valid, 422 URL doesn't match the host, 429 too many requests) or **sent in the last 24 h**. "Received" means IndexNow accepted the notice, not that Bing indexed the page. - The push outcome says it plainly, for example "3 links also sent to Bing (IndexNow)". Use `get_job_indexnow` or `GET /api/v1/jobs/{id}/indexnow` for per-link detail. ## Staying verified FreshlyCited re-checks every verified site daily. If the key file is missing twice in a row (an hour apart), the site is **paused**: IndexNow notices stop, you get an email and a notice on the site, and nothing else changes until you verify again. You can also switch a site off at any time, or rotate its key. ## Seen by Bing? A notice isn't proof of indexing. FreshlyCited has an optional Bing search check (`engine: "scan_bing"`) that platform admins can switch on under Settings › Integrations; it is **off by default** because Bing search results proved unreliable for per-URL checks, and `check_index` with `engine: "scan_bing"` returns 409 while it's off. When it's on, it only confirms positives: a match shows **Seen by Bing** (1 credit); a miss shows **Not confirmed by Bing** and is refunded, because not finding a URL in Bing's results doesn't prove it isn't indexed. A reliable per-URL Bing index status would need Bing Webmaster Tools' URL inspection, which requires each site to be verified in Bing Webmaster Tools. That's on our roadmap. ## API at a glance | Action | MCP tool | REST | | --- | --- | --- | | List sites | `list_indexnow_sites` | `GET /api/v1/indexnow/sites` | | Add a site | `add_indexnow_site` | `POST /api/v1/indexnow/sites` | | Verify | `verify_indexnow_site` | `POST /api/v1/indexnow/sites/{id}/verify` | | Switch on/off, move key file | `update_indexnow_site` | `PATCH /api/v1/indexnow/sites/{id}` | | Remove | `delete_indexnow_site` | `DELETE /api/v1/indexnow/sites/{id}` | | What a push sent | `get_job_indexnow` | `GET /api/v1/jobs/{id}/indexnow` | Step-by-step: [Verify your site for IndexNow](https://freshlycited.com/docs/recipes/verify-site-indexnow). --- Source: https://freshlycited.com/docs/indexnow --- # MCP tool reference The FreshlyCited MCP server at `https://freshlycited.com/mcp` exposes **49 tools**. This page is generated from the server's own tool definitions, so it always matches what your client sees in `tools/list`. API names stay technical: a *push* is an index job, a *visibility check* is an index check. Every tool works with the permissions of the API key or OAuth connection: tools above your role are listed but return 403. Read-only connections (scope `mcp:read`) can only call read-only tools. Each call counts against your [rate limits](https://freshlycited.com/docs/rate-limits) (60 calls a minute per key; MCP is included on Agency Pro and Scale); tools that spend credits weigh 5 units and ask for `confirm_spend: true` above 1,000 credits. | Tool | What it does | | --- | --- | | [`get_started`](https://freshlycited.com/docs/tools#get_started) | Get started | | [`whoami`](https://freshlycited.com/docs/tools#whoami) | Who am I | | [`get_pricing`](https://freshlycited.com/docs/tools#get_pricing) | Pricing and limits | | [`validate_urls`](https://freshlycited.com/docs/tools#validate_urls) | Validate URLs | | [`preflight_urls`](https://freshlycited.com/docs/tools#preflight_urls) | Pre-flight URLs before pushing | | [`submit_index_job`](https://freshlycited.com/docs/tools#submit_index_job) | Push links to Google (index job) | | [`get_job_status`](https://freshlycited.com/docs/tools#get_job_status) | Get push or check | | [`list_jobs`](https://freshlycited.com/docs/tools#list_jobs) | List pushes and checks | | [`list_job_urls`](https://freshlycited.com/docs/tools#list_job_urls) | List a job's links | | [`update_job`](https://freshlycited.com/docs/tools#update_job) | Rename a job | | [`cancel_job`](https://freshlycited.com/docs/tools#cancel_job) | Cancel a job | | [`retry_job`](https://freshlycited.com/docs/tools#retry_job) | Push failed links again | | [`send_unindexed_to_indexer`](https://freshlycited.com/docs/tools#send_unindexed_to_indexer) | Push the invisible links again | | [`delete_job`](https://freshlycited.com/docs/tools#delete_job) | Delete a job | | [`delete_job_url`](https://freshlycited.com/docs/tools#delete_job_url) | Remove one link | | [`check_index`](https://freshlycited.com/docs/tools#check_index) | Visibility check (index check) | | [`get_check_results`](https://freshlycited.com/docs/tools#get_check_results) | Stored search results | | [`share_job_report`](https://freshlycited.com/docs/tools#share_job_report) | Share a client report | | [`export_job_csv`](https://freshlycited.com/docs/tools#export_job_csv) | Export CSV | | [`list_indexnow_sites`](https://freshlycited.com/docs/tools#list_indexnow_sites) | List IndexNow sites | | [`add_indexnow_site`](https://freshlycited.com/docs/tools#add_indexnow_site) | Add a site for IndexNow | | [`verify_indexnow_site`](https://freshlycited.com/docs/tools#verify_indexnow_site) | Verify an IndexNow site | | [`update_indexnow_site`](https://freshlycited.com/docs/tools#update_indexnow_site) | Turn a site on/off or move its key file | | [`delete_indexnow_site`](https://freshlycited.com/docs/tools#delete_indexnow_site) | Remove an IndexNow site | | [`get_job_indexnow`](https://freshlycited.com/docs/tools#get_job_indexnow) | IndexNow status of a push | | [`list_tenants`](https://freshlycited.com/docs/tools#list_tenants) | List workspaces | | [`list_sub_tenants`](https://freshlycited.com/docs/tools#list_sub_tenants) | List direct sub-workspaces | | [`get_tenant`](https://freshlycited.com/docs/tools#get_tenant) | Get a workspace | | [`create_sub_tenant`](https://freshlycited.com/docs/tools#create_sub_tenant) | Create a client workspace | | [`update_tenant`](https://freshlycited.com/docs/tools#update_tenant) | Update a workspace | | [`delete_tenant`](https://freshlycited.com/docs/tools#delete_tenant) | Delete or archive a workspace | | [`list_members`](https://freshlycited.com/docs/tools#list_members) | List members | | [`add_member`](https://freshlycited.com/docs/tools#add_member) | Add a member | | [`update_member_role`](https://freshlycited.com/docs/tools#update_member_role) | Change a member's role | | [`remove_member`](https://freshlycited.com/docs/tools#remove_member) | Remove a member | | [`get_credits`](https://freshlycited.com/docs/tools#get_credits) | Credit balance | | [`list_ledger`](https://freshlycited.com/docs/tools#list_ledger) | Credit ledger | | [`allocate_credits`](https://freshlycited.com/docs/tools#allocate_credits) | Give credits to a client | | [`reverse_ledger_entry`](https://freshlycited.com/docs/tools#reverse_ledger_entry) | Reverse a transfer | | [`list_api_keys`](https://freshlycited.com/docs/tools#list_api_keys) | List API keys | | [`create_api_key`](https://freshlycited.com/docs/tools#create_api_key) | Create an API key | | [`update_api_key`](https://freshlycited.com/docs/tools#update_api_key) | Update an API key | | [`revoke_api_key`](https://freshlycited.com/docs/tools#revoke_api_key) | Revoke an API key | | [`delete_api_key`](https://freshlycited.com/docs/tools#delete_api_key) | Delete an API key | | [`list_users`](https://freshlycited.com/docs/tools#list_users) | List users | | [`get_user`](https://freshlycited.com/docs/tools#get_user) | Get a user | | [`list_errors`](https://freshlycited.com/docs/tools#list_errors) | List tracked errors | | [`resolve_error`](https://freshlycited.com/docs/tools#resolve_error) | Resolve an error | | [`list_audit_log`](https://freshlycited.com/docs/tools#list_audit_log) | Audit log | ## Getting started Who you are, what things cost, what to do next. ### `get_started` **Get started.** Start here. Returns who you are (role, workspace, plan, index and check credit balances), what you've done so far, rate limits, pricing and the next steps that fit this account (first check, smart push, IndexNow setup, sharing a report), with links to the docs. > Role: any role · read-only · rate weight 1 · idempotent No parameters. First call in a new session: ```json { "name": "get_started", "arguments": {} } ``` ### `whoami` **Who am I.** Identity behind this key or connection: kind (user/apikey), id, workspace (tenantId), role, plan rate limits and, for OAuth connections, the app and scope. > Role: any role · read-only · rate weight 1 · idempotent No parameters. Identity: ```json { "name": "whoami", "arguments": {} } ``` ### `get_pricing` **Pricing and limits.** Prices and limits. Two credit kinds: index credits (1 per URL pushed, reserved at submission, used only if Google indexes it; not indexed after 7 days → the credit comes back automatically; re-checks on day 1, 3, 7 are free) and check credits (1 per Standard check, 5 per Live check). IndexNow (Bing) submissions are free. Returns pricing (credits per action: { index, priority, check, liveCheck }; the priority lane is not sold yet), the packs and plans in USD, the guarantee rules, URLs per job (Free 50, paid 10,000) and API rate limits. > Role: any role · read-only · rate weight 1 · idempotent No parameters. Pricing: ```json { "name": "get_pricing", "arguments": {} } ``` ## Pushes (index jobs) Send links to Google (and to Bing via IndexNow for verified sites), track them, push again. ### `validate_urls` **Validate URLs.** Validate and de-duplicate a URL list without spending credits. Returns how many are accepted, invalid and duplicated, with up to 10 invalid samples. Use before submit_index_job or check_index when the list came from a user paste or a file. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | URLs to validate | Clean a pasted list: ```json { "name": "validate_urls", "arguments": { "urls": [ "https://example.com/blog/new-post", "https://example.com/pricing", "example.com/no-scheme", "https://example.com/blog/new-post" ] } } ``` ### `preflight_urls` **Pre-flight URLs before pushing.** Free pre-flight for up to 1,000 URLs: fetches each page (as a crawler would) and flags ones Google can't index at that address: HTTP 4xx/5xx or unreachable, noindex (meta or X-Robots-Tag), blocked by robots.txt for Googlebot, redirects, canonical pointing elsewhere. submit_index_job skips flagged URLs for free by default (push_anyway overrides; then their credit is used). Results are cached for 6 hours, so a push right after reuses them. > Role: member or higher · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | Check a list before pushing: ```json { "name": "preflight_urls", "arguments": { "urls": [ "https://example.com/blog/new-post", "https://example.com/pricing" ] } } ``` ### `submit_index_job` **Push links to Google (index job).** Push up to 10,000 URLs so Google crawls them (an "index job"). Each URL reserves 1 index credit, used only if Google indexes it: FreshlyCited re-checks on day 1, 3, 7 (free) and gives the credit back automatically if the link still isn't indexed after day 7. Not covered (credit used): pages that return 404/410/5xx, are noindex, blocked by robots.txt, redirect, have a canonical pointing elsewhere, or that you remove. A free pre-flight runs first and skips flagged URLs (see preflight_urls; response field preflight). Recommended: smart=true checks every URL first (1 check credit/URL) and only pushes the ones Google doesn't show yet; their reserved index credit comes straight back. drip_days spreads the push over 1-30 days. URLs on a site you verified for IndexNow are ALSO sent to Bing and the other IndexNow engines for free (not to Google, ChatGPT or Perplexity); a URL sent to IndexNow in the last 24 h isn't resent unless indexnow_force=true. Returns the job with an outcome headline, credits { index: { reserved, consumed, released, excluded } } and the guarantee's next re-check. Spends credits: calls above the confirmation threshold need confirm_spend=true. > Role: member or higher · writes · spends credits (rate weight 5) | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | Full http(s) URLs, up to 10,000 (Free plan: 50). Duplicates and invalid entries are dropped and reported. | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `name` | string (≤200 chars) | no | Label shown in lists, emails and client reports | | `drip_days` | integer (≥0, ≤30) | no | Spread the push over this many days (0 = all now) | | `recheck_days` | integer (≥0, ≤5) | no | Deprecated, kept for compatibility: re-checks now follow the guarantee schedule (day 1, 3, 7) automatically | | `pre_check` | boolean | no | Take a 'before' snapshot first (1 check credit/URL); every link is still pushed | | `smart` | boolean | no | Recommended: check first and only push what Google can't see (their index credit comes back) | | `preflight` | boolean | no | Run the free pre-flight (default true) | | `skip_flagged` | boolean | no | Skip URLs the pre-flight flags, for free (default true) | | `push_anyway` | boolean \| array of string | no | Push flagged URLs anyway (true = all, or a list). They aren't covered by the guarantee: their index credit is used | | `force_refresh` | boolean | no | Refresh anyway (needs smart=true): links Google already has are sent too and use 1 index credit each when sent. No credit back: we can't see when Google re-crawls a page it already has, so the guarantee doesn't apply. IndexNow pings stay free | | `indexnow_force` | boolean | no | Resend to IndexNow even if sent in the last 24 h (only when the content changed again) | | `confirm_spend` | boolean | no | Set true to confirm a call that spends more than the confirmation threshold (default 1,000 credits). Ask the user first. | Smart push: ```json { "name": "submit_index_job", "arguments": { "urls": [ "https://example.com/blog/new-post", "https://example.com/pricing" ], "smart": true, "name": "October posts" } } ``` Drip 500 backlinks over 7 days: ```json { "name": "submit_index_job", "arguments": { "urls": [ "https://guest-blog.example.net/post-about-you" ], "drip_days": 7 } } ``` ### `get_job_status` **Get push or check.** Full status of one push or visibility check: outcome headline (e.g. '11 of 12 links seen by Google (+2)'), stage, drip progress, before/after comparison, credits (index: reserved / consumed / released / excluded; check credits used), the guarantee's next re-check, pre-flight counts, ledger lines, IndexNow (Bing) summary and the first URLs (each with credit_state). sync=true refreshes crawl status from the network first (cheap, no credits). > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | Job id (job_…) | | `url_limit` | integer (≥0, ≤1000) | no | How many URLs to include (default 50) | | `sync` | boolean | no | Refresh status from the crawl network first | Status with 10 URLs: ```json { "name": "get_job_status", "arguments": { "job_id": "job_0123456789abcdef", "url_limit": 10 } } ``` ### `list_jobs` **List pushes and checks.** List pushes (type=index) and visibility checks (type=check) in scope, newest first, each with its outcome and index credits reserved / consumed / released. Paginated: returns { items, total, page, page_size }. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `status` | string | no | Filter: checking, submitting, dripping, queued, processing, approval_pending, completed, partial, failed, cancelled | | `type` | `index` \| `check` | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | Last 10 pushes: ```json { "name": "list_jobs", "arguments": { "type": "index", "page_size": 10 } } ``` ### `list_job_urls` **List a job's links.** List the links of one push or check with filters: state (pending, queued, completed, failed, skipped, …), indexed (yes = seen by Google, no = invisible, unknown = not checked) and credit (reserved, consumed, released, excluded). Each row includes the latest Google position/title, the guarantee fields (credit_state, sent_at, next_recheck_at, recheck_n, excluded_reason), the pre-flight flag, the IndexNow state and the Bing check result. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `state` | string | no | | | `indexed` | `yes` \| `no` \| `unknown` | no | | | `credit` | `reserved` \| `consumed` \| `released` \| `excluded` | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | Links Google still can't see: ```json { "name": "list_job_urls", "arguments": { "job_id": "job_0123456789abcdef", "indexed": "no" } } ``` Credits returned: ```json { "name": "list_job_urls", "arguments": { "job_id": "job_0123456789abcdef", "credit": "released" } } ``` ### `update_job` **Rename a job.** Rename a push or check. (recheck_days is accepted for compatibility; guarantee re-checks on day 1, 3 and 7 are automatic.) > Role: member or higher · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `name` | string (≤200 chars) | no | | | `recheck_days` | integer (≥0, ≤5) | no | | Rename: ```json { "name": "update_job", "arguments": { "job_id": "job_0123456789abcdef", "name": "October citations" } } ``` ### `cancel_job` **Cancel a job.** Cancel a running or dripping push/check. Links not sent yet get their index credit back; links already pushed can't be recalled and keep their 7-day guarantee. > Role: member or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | Cancel: ```json { "name": "cancel_job", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ### `retry_job` **Push failed links again.** Re-push a job's failed or cancelled links as a new push (1 index credit reserved per link, same guarantee). Counts as an explicit re-push for IndexNow. > Role: member or higher · writes · spends credits (rate weight 5) | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | | `confirm_spend` | boolean | no | Set true to confirm a call that spends more than the confirmation threshold (default 1,000 credits). Ask the user first. | Retry: ```json { "name": "retry_job", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ### `send_unindexed_to_indexer` **Push the invisible links again.** One step: start a new push with only the links Google can't see in this job's latest check (indexed=no). 1 index credit reserved per link, same guarantee. The latest check becomes the 'before' for the visibility lift. Counts as an explicit re-push for IndexNow. > Role: member or higher · writes · spends credits (rate weight 5) | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | | `drip_days` | integer (≥0, ≤30) | no | | | `recheck_days` | integer (≥0, ≤5) | no | Deprecated: guarantee re-checks are automatic | | `confirm_spend` | boolean | no | Set true to confirm a call that spends more than the confirmation threshold (default 1,000 credits). Ask the user first. | Push again: ```json { "name": "send_unindexed_to_indexer", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ### `delete_job` **Delete a job.** Permanently delete a finished or cancelled push/check, its link results and any shared report link. Credits are not refunded; links still inside their 7-day guarantee count as removed by you (credit used). > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | Delete: ```json { "name": "delete_job", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ### `delete_job_url` **Remove one link.** Remove one link (by its numeric url id from list_job_urls) from a finished job. A link still inside its guarantee counts as removed by you (credit used). > Role: member or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `url_id` | integer (≥-9007199254740991, ≤9007199254740991) | yes | | Remove: ```json { "name": "delete_job_url", "arguments": { "job_id": "job_0123456789abcdef", "url_id": 42 } } ``` ## Visibility checks (index checks) Ask Google (and Bing) whether links are indexed, and read the stored results. ### `check_index` **Visibility check (index check).** Check whether URLs are indexed (1 check credit/URL with Pilot Scan: Standard, 5 with Live; up to 10,000, Free plan 50). Pass urls to create a new check, or job_id to re-check an existing push/check (manual re-checks are charged; the guarantee's own re-checks are free). engine: scan_standard (default queue, may take minutes; poll get_job_status), scan_live (seconds; monthly Live quota on Agency plans), scan_bing (positive-only "Seen by Bing" for an existing job: confirms links Bing shows, misses are returned and read "not confirmed"; off unless the platform enabled it). A check that finds a pushed link indexed uses its reserved index credit. Returns the job; results land on each link as indexed / bing_indexed. > Role: member or higher · writes · spends credits (rate weight 5) | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | no | | | `job_id` | string | no | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `name` | string (≤200 chars) | no | | | `engine` | `scan_standard` \| `scan_live` \| `scan_bing` \| `upstream` | no | | | `confirm_spend` | boolean | no | Set true to confirm a call that spends more than the confirmation threshold (default 1,000 credits). Ask the user first. | Check two pages: ```json { "name": "check_index", "arguments": { "urls": [ "https://example.com/blog/new-post", "https://example.com/pricing" ] } } ``` Is a push in Bing yet?: ```json { "name": "check_index", "arguments": { "job_id": "job_0123456789abcdef", "engine": "scan_bing" } } ``` ### `get_check_results` **Stored search results.** Stored search data for a job's links: indexed, position, title, snippet, displayed URL, SERP features, match type, query, total results and the engine (Google or Bing). Pass url for one link's full history. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `url` | string | no | | All results: ```json { "name": "get_check_results", "arguments": { "job_id": "job_0123456789abcdef" } } ``` One link's history: ```json { "name": "get_check_results", "arguments": { "job_id": "job_0123456789abcdef", "url": "https://example.com/blog/new-post" } } ``` ### `share_job_report` **Share a client report.** Create (or return the existing) read-only client report link for a job: before/after visibility, per-link status, no login needed. Your branding on Agency plans; FreshlyCited-branded on Free. revoke=true stops sharing. > Role: member or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | | `revoke` | boolean | no | | Share: ```json { "name": "share_job_report", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ### `export_job_csv` **Export CSV.** Export a job's links with submission state, before/after index status, index credit state and the latest search data as CSV text ({ filename, csv }). > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | Export: ```json { "name": "export_job_csv", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ## Bing & Copilot (IndexNow) Verify your sites for IndexNow so pushes also notify Bing and the other IndexNow engines. Free. ### `list_indexnow_sites` **List IndexNow sites.** List the sites (hosts) registered for IndexNow in scope, with verification state, the key, where the key file must be hosted (key_file_url) and how many links went to IndexNow in the last 30 days. A site pings IndexNow only when verified=true and enabled=true (active). > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | All sites: ```json { "name": "list_indexnow_sites", "arguments": {} } ``` ### `add_indexnow_site` **Add a site for IndexNow.** Register a host (e.g. example.com or www.example.com; one entry per exact hostname) for IndexNow. Returns a generated key and key_file_url: the site owner must publish a plain-text file at that URL containing only the key (or set key_location to a .txt file elsewhere on the same host; it then only covers URLs under that folder). Then call verify_indexnow_site. Free. > Role: admin or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `host` | string | yes | Domain or any URL on it, e.g. https://www.example.com/blog | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `key_location` | string | no | Optional full URL of the key file on the same host, e.g. https://example.com/keys/indexnow.txt | Add a domain: ```json { "name": "add_indexnow_site", "arguments": { "host": "www.example.com" } } ``` ### `verify_indexnow_site` **Verify an IndexNow site.** Fetch the site's key file now and mark the site verified if it contains exactly the key. Returns verification { ok, url, detail } in plain language (e.g. 'The key file isn't there yet (HTTP 404 …)'). Verified sites are re-checked daily; two failures in a row pause pings with a notice. > Role: member or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `site_id` | string | yes | | Verify: ```json { "name": "verify_indexnow_site", "arguments": { "site_id": "site_0123456789abcdef" } } ``` ### `update_indexnow_site` **Turn a site on/off or move its key file.** Switch IndexNow pings for a site on or off (enabled), or change key_location (null = the root /.txt). Changing the key location requires verifying again. > Role: admin or higher · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `site_id` | string | yes | | | `enabled` | boolean | no | | | `key_location` | string \| null | no | | Pause pings: ```json { "name": "update_indexnow_site", "arguments": { "site_id": "site_0123456789abcdef", "enabled": false } } ``` ### `delete_indexnow_site` **Remove an IndexNow site.** Remove a site from IndexNow. Pushes stop notifying IndexNow for that host; past submission records stay on the jobs. > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `site_id` | string | yes | | Remove: ```json { "name": "delete_indexnow_site", "arguments": { "site_id": "site_0123456789abcdef" } } ``` ### `get_job_indexnow` **IndexNow status of a push.** What a push sent to IndexNow: summary { sent, accepted (HTTP 200), pending (HTTP 202, key still being validated), errors, skipped_recent (sent < 24 h ago, not resent), bing_seen, bing_not, hosts, http_codes } and per-link rows (indexnow_state, indexnow_http, indexnow_at, bing_indexed). Links on hosts that aren't verified are never sent to IndexNow. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | yes | | Status: ```json { "name": "get_job_indexnow", "arguments": { "job_id": "job_0123456789abcdef" } } ``` ## Clients & members Your agency, client workspaces and who can access them. ### `list_tenants` **List workspaces.** List your workspace and every client/team under it in tree order (depth, path) with credits, member and job counts. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `q` | string | no | | | `kind` | `agency` \| `team` \| `client` | no | | | `include_archived` | boolean | no | | Clients only: ```json { "name": "list_tenants", "arguments": { "kind": "client" } } ``` ### `list_sub_tenants` **List direct sub-workspaces.** List the direct children of one workspace. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `parent_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | Children of mine: ```json { "name": "list_sub_tenants", "arguments": {} } ``` ### `get_tenant` **Get a workspace.** One workspace with credits, counts, parent and whether it's your root. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | Get: ```json { "name": "get_tenant", "arguments": { "tenant_id": "ten_0123456789abcdef" } } ``` ### `create_sub_tenant` **Create a client workspace.** Create a client (default) or team workspace under yours (or under parent_id). It starts with 0 credits: use allocate_credits. > Role: admin or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string (≤120 chars) | yes | | | `kind` | `team` \| `client` | no | | | `parent_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `notes` | string | no | | New client: ```json { "name": "create_sub_tenant", "arguments": { "name": "", "kind": "client" } } ``` ### `update_tenant` **Update a workspace.** Rename, change kind or notes, set the default re-check days (0-5), move under another parent, or archive/restore a workspace. > Role: admin or higher · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `name` | string | no | | | `kind` | `team` \| `client` | no | | | `notes` | string | no | | | `default_recheck_days` | integer (≥0, ≤5) | no | | | `parent_id` | string | no | | | `archived` | boolean | no | | Default re-check 3 days: ```json { "name": "update_tenant", "arguments": { "tenant_id": "ten_0123456789abcdef", "default_recheck_days": 3 } } ``` ### `delete_tenant` **Delete or archive a workspace.** Delete an EMPTY workspace (confirm must equal its exact name) or archive it (mode=archive). Workspaces with jobs, credits or children can only be archived. > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `confirm` | string | no | | | `mode` | `delete` \| `archive` | no | | Archive: ```json { "name": "delete_tenant", "arguments": { "tenant_id": "ten_0123456789abcdef", "mode": "archive" } } ``` ### `list_members` **List members.** People with access to a workspace and their roles. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | Members: ```json { "name": "list_members", "arguments": {} } ``` ### `add_member` **Add a member.** Give a person access to a workspace with a role (owner, admin, member, client_viewer = read-only). Creates and invites the account if the email is new. > Role: admin or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | yes | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | yes | | | `name` | string | no | | Read-only client login: ```json { "name": "add_member", "arguments": { "email": "client@acme.example", "tenant_id": "ten_0123456789abcdef", "role": "client_viewer" } } ``` ### `update_member_role` **Change a member's role.** Change a member's role (never above your own). > Role: admin or higher · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `user_id` | string | yes | | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | yes | | Make admin: ```json { "name": "update_member_role", "arguments": { "tenant_id": "ten_0123456789abcdef", "user_id": "usr_0123456789abcdef", "role": "admin" } } ``` ### `remove_member` **Remove a member.** Remove a person's access to a workspace (the last owner can't be removed). > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `user_id` | string | yes | | Remove: ```json { "name": "remove_member", "arguments": { "tenant_id": "ten_0123456789abcdef", "user_id": "usr_0123456789abcdef" } } ``` ## Credits Balances, the ledger and moving credits to clients. ### `get_credits` **Credit balance.** A workspace's balances { index, check, reservedIndex } (index credits reserved by pushes are waiting for the guarantee), the plan with its limits and what's used, usage this period, credits expiring in the next 30 days, pricing and the 20 most recent ledger lines. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | My balance: ```json { "name": "get_credits", "arguments": {} } ``` ### `list_ledger` **Credit ledger.** Paginated, append-only credit ledger in scope: grants (purchase, plan_grant, admin), reserve / consume / release / excluded for pushes, check usage, expiries and transfers (allocate). kind=index|check filters the credit kind; direction=in|out filters credits received or spent. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `kind` | `index` \| `check` | no | | | `direction` | `in` \| `out` | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | Check spending: ```json { "name": "list_ledger", "arguments": { "kind": "check", "direction": "out" } } ``` ### `allocate_credits` **Give credits to a client.** Move index or check credits from a parent workspace to a sub-workspace (negative amount pulls credits back). Each moved credit keeps its expiry. Platform admins may also grant to a root workspace. > Role: admin or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `amount` | integer (≥-9007199254740991, ≤9007199254740991) | yes | | | `kind` | `index` \| `check` | no | Which credits to move (default index) | | `note` | string | no | | Give 500 index credits: ```json { "name": "allocate_credits", "arguments": { "tenant_id": "ten_0123456789abcdef", "amount": 500, "kind": "index", "note": "October" } } ``` ### `reverse_ledger_entry` **Reverse a transfer.** Reverse a transfer to a client (while those credits are unspent) or a platform-admin adjustment. Push and check credits settle automatically and can't be reversed. > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `entry_id` | integer (≥-9007199254740991, ≤9007199254740991) | yes | | Reverse: ```json { "name": "reverse_ledger_entry", "arguments": { "entry_id": 1234 } } ``` ## API keys Create, limit and revoke API keys. ### `list_api_keys` **List API keys.** API keys in scope (prefix only, never the secret) with role, rate limits, last use and status. > Role: any role · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `status` | `active` \| `revoked` | no | | Active keys: ```json { "name": "list_api_keys", "arguments": { "status": "active" } } ``` ### `create_api_key` **Create an API key.** Create an API key for a workspace. The secret (ipk_…) is returned once. Optional per-key limits: rate_per_min, rate_per_day (requests) and daily_credit_cap (credits per UTC day). > Role: admin or higher · writes · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | no | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | no | | | `rate_per_min` | integer (≥1, ≤600) | no | | | `rate_per_day` | integer (≥1, ≤100000) | no | | | `daily_credit_cap` | integer (≥1, ≤9007199254740991) \| null | no | | Read-only key for a client dashboard: ```json { "name": "create_api_key", "arguments": { "name": "Looker", "role": "client_viewer", "rate_per_min": 30 } } ``` ### `update_api_key` **Update an API key.** Rename, change role or change the key's rate limits / daily credit cap (null = default). > Role: admin or higher · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `key_id` | string | yes | | | `name` | string | no | | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | no | | | `rate_per_min` | integer (≥1, ≤600) \| null | no | | | `rate_per_day` | integer (≥1, ≤100000) \| null | no | | | `daily_credit_cap` | integer (≥1, ≤9007199254740991) \| null | no | | Cap spend: ```json { "name": "update_api_key", "arguments": { "key_id": "key_0123456789abcdef", "daily_credit_cap": 2000 } } ``` ### `revoke_api_key` **Revoke an API key.** Revoke a key immediately (it stays listed for audit). A key can't revoke itself. > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `key_id` | string | yes | | Revoke: ```json { "name": "revoke_api_key", "arguments": { "key_id": "key_0123456789abcdef" } } ``` ### `delete_api_key` **Delete an API key.** Permanently delete a key. > Role: admin or higher · destructive · rate weight 1 | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `key_id` | string | yes | | Delete: ```json { "name": "delete_api_key", "arguments": { "key_id": "key_0123456789abcdef" } } ``` ## Platform admin Only for FreshlyCited platform administrators. ### `list_users` **List users.** Platform admin: list user accounts. > Role: platform admin · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `status` | `active` \| `suspended` \| `admin` | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | Suspended: ```json { "name": "list_users", "arguments": { "status": "suspended" } } ``` ### `get_user` **Get a user.** Platform admin: one user's memberships, sessions, activity and keys. > Role: platform admin · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `user_id` | string | yes | | Get: ```json { "name": "get_user", "arguments": { "user_id": "usr_0123456789abcdef" } } ``` ### `list_errors` **List tracked errors.** Platform admin: tracked server/API/MCP errors. > Role: platform admin · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `source` | string | no | | | `level` | `error` \| `warning` | no | | | `status` | `open` \| `resolved` | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | Open errors: ```json { "name": "list_errors", "arguments": { "status": "open" } } ``` ### `resolve_error` **Resolve an error.** Platform admin: mark an error resolved or open again. > Role: platform admin · writes · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `error_id` | string | yes | | | `resolved` | boolean | yes | | Resolve: ```json { "name": "resolve_error", "arguments": { "error_id": "err_0123456789abcdef", "resolved": true } } ``` ### `list_audit_log` **Audit log.** Platform admin: the audit trail. > Role: platform admin · read-only · rate weight 1 · idempotent | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `action` | string | no | | | `page` | integer (≥1, ≤9007199254740991) | no | Page number, 1-based (default 1) | | `page_size` | integer (≥1, ≤200) | no | Items per page, 1-200 (default 25) | | `q` | string | no | Free-text search | | `sort` | string | no | Sort column | | `dir` | `asc` \| `desc` | no | Sort direction (default desc) | IndexNow events: ```json { "name": "list_audit_log", "arguments": { "action": "indexnow.site_paused" } } ``` --- Source: https://freshlycited.com/docs/tools --- # REST API reference Base URL: `https://freshlycited.com/api/v1`. Authenticate with an API key: `Authorization: Bearer ipk_…` (or `X-Api-Key`). Every response is `{ "ok": true, "data": … }` or `{ "ok": false, "error": { "code", "message", "request_id" } }` and carries an `X-Request-Id` header. This page is generated from the same [OpenAPI 3.1 spec](https://freshlycited.com/openapi.json) the server publishes, which is built from the live route table. ```bash curl https://freshlycited.com/api/v1/me -H "Authorization: Bearer ipk_YOUR_KEY" ``` Errors: 401 missing/invalid key · 402 not enough credits · 403 role too low or account awaiting approval · 404 not found or outside your workspace · 409 conflict · 413 more than 10,000 URLs · 422 validation · 429 [rate limit](https://freshlycited.com/docs/rate-limits) (see `Retry-After`). Lists take `page`, `page_size` (≤200), `sort`, `dir` and return `{ items, total, page, page_size }`. ## Account Identity, profile, sessions and connected apps. ### GET `/me` Identity of the API key or session. ### GET `/mcp-tools` MCP tool catalog (names, descriptions, input schemas, examples). ### GET `/routes` Every REST route. ### GET `/pricing` Credits, packs, plans, the credit-back guarantee and rate limits (USD). ### GET `/oauth/grants` Apps connected to your login via OAuth. ### DELETE `/oauth/grants/{id}` Disconnect an app (revokes its tokens). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/profile` Your profile. ### PATCH `/profile` Update your profile. Request body (JSON): Any JSON object (see the app for fields). ### DELETE `/profile` Delete your account (confirm = your email). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `confirm` | string | yes | | ### GET `/profile/sessions` Your sign-in sessions. ### DELETE `/profile/sessions/{sid}` Sign out one session. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sid` | path | string | yes | | ## Clients Your agency workspace, client workspaces and members. ### GET `/tenants` List your workspace and its clients (tree order). MCP tool: [`list_tenants`](https://freshlycited.com/docs/tools#list_tenants). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `q` | query | string | no | | | `kind` | query | `agency` \| `team` \| `client` | no | | | `include_archived` | query | string | no | | ### POST `/tenants` Create a client or team workspace. Role admin or higher. MCP tool: [`create_sub_tenant`](https://freshlycited.com/docs/tools#create_sub_tenant). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string (≤120 chars) | yes | | | `kind` | `team` \| `client` | no | | | `parent_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `notes` | string | no | | ### GET `/tenants/{id}` Get a workspace. MCP tool: [`get_tenant`](https://freshlycited.com/docs/tools#get_tenant). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/tenants/{id}` Update, move, archive or restore a workspace. Role admin or higher. MCP tool: [`update_tenant`](https://freshlycited.com/docs/tools#update_tenant). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | no | | | `kind` | `team` \| `client` | no | | | `notes` | string | no | | | `default_recheck_days` | integer (≥0, ≤5) | no | | | `parent_id` | string | no | | | `archived` | boolean | no | | ### DELETE `/tenants/{id}` Delete an empty workspace (confirm=) or archive it (mode=archive). Role admin or higher. MCP tool: [`delete_tenant`](https://freshlycited.com/docs/tools#delete_tenant). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `confirm` | query | string | no | | | `mode` | query | `delete` \| `archive` | no | | ### GET `/tenants/{id}/members` List a workspace's members. MCP tool: [`list_members`](https://freshlycited.com/docs/tools#list_members). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/tenants/{id}/members` Add or invite a member. Role admin or higher. MCP tool: [`add_member`](https://freshlycited.com/docs/tools#add_member). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | yes | | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | yes | | | `name` | string | no | | ### PATCH `/tenants/{id}/members/{uid}` Change a member's role. Role admin or higher. MCP tool: [`update_member_role`](https://freshlycited.com/docs/tools#update_member_role). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `uid` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | yes | | ### DELETE `/tenants/{id}/members/{uid}` Remove a member. Role admin or higher. MCP tool: [`remove_member`](https://freshlycited.com/docs/tools#remove_member). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `uid` | path | string | yes | | ### GET `/members` List members (of tenant_id, default yours). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `tenant_id` | query | string | no | Limit to one workspace | ### POST `/members` Add or invite a member. Role admin or higher. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | yes | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | yes | | | `name` | string | no | | ### GET `/tenants/{id}/branding` White-label branding of a workspace and what the plan allows. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PUT `/tenants/{id}/branding` Update white-label branding (logo: Agency Starter+; colours, sender name: Agency Pro+; custom domain: Agency Scale). Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `logo_url` | string \| null | no | | | `accent` | string \| null | no | | | `from_name` | string \| null | no | | | `domain` | string \| null | no | | ## Settings Workspace and platform settings. ### GET `/settings/email` Email delivery settings. Platform admin only. ### PUT `/settings/email` Update email delivery settings. Platform admin only. Request body (JSON): Any JSON object (see the app for fields). ### POST `/settings/email/test` Send a test email. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `to` | string | no | | ### GET `/settings/email/templates` Email templates. Platform admin only. ### GET `/settings/email/templates/{name}` Preview an email template. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `name` | path | string | yes | | ### POST `/settings/email/templates/{name}/send` Send a template preview to yourself. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `name` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `to` | string | no | | ### GET `/emails` Email log. Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `status` | query | string | no | | | `template` | query | string | no | | ### GET `/emails/{id}` One logged email. Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/emails/{id}/resend` Resend a logged email. Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/tenants/{id}/notifications` Notification settings of a workspace. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/tenants/{id}/notifications` Update notification settings. Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): Any JSON object (see the app for fields). ### POST `/tenants/{id}/digest` Send the daily digest now. Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `to` | string | no | | | `skip_if_unchanged` | boolean | no | | ### GET `/tenants/{id}/digest/preview` Preview the daily digest. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/settings/integrations` Check engines, caps and spend. Platform admin only. ### PUT `/settings/integrations` Update check engines and caps. Platform admin only. Request body (JSON): Any JSON object (see the app for fields). ### POST `/settings/integrations/{source}/test` Test a check engine. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `source` | path | string | yes | | ### GET `/settings/crawl` Crawl routes: status, circuit breaker, last errors, plan and allowance. Platform admin only. ### PUT `/settings/crawl` Update crawl plan tier, cost, monthly allowance and failover thresholds. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `plan_tier` | string \| null | no | | | `cost_per_indexed_usd` | number \| null | no | | | `monthly_allowance` | integer (≥-9007199254740991, ≤9007199254740991) \| null | no | | | `fallback_cost_per_indexed_usd` | number | no | | | `failover_errors` | integer (≥-9007199254740991, ≤9007199254740991) | no | | | `failover_window_min` | integer (≥-9007199254740991, ≤9007199254740991) | no | | | `failover_cooldown_min` | integer (≥-9007199254740991, ≤9007199254740991) | no | | | `failover_allowance_pct` | number | no | | | `failover_day3_min_rate_pct` | number | no | | ### POST `/settings/crawl/breaker/reset` Close the crawl circuit breaker (route new batches to the primary again). Platform admin only. ### POST `/settings/crawl/{route}/test` Test a crawl route (free, read-only call). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `route` | path | string | yes | | ### GET `/settings/job-sync` Crawl-status sync schedule. ### PUT `/settings/job-sync` Update the crawl-status sync schedule. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `frequency` | `daily` \| `6h` \| `1h` | no | | | `time` | string | no | | | `tz` | string | no | | ### GET `/settings/access` Sign-up mode and the Free plan grant. Platform admin only. ### PUT `/settings/access` Update the sign-up mode. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `signup_mode` | `approval` \| `open` | no | | ## Credits Balances, ledger, allocations and credit packs. ### GET `/credits` Credit balance and recent ledger. MCP tool: [`get_credits`](https://freshlycited.com/docs/tools#get_credits). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `tenant_id` | query | string | no | Limit to one workspace | ### GET `/credits/ledger` Paginated credit ledger (kind=index|check). MCP tool: [`list_ledger`](https://freshlycited.com/docs/tools#list_ledger). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `tenant_id` | query | string | no | Limit to one workspace | | `kind` | query | `index` \| `check` | no | | | `direction` | query | `in` \| `out` | no | | ### GET `/credits/ledger/{id}` One ledger entry with related lines. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/credits/ledger/{id}/reverse` Reverse an allocation or grant. Role admin or higher. MCP tool: [`reverse_ledger_entry`](https://freshlycited.com/docs/tools#reverse_ledger_entry). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/credits/allocate` Give index or check credits to a client (negative pulls back). Role admin or higher. MCP tool: [`allocate_credits`](https://freshlycited.com/docs/tools#allocate_credits). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `amount` | integer (≥-9007199254740991, ≤9007199254740991) | yes | | | `kind` | `index` \| `check` | no | Which credits to move (default index) | | `note` | string | no | | ### POST `/credits/adjust` Adjust index or check credits (platform admin). Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `amount` | integer (≥-9007199254740991, ≤9007199254740991) | yes | | | `reason` | string | yes | | | `kind` | `index` \| `check` | no | | ### GET `/credits/packs` Credit packs (index + check credits, USD). ### GET `/credits/requests` Credit pack requests. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `status` | query | string | no | | ### POST `/credits/requests` Request a credit pack. Role admin or higher. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `pack` | `try` \| `boost` \| `pro` \| `checks` \| `checks_l` | yes | | | `tenant_id` | string | no | | | `note` | string | no | | ### GET `/plans` Plans and their limits (USD). ## Pushes Push links to Google (index jobs) and track them. Verified IndexNow hosts are also sent to Bing & co. ### GET `/jobs` List pushes and visibility checks, each with an outcome. MCP tool: [`list_jobs`](https://freshlycited.com/docs/tools#list_jobs). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `tenant_id` | query | string | no | Limit to one workspace | | `status` | query | string | no | | | `type` | query | `index` \| `check` | no | | ### POST `/jobs` Push links (index job): free pre-flight, 1 index credit reserved per link and used only if indexed (credit back after the last re-check); verified IndexNow hosts are also sent to Bing. Role member or higher. MCP tool: [`submit_index_job`](https://freshlycited.com/docs/tools#submit_index_job). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | Full http(s) URLs, up to 10,000 (Free plan: 50). Duplicates and invalid entries are dropped and reported. | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `name` | string (≤200 chars) | no | Label shown in lists, emails and client reports | | `drip_days` | integer (≥0, ≤30) | no | Spread the push over this many days (0 = all now) | | `recheck_days` | integer (≥0, ≤5) | no | Deprecated, kept for compatibility: re-checks now follow the guarantee schedule (day 1, 3, 7) automatically | | `pre_check` | boolean | no | Take a 'before' snapshot first (1 check credit/URL); every link is still pushed | | `smart` | boolean | no | Recommended: check first and only push what Google can't see (their index credit comes back) | | `preflight` | boolean | no | Run the free pre-flight (default true) | | `skip_flagged` | boolean | no | Skip URLs the pre-flight flags, for free (default true) | | `push_anyway` | boolean \| array of string | no | Push flagged URLs anyway (true = all, or a list). They aren't covered by the guarantee: their index credit is used | | `force_refresh` | boolean | no | Refresh anyway (needs smart=true): links Google already has are sent too and use 1 index credit each when sent. No credit back: we can't see when Google re-crawls a page it already has, so the guarantee doesn't apply. IndexNow pings stay free | | `indexnow_force` | boolean | no | Resend to IndexNow even if sent in the last 24 h (only when the content changed again) | ### POST `/urls/validate` Validate and de-duplicate URLs (free). MCP tool: [`validate_urls`](https://freshlycited.com/docs/tools#validate_urls). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string \| string | yes | | ### POST `/preflight` Pre-flight URLs before pushing (free): 4xx/5xx, noindex, robots.txt, redirects, canonical elsewhere. Role member or higher. MCP tool: [`preflight_urls`](https://freshlycited.com/docs/tools#preflight_urls). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | ### GET `/jobs/{id}` One push or check with outcome, comparison and IndexNow summary. MCP tool: [`get_job_status`](https://freshlycited.com/docs/tools#get_job_status). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `url_limit` | query | string | no | | ### PATCH `/jobs/{id}` Rename a job. Role member or higher. MCP tool: [`update_job`](https://freshlycited.com/docs/tools#update_job). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string (≤200 chars) | no | | | `recheck_days` | integer (≥0, ≤5) | no | | ### DELETE `/jobs/{id}` Delete a finished job. Role admin or higher. MCP tool: [`delete_job`](https://freshlycited.com/docs/tools#delete_job). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/jobs/{id}/sync` Refresh crawl status now. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/jobs/{id}/cancel` Cancel a job (unsent links refunded). Role member or higher. MCP tool: [`cancel_job`](https://freshlycited.com/docs/tools#cancel_job). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/jobs/{id}/retry` Push failed links again. Role member or higher. MCP tool: [`retry_job`](https://freshlycited.com/docs/tools#retry_job). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | ### POST `/jobs/{id}/send-unindexed` Push the links Google can't see again. Role member or higher. MCP tool: [`send_unindexed_to_indexer`](https://freshlycited.com/docs/tools#send_unindexed_to_indexer). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `mode` | `standard` | no | Lane. Only standard exists: 1 index credit per link, used only if the link gets indexed (credit back after 7 days if not). A faster priority lane is not available yet. | | `drip_days` | integer (≥0, ≤30) | no | | | `recheck_days` | integer (≥0, ≤5) | no | Deprecated: guarantee re-checks are automatic | ### GET `/jobs/{id}/urls` A job's links (filters: state, indexed=yes|no|unknown, credit=reserved|consumed|released|excluded). MCP tool: [`list_job_urls`](https://freshlycited.com/docs/tools#list_job_urls). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `state` | query | string | no | | | `indexed` | query | `yes` \| `no` \| `unknown` | no | | | `credit` | query | `reserved` \| `consumed` \| `released` \| `excluded` | no | | ### DELETE `/jobs/{id}/urls/{uid}` Remove one link from a finished job. Role member or higher. MCP tool: [`delete_job_url`](https://freshlycited.com/docs/tools#delete_job_url). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `uid` | path | string | yes | | ## Checks Visibility checks (index checks), stored search results, CSV exports and client reports. ### POST `/jobs/{id}/check` Re-check a job's links now (1 check credit per link, 5 with scan_live). Role member or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `url_ids` | array of integer (≥-9007199254740991, ≤9007199254740991) | no | | | `engine` | `scan_standard` \| `scan_live` \| `scan_bing` \| `upstream` | no | | ### GET `/jobs/{id}/google` Stored search results (pass url for one link's history). MCP tool: [`get_check_results`](https://freshlycited.com/docs/tools#get_check_results). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `url` | query | string | no | | ### GET `/jobs/{id}/google/raw/{rid}` Raw stored search response. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `rid` | path | string | yes | | ### GET `/jobs/{id}/csv` Export a job as CSV. MCP tool: [`export_job_csv`](https://freshlycited.com/docs/tools#export_job_csv). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/check` Visibility check (index check). Role member or higher. MCP tool: [`check_index`](https://freshlycited.com/docs/tools#check_index). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | no | | | `job_id` | string | no | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `name` | string (≤200 chars) | no | | | `engine` | `scan_standard` \| `scan_live` \| `scan_bing` \| `upstream` | no | | ### POST `/jobs/{id}/share` Create (or return) a client report link. Role member or higher. MCP tool: [`share_job_report`](https://freshlycited.com/docs/tools#share_job_report). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### DELETE `/jobs/{id}/share` Stop sharing a client report. Role member or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ## IndexNow Sites verified for IndexNow (Bing, Copilot, Yandex, Seznam, Naver, Yep) and what each push sent. ### GET `/jobs/{id}/indexnow` What a push sent to IndexNow (per link + summary). MCP tool: [`get_job_indexnow`](https://freshlycited.com/docs/tools#get_job_indexnow). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/indexnow/sites` List IndexNow sites. MCP tool: [`list_indexnow_sites`](https://freshlycited.com/docs/tools#list_indexnow_sites). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `tenant_id` | query | string | no | Limit to one workspace | ### POST `/indexnow/sites` Add a site (returns the key to host). Role admin or higher. MCP tool: [`add_indexnow_site`](https://freshlycited.com/docs/tools#add_indexnow_site). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `host` | string | yes | Domain or any URL on it, e.g. https://www.example.com/blog | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `key_location` | string | no | Optional full URL of the key file on the same host, e.g. https://example.com/keys/indexnow.txt | ### GET `/indexnow/sites/{id}` One IndexNow site with recent submissions. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/indexnow/sites/{id}` Turn pings on/off or change the key location. Role admin or higher. MCP tool: [`update_indexnow_site`](https://freshlycited.com/docs/tools#update_indexnow_site). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `enabled` | boolean | no | | | `key_location` | string \| null | no | | ### DELETE `/indexnow/sites/{id}` Remove an IndexNow site. Role admin or higher. MCP tool: [`delete_indexnow_site`](https://freshlycited.com/docs/tools#delete_indexnow_site). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/indexnow/sites/{id}/verify` Fetch the key file and verify the site. Role member or higher. MCP tool: [`verify_indexnow_site`](https://freshlycited.com/docs/tools#verify_indexnow_site). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/indexnow/sites/{id}/rotate-key` Generate a new key (verify again afterwards). Role admin or higher. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/indexnow/preview` How many of these URLs would also go to IndexNow. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `urls` | array of string | yes | | | `tenant_id` | string | no | | ### GET `/indexnow/own` Our own site's IndexNow submissions (platform admin). Platform admin only. ### POST `/indexnow/tick` Run the daily re-verification now (platform admin). Platform admin only. ## API keys API keys and their per-key limits. ### GET `/api-keys` List API keys (prefix only). MCP tool: [`list_api_keys`](https://freshlycited.com/docs/tools#list_api_keys). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `tenant_id` | query | string | no | Limit to one workspace | | `status` | query | `active` \| `revoked` | no | | | `q` | query | string | no | | ### POST `/api-keys` Create an API key (secret shown once). Role admin or higher. MCP tool: [`create_api_key`](https://freshlycited.com/docs/tools#create_api_key). Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | no | | | `tenant_id` | string | no | Workspace (tenant) id. Defaults to the workspace of the key or connection; use list_tenants to find client ids. | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | no | | | `rate_per_min` | integer (≥1, ≤600) | no | | | `rate_per_day` | integer (≥1, ≤100000) | no | | | `daily_credit_cap` | integer (≥1, ≤9007199254740991) \| null | no | | ### GET `/api-keys/{id}` One API key. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/api-keys/{id}` Rename, change role or limits. Role admin or higher. MCP tool: [`update_api_key`](https://freshlycited.com/docs/tools#update_api_key). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | no | | | `role` | `owner` \| `admin` \| `member` \| `client_viewer` | no | | | `rate_per_min` | integer (≥1, ≤600) \| null | no | | | `rate_per_day` | integer (≥1, ≤100000) \| null | no | | | `daily_credit_cap` | integer (≥1, ≤9007199254740991) \| null | no | | ### DELETE `/api-keys/{id}` Delete an API key. Role admin or higher. MCP tool: [`delete_api_key`](https://freshlycited.com/docs/tools#delete_api_key). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/api-keys/{id}/revoke` Revoke an API key. Role admin or higher. MCP tool: [`revoke_api_key`](https://freshlycited.com/docs/tools#revoke_api_key). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ## Platform FreshlyCited platform administration. ### GET `/users` List users. Platform admin only. MCP tool: [`list_users`](https://freshlycited.com/docs/tools#list_users). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `status` | query | string | no | | ### POST `/users` Create a user. Platform admin only. Request body (JSON): Any JSON object (see the app for fields). ### GET `/users/{id}` One user. Platform admin only. MCP tool: [`get_user`](https://freshlycited.com/docs/tools#get_user). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/users/{id}` Update a user. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): Any JSON object (see the app for fields). ### DELETE `/users/{id}` Delete a user. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/users/{id}/suspend` Suspend a user. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/users/{id}/activate` Re-activate a user. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/users/{id}/memberships` Add a membership. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tenant_id` | string | yes | | | `role` | string | yes | | ### DELETE `/users/{id}/memberships/{tid}` Remove a membership. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `tid` | path | string | yes | | ### DELETE `/users/{id}/sessions/{sid}` Sign out a user's session. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | | `sid` | path | string | yes | | ### GET `/audit` Audit trail. Platform admin only. MCP tool: [`list_audit_log`](https://freshlycited.com/docs/tools#list_audit_log). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `action` | query | string | no | | ### GET `/errors` Tracked errors. Platform admin only. MCP tool: [`list_errors`](https://freshlycited.com/docs/tools#list_errors). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | ### GET `/errors/{id}` One tracked error. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### PATCH `/errors/{id}` Resolve or reopen an error. Platform admin only. MCP tool: [`resolve_error`](https://freshlycited.com/docs/tools#resolve_error). | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `resolved` | boolean | yes | | ### DELETE `/errors/{id}` Delete a tracked error. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/invites` Invite codes (status: active, used, redeemed, revoked, expired). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `status` | query | `active` \| `used` \| `redeemed` \| `revoked` \| `expired` | no | | ### POST `/invites` Create invite codes: one (optionally bound to an email and sent), or a batch of up to 200. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `count` | integer (≥1, ≤200) | no | | | `email` | string | no | | | `note` | string | no | | | `max_uses` | integer (≥1, ≤1000) | no | | | `expires_days` | number (≥1, ≤365) | no | | | `send` | boolean | no | | ### GET `/invites/{id}` One invite with who redeemed it. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/invites/{id}/send` Email (or re-send) an invite; an unbound single-use invite becomes bound to that address. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | no | | ### POST `/invites/{id}/revoke` Revoke an invite (it stops working at once). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/waitlist` Invite requests (waitlist). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `status` | query | `pending` \| `invited` \| `declined` \| `joined` | no | | ### POST `/waitlist/{id}/approve` Approve a request: a single-use invite bound to that email, sent at once. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `expires_days` | number (≥1, ≤365) | no | | ### POST `/waitlist/{id}/decline` Decline a request (silent unless send_email is true). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `send_email` | boolean | no | | | `note` | string | no | | ### POST `/users/{id}/approve` Approve a pending account. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/users/{id}/decline` Decline a pending account. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/credits/requests/{id}/approve` Approve a credit request. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/credits/requests/{id}/decline` Decline a credit request. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `note` | string | no | | ### POST `/credits/requests/{id}/refund` Refund an approved pack: takes back its unspent credits (platform admin). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `note` | string | no | | ### GET `/upstream/balance` Upstream balances: Standard scans (USD), Live scans (searches left), Pilot Crawl. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `refresh` | query | string | no | 1 = bypass the 5-minute cache | ### PUT `/tenants/{id}/plan` Set a workspace's plan (platform admin override; Stripe sets it automatically once payments are live). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `plan` | `free` \| `agency_starter` \| `agency_pro` \| `agency_scale` | yes | | | `status` | `active` \| `past_due` \| `canceled` | no | | | `interval` | `month` \| `year` \| null | no | | | `current_period_end` | string \| null | no | | | `grace_until` | string \| null | no | | | `grant_period` | boolean | no | Also grant one period of plan credits | | `period_start` | string | no | | | `period_end` | string | no | | | `ref` | string | no | Idempotency key for the grant | | `note` | string | no | Why (kept in the audit log) | ### GET `/admin/margin` Margin dashboard: revenue vs upstream cost, index and credit-back rates, free-tier cost, upstream utilisation, reconciliation. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `from` | query | string | no | | | `to` | query | string | no | | | `days` | query | string | no | | ### GET `/admin/margin/settings` Upstream tier, $/indexed link, monthly allowance and check rates. Platform admin only. ### PUT `/admin/margin/settings` Update upstream tier, $/indexed link, monthly allowance and check rates. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tier` | string \| null | no | | | `cost_per_indexed_usd` | number \| null | no | | | `monthly_allowance` | integer (≥-9007199254740991, ≤9007199254740991) \| null | no | | | `standard_check_usd` | number | no | | | `live_check_usd` | number | no | | ### PUT `/admin/margin/reconciliation/{month}` Enter the upstream billed count for a month (YYYY-MM). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `month` | path | string | yes | | Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `billed_count` | integer (≥-9007199254740991, ≤9007199254740991) \| null | yes | | | `note` | string | no | | ### GET `/admin/free-checks` Free checks: totals (today, 7 and 30 days), top countries, cities, domains, IPs and networks, active blocks and today's caps. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `days` | query | `1` \| `7` \| `30` | no | | ### GET `/admin/free-checks/checks` Free checks log, newest first (q = IP, network, domain, country code or city). Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `kind` | query | `xray` \| `answer` \| `lens` \| `xray_retry` \| `answer_edit` | no | | | `blocked` | query | `1` | no | | ### GET `/admin/free-checks/csv` Free checks of the last 30 days as CSV. Platform admin only. ### POST `/admin/free-checks/blocks` Block an IP or network (/24, /64) from the free checks; hours empty = until lifted. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `target` | string | yes | | | `hours` | integer (≥-9007199254740991, ≤9007199254740991) \| null | no | | | `reason` | string | no | | ### DELETE `/admin/free-checks/blocks/{id}` Lift a free-checks block. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### POST `/admin/free-checks/report` Email yesterday's free-checks report now (default: to yourself). Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `to` | string | no | | ### GET `/admin/billing` Billing: revenue this and last month, refunds and chargebacks, subscriptions by plan, MRR (list prices), Stripe mode. Platform admin only. ### GET `/admin/billing/events` Money events (pack purchases, plan invoices, refunds, chargebacks, failed payments) with Stripe links. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `type` | query | `pack_purchase` \| `plan_invoice` \| `refund` \| `chargeback` \| `payment_failed` | no | | | `tenant_id` | query | string | no | | | `from` | query | string | no | YYYY-MM-DD (UTC) | | `to` | query | string | no | YYYY-MM-DD (UTC, inclusive) | ### GET `/admin/billing/events/csv` The filtered money events as CSV. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `page` | query | string | no | | | `page_size` | query | string | no | | | `q` | query | string | no | | | `sort` | query | string | no | | | `dir` | query | `asc` \| `desc` | no | | | `type` | query | `pack_purchase` \| `plan_invoice` \| `refund` \| `chargeback` \| `payment_failed` | no | | | `tenant_id` | query | string | no | | | `from` | query | string | no | YYYY-MM-DD (UTC) | | `to` | query | string | no | YYYY-MM-DD (UTC, inclusive) | ### GET `/admin/billing/tenants/{id}` One workspace's billing: plan, Stripe subscription, purchases with the pack refund check, recent money events. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/admin/system` Server status: version, uptime, database, scheduler steps, crawl routes, SMTP, Stripe mode, geo databases, backups. Platform admin only. ### GET `/admin/providers` Providers: Pilot Crawl credits estimate (from the last entered balance), fallback credits, scan balances and today's spend vs caps. Platform admin only. ### PUT `/admin/providers/balance` Re-base the Pilot Crawl estimate: credits on the supplier's member page and when, plan tier, $/credit, next bill date, monthly allowance. Platform admin only. Request body (JSON): | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `credits` | integer (≥-9007199254740991, ≤9007199254740991) \| null | no | | | `as_of` | string \| null | no | ISO date-time, default now | | `plan_tier` | string \| null | no | | | `cost_per_credit_usd` | number \| null | no | null = the tier's price | | `next_bill_at` | string \| null | no | | | `monthly_allowance` | integer (≥-9007199254740991, ≤9007199254740991) \| null | no | | ### GET `/admin/providers/usage` Crawl usage by client: links per route this billing period and all time, provider cost, indexed vs credited back, revenue and margin. Platform admin only. ### GET `/admin/providers/usage/csv` Crawl usage by client as CSV. Platform admin only. ### GET `/admin/providers/campaigns` The newest 100 crawl campaigns (names as on the supplier dashboard) with client, site and job, plus per-client and per-site rollups. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `tenant_id` | query | string | no | | | `site` | query | string | no | | | `q` | query | string | no | | ### GET `/admin/providers/campaigns/{id}/links` One campaign's links: the supplier's per-link status (for reference) next to our push state, Google visibility and credit. Platform admin only. | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string | yes | | ### GET `/admin/providers/supplier` Supplier account: connected or not, last sync, last error, the cross-check of our estimate against the supplier's balance. Platform admin only. ### DELETE `/admin/providers/supplier` Disconnect the supplier account (deletes the stored sign-in). Platform admin only. ### POST `/admin/providers/supplier/connect` Start connecting the supplier account: returns the approval page and the code to approve there. Platform admin only. ### POST `/admin/providers/supplier/connect/finish` Finish connecting after the code was approved (the sign-in is stored encrypted, never returned), then sync. Platform admin only. ### POST `/admin/providers/supplier/sync` Sync the supplier's balance and campaign statuses now. Platform admin only. ### POST `/billing/tick` Run the guarantee re-checks and credit housekeeping now (platform admin). Platform admin only. --- Source: https://freshlycited.com/docs/api --- # Recipes: FreshlyCited workflows for agents Each recipe is a short, real workflow shown two ways: as **MCP tool calls** (what your agent does) and as the equivalent **REST** requests (for scripts and CI). Copy the prompt into Claude, ChatGPT or Cursor, or adapt the curl commands. ## Recipes - [Find which of my sitemap URLs aren't indexed and push them](https://freshlycited.com/docs/recipes/push-unindexed-sitemap-urls): check a sitemap, push only what Google can't see; we re-check on day 1, 3 and 7 and return the credit for anything still not indexed. - [Verify my site for IndexNow](https://freshlycited.com/docs/recipes/verify-site-indexnow): add your domain, host the key file, verify it, and confirm pushes now notify Bing. - [Share a client report](https://freshlycited.com/docs/recipes/share-client-report): turn a push or check into a read-only before/after link for a client. All recipes assume a connected client ([Quickstart](https://freshlycited.com/docs/quickstart)) or an API key ([Authentication](https://freshlycited.com/docs/authentication)). --- Source: https://freshlycited.com/docs/recipes --- # Find unindexed sitemap URLs and push them Goal: of the pages in your sitemap, find the ones Google doesn't show yet, push only those, and get the result in a few days. Cost: 1 check credit per URL checked, plus 1 index credit per URL pushed, used only if it gets indexed (it comes back after 7 days if not). ## Prompt for your agent > "Fetch https://example.com/sitemap.xml, collect the page URLs, check which ones Google can't see with FreshlyCited, push those (FreshlyCited re-checks them on day 1, 3 and 7), and tell me the outcome." ## 1. Collect the URLs Your agent (or script) reads the sitemap and extracts each ``. For a sitemap index, read the child sitemaps too. Keep only canonical, public https URLs; up to 10,000 per job. ## 2. Check them ```json { "name": "check_index", "arguments": { "urls": [ "https://example.com/", "https://example.com/blog/new-post", "https://example.com/pricing" ], "name": "Sitemap check, October" } } ``` ```bash curl -X POST https://freshlycited.com/api/v1/check -H "Authorization: Bearer ipk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"urls":["https://example.com/","https://example.com/blog/new-post"],"name":"Sitemap check"}' ``` Larger checks run in a queue: poll until the job's `outcome.stage` is `check_done`. ```json { "name": "get_job_status", "arguments": { "job_id": "job_…", "url_limit": 0 } } ``` ## 3. Push only the invisible ones ```json { "name": "send_unindexed_to_indexer", "arguments": { "job_id": "job_…" } } ``` ```bash curl -X POST https://freshlycited.com/api/v1/jobs/job_…/send-unindexed -H "Authorization: Bearer ipk_YOUR_KEY" \ -H "Content-Type: application/json" -d '{}' ``` This creates a new push with only the URLs Google didn't show. The check becomes the "before" for the visibility lift. If any of those URLs are on a site you [verified for IndexNow](https://freshlycited.com/docs/recipes/verify-site-indexnow), they're also sent to Bing and the other IndexNow engines, free. **Shortcut:** skip step 2 and push the whole list with `smart: true`. FreshlyCited checks first and only pushes, and charges the push for, the URLs Google can't see: ```json { "name": "submit_index_job", "arguments": { "urls": [ "https://example.com/", "https://example.com/blog/new-post" ], "smart": true, "name": "Sitemap: October" } } ``` ## 4. Read the result After the day-1, day-3 or day-7 re-check (or any time with `check_index` and the push's `job_id`), `get_job_status` returns an outcome such as *"11 of 12 links seen by Google (+2)"*. Still invisible? Push them again with `send_unindexed_to_indexer`, or give Google a few more days: FreshlyCited gets pages crawled, but Google decides what it shows. --- Source: https://freshlycited.com/docs/recipes/push-unindexed-sitemap-urls --- # Recipe: verify your site for IndexNow Goal: every push for your domain also notifies Bing (and Copilot, Yandex, Seznam, Naver, Yep) through IndexNow. Free. Takes a few minutes, mostly uploading one small file. IndexNow does not reach Google; your Google push works exactly as before. ## Prompt for your agent > "Add www.example.com to FreshlyCited's IndexNow sites, tell me the key file to upload, and verify it when I say it's done." ## 1. Add the site ```json { "name": "add_indexnow_site", "arguments": { "host": "www.example.com" } } ``` ```bash curl -X POST https://freshlycited.com/api/v1/indexnow/sites -H "Authorization: Bearer ipk_YOUR_KEY" \ -H "Content-Type: application/json" -d '{"host":"www.example.com"}' ``` The response includes `id`, `key` and `key_file_url`, for example `https://www.example.com/3f9c…e1.txt`. Add each hostname you use separately (`example.com` and `www.example.com` are different to IndexNow). ## 2. Publish the key file Create a plain-text file named `.txt` whose only content is the key, and upload it to the root of the site so it loads at `key_file_url`. On WordPress, upload it with your host's file manager or SFTP; on Vercel, Netlify or a static site, put it in the public folder. Can't write to the root? Put it anywhere on the same host and set it as the key location; it then covers only URLs under that folder: ```json { "name": "update_indexnow_site", "arguments": { "site_id": "site_…", "key_location": "https://www.example.com/seo/3f9c…e1.txt" } } ``` ## 3. Verify ```json { "name": "verify_indexnow_site", "arguments": { "site_id": "site_…" } } ``` ```bash curl -X POST https://freshlycited.com/api/v1/indexnow/sites/site_…/verify -H "Authorization: Bearer ipk_YOUR_KEY" ``` `verification.ok: true` means you're done. Otherwise `verification.detail` says what's wrong in plain words, such as "The key file isn't there yet (HTTP 404…)" or "returned a web page, not the key". ## 4. Confirm on your next push Push any URLs on that host as usual. The outcome adds a line like *"3 links also sent to Bing (IndexNow)"*, and the per-link detail shows each IndexNow result: ```json { "name": "get_job_indexnow", "arguments": { "job_id": "job_…" } } ``` `accepted` (HTTP 200) reads "Sent to Bing (IndexNow): received"; `submitted` (HTTP 202) reads "received, key pending", which is normal right after verification. Either way IndexNow got the notice; Bing still decides when, and whether, to index the page. FreshlyCited re-checks the key file daily and pauses notices (with an email) if it disappears twice in a row. More: [Bing & Copilot (IndexNow)](https://freshlycited.com/docs/indexnow). --- Source: https://freshlycited.com/docs/recipes/verify-site-indexnow --- # Recipe: share a client visibility report Goal: send a client a read-only, white-label link that shows what Google saw before and after your work, per link. No login needed on their side; you can stop sharing at any time. ## Prompt for your agent > "Find my latest push for in FreshlyCited and give me a client report link." ## 1. Find the job ```json { "name": "list_jobs", "arguments": { "q": "", "type": "index", "page_size": 5 } } ``` ```bash curl "https://freshlycited.com/api/v1/jobs?q=CLIENT_NAME&type=index&page_size=5" -H "Authorization: Bearer ipk_YOUR_KEY" ``` ## 2. Make sure the result is fresh If the push hasn't been re-checked yet, run a visibility check on it (1 check credit per link) so the report shows the "after": ```json { "name": "check_index", "arguments": { "job_id": "job_…" } } ``` ## 3. Create the link ```json { "name": "share_job_report", "arguments": { "job_id": "job_…" } } ``` ```bash curl -X POST https://freshlycited.com/api/v1/jobs/job_…/share -H "Authorization: Bearer ipk_YOUR_KEY" ``` The response includes `url` (for example `https://freshlycited.com/r/…`). Calling it again returns the same link. The report shows the before/after visibility, each link's status and when it was checked, without your account details or credit costs. ## 4. Stop sharing ```json { "name": "share_job_report", "arguments": { "job_id": "job_…", "revoke": true } } ``` The old link stops working immediately. Prefer a spreadsheet? `export_job_csv` returns the same data as CSV. --- Source: https://freshlycited.com/docs/recipes/share-client-report --- # AGENTS.md snippet for FreshlyCited Coding agents (Claude Code, Cursor, Codex, Copilot…) read `AGENTS.md` or `CLAUDE.md` at the root of a repository. Paste the snippet below so that after the agent ships or changes public pages, it checks them and gets them crawled with FreshlyCited, without guessing at prices or overpromising. ## Before you paste - Connect the FreshlyCited MCP server in your agent first (see [Quickstart](https://freshlycited.com/docs/quickstart)). - Replace `example.com` with your domain. - Optional: [verify the domain for IndexNow](https://freshlycited.com/docs/recipes/verify-site-indexnow) so pushes also reach Bing. ## The snippet ```markdown ## Getting new pages seen (FreshlyCited) This project uses the FreshlyCited MCP server (https://freshlycited.com/mcp) to get new and updated public pages crawled and to check what search engines see. When you add or substantially change public pages on example.com: 1. Collect the full public URLs (production, https, no drafts or staging). 2. Call `submit_index_job` with `{ "urls": [...], "smart": true }` (we re-check on day 1, 3 and 7). smart=true checks first and only pushes URLs Google doesn't show yet. 3. Report the outcome headline from the result to the user. Rules: - Credits: check 1 check credit/URL; push 1 index credit/URL, used only if indexed (credit back after 7 days if not). If a tool returns needs_confirmation, ask the user before calling again with confirm_spend: true. - Don't push the same URLs again within 24 hours unless the content changed. - Never claim a page is indexed or will be cited. Say what the check showed, e.g. "4 of 5 seen by Google; we re-check on Monday". - IndexNow (Bing, Copilot, Yandex…) is automatic for verified domains and free. It does not reach Google, ChatGPT or Perplexity. - Unsure what to do? Call `get_started`. ``` ## Why these rules - **smart: true** saves index credits: URLs Google already shows aren't pushed, and their reserved credit comes straight back. - **The confirmation guard** matches the server: calls that would spend more than 1,000 credits return `needs_confirmation` until the user agrees (see [Rate limits](https://freshlycited.com/docs/rate-limits)). - **Honest reporting**: FreshlyCited makes the crawl request and measures the result; search engines decide what they index and cite. --- Source: https://freshlycited.com/docs/agents-md