> For the complete documentation index, see [llms.txt](https://docs.yaeris.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.yaeris.com/software/yaeris-radar/crawler-api-and-mcp.md).

# Radar Crawler REST API & MCP Tools

Call Radar's Crawler from your own code or AI agent via REST API or MCP tools — same crawl engine, pricing, and contact extraction as the dashboard.

Everything the Crawler does in the dashboard — Brand and Directory crawls, contact extraction, and the optional HTML/Markdown page output — is also available as a REST API and as MCP tools, so you can call it from your own code or point an AI agent at it directly.

### Authentication

Create a key at **Settings → API Keys** in the dashboard. The plaintext key is shown exactly once — store it yourself, Radar only keeps a hash. Send it as a bearer token on every request:

```
Authorization: Bearer rdr_live_...
```

{% hint style="info" %}
Rate limit: 60 requests/minute per key, shared across every Radar API/MCP operation. An invalid or revoked key returns `401`; going over the limit returns `429` with a `Retry-After` header.
{% endhint %}

### REST API

Base URL: `https://radar.yaeris.com/api/v1`

**`POST /crawl`** — start a crawl.

```json
{
  "type": "BRAND",
  "urls": ["https://example.com"],
  "pageLimit": 30,
  "depthLimit": 2,
  "format": ["contacts", "markdown"]
}
```

* `type`: `"BRAND"` (crawl one or more business sites directly) or `"DIRECTORY"` (crawl a listing/index page and follow individual listings).
* `urls`: required, non-empty.
* `pageLimit` / `depthLimit`: optional (default 100 / 2).
* `format`: optional, defaults to `["contacts"]`. Any combination of:
  * `"contacts"` — business name/phone/email/website (today's default behavior).
  * `"html"` — the raw fetched page HTML, capped at 300,000 characters (truncated with a trailing marker past that).
  * `"markdown"` — a readability-cleaned Markdown version of the page content, capped at 100,000 characters — the format an LLM/RAG pipeline typically wants, far cheaper in tokens than raw HTML. Falls back to converting the whole page if it isn't article-shaped enough for readability extraction to find a main content block (e.g. a directory listing page), so it's never returned empty just because a page isn't an article.

→ `202 { "jobId": "...", "status": "QUEUED" }`

**`GET /crawl/:jobId`** — status and results.

```json
{
  "jobId": "...",
  "type": "BRAND",
  "status": "DONE",
  "error": null,
  "createdAt": "...",
  "finishedAt": "...",
  "pages": [
    { "url": "...", "httpStatus": 200, "fetchStatus": "SUCCESS", "businessName": "...", "phone": "...", "email": "...", "websiteUrl": "...", "html": null, "markdown": "..." }
  ]
}
```

`status` is one of `QUEUED` / `RUNNING` / `DONE` / `FAILED`. A page's `fetchStatus` (`SUCCESS` / `BLOCKED` / `FAILED` / `TIMEOUT`) explains that specific page even when the overall job succeeded. `html`/`markdown` are `null` unless requested via `format` on the original `POST /crawl` call.

{% hint style="info" %}
Charged 1 credit per page crawled, once the job finishes — plus 1 extra credit per page if `format` includes `"html"` and/or `"markdown"` (both admin-configurable in the dashboard's Admin → Pricing). Your balance is checked against the maximum possible cost (page limit × rate) before the crawl starts, so an empty balance returns a `402` immediately rather than the crawl starting and failing partway through — the actual charge afterward is capped by pages actually visited, never more.
{% endhint %}

#### Errors

| Status | Meaning                                                        |
| ------ | -------------------------------------------------------------- |
| `400`  | Bad request — missing/invalid fields (message explains which). |
| `401`  | Missing, malformed, or invalid `Authorization` header.         |
| `402`  | Insufficient credit balance for this operation.                |
| `404`  | The referenced job doesn't exist on this project.              |
| `429`  | Rate limit exceeded — check `Retry-After`.                     |

Every error body is `{ "error": "..." }`.

### MCP server

Endpoint (Streamable HTTP, stateless): `https://radar.yaeris.com/api/mcp`

Same bearer-token auth as the REST API, sent as a header on the connection.

**Claude Code** (project-scoped `.mcp.json`, or `claude mcp add`):

```json
{
  "mcpServers": {
    "radar": {
      "url": "https://radar.yaeris.com/api/mcp",
      "headers": { "Authorization": "Bearer rdr_live_..." }
    }
  }
}
```

**Claude.ai / other MCP clients**: add a remote MCP connector pointing at the same URL, with the same `Authorization` header.

| Tool            | Equivalent to       |
| --------------- | ------------------- |
| `start_crawl`   | `POST /crawl`       |
| `get_crawl_job` | `GET /crawl/:jobId` |

Each tool wraps the identically-named REST operation above — same inputs, same validation, same credit charges. A typical agent calls `start_crawl`, then polls `get_crawl_job` until `status` is no longer `QUEUED`/`RUNNING`.

{% hint style="info" %}
Dashboard-only for now: Bulk Crawl (crawling many starting URLs from a saved list in one go). The API/MCP tools above cover single and multi-URL Brand/Directory crawls, just not that saved-list workflow yet.
{% endhint %}
