# Agentic Readiness Scanner REST API

The scanner exposes a small public REST API under `/api`. No authentication is required. The machine-readable contract is the [OpenAPI 3.1 description](/api/openapi.json); this guide explains how to use it.

## Purpose

Use this API when you need to assess how well a public website exposes machine-readable affordances to agents, or to read the public leaderboard. Every response is JSON except the progress stream, which uses server-sent events.

## Run a scan

1. `POST /api/scans` with body `{"url": "https://example.com"}`. The response is a scan record with `status: "pending"` and an `id`.
2. Poll `GET /api/scans/{id}` every few seconds until `status` is `completed` or `failed`. Alternatively subscribe to `GET /api/scans/{id}/events` for server-sent events and resume with the `Last-Event-ID` header.
3. Read `assessment.scores.overall.percent` for the score, `assessment.scores.gates` for unmet tier gates, and `assessment.checks` for each check's state, evidence summary and remediation.

Resubmitting the same URL within 24 hours is an idempotent operation for the assessment: the new scan reuses the retained collection and reports `reused: true`. Pass `"refresh": true` to force a fresh retrieval.

## Leaderboard

- `GET /api/leaderboard` returns the top 100 domains with tier, score and latest scan identifier.
- `GET /api/leaderboard/scans/{scanId}` returns the rank of the domain behind a scan, or a null rank when it is unranked.

## MCP and A2A

The same capability is available to agent protocols without the REST client:

- **MCP**: a Streamable HTTP server at `/api/mcp` (server card at [/.well-known/mcp/server-card.json](/.well-known/mcp/server-card.json)) exposing the `scan_website`, `get_scan` and `get_leaderboard` tools. No authentication; browser origins other than this site are rejected.
- **A2A**: a JSON-RPC 2.0 agent at `/api/a2a` (agent card at [/.well-known/agent-card.json](/.well-known/agent-card.json)). `message/send` with a text part containing the URL starts a scan and returns a Task whose id is the scan id; `tasks/get` returns the Task with an `assessment-summary` artifact once completed. `tasks/cancel` is not supported.

## Errors

Errors are JSON objects with a stable `code`, a human-readable `message` and a `_tag` naming the error type.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_scan_target` | The URL is not a public http(s) hostname URL the scanner can retrieve. |
| 404 | `scan_not_found` | No scan exists with that identifier. |
| 429 | `scan_intake_saturated` | The scan backlog is full. Wait for the `Retry-After` delay. |
| 429 | `rate_limited` | Too many requests from this client. Wait for the `Retry-After` delay. |
| 503 | `service_unavailable` | Storage is unreachable. Retry later. |

## Rate limits

Scan submissions are limited to 30 per client per minute and reads to 600 per client per minute. Both limits answer 429 with a `Retry-After` header. Honour that header before retrying; do not retry a 400.

## Related resources

- [llms.txt](/llms.txt): Agent-facing index of this site.
- [Check catalog](/checks.md): What each check measures and how it scores.
