> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Scan

> On-demand single-domain scan, retrieval, and listing.

## POST /v1/scanner/scan

Scan a single domain. Returns in 2–5 seconds for most sites.

**Scope required:** `scan`   **Cost:** 1 credit

```bash theme={null}
curl -X POST https://scanner.getsly.ai/v1/scanner/scan \
  -H "Authorization: Bearer $SCANNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "shopify.com",
    "merchant_name": "Shopify",
    "merchant_category": "saas",
    "country_code": "CA",
    "region": "north_america",
    "skip_if_fresh": true
  }'
```

Request fields:

| Field               | Type    | Notes                                                                                                      |
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------- |
| `domain`            | string  | Required. Normalized server-side (lowercase, no scheme).                                                   |
| `merchant_name`     | string  | Optional metadata.                                                                                         |
| `merchant_category` | enum    | `retail`, `saas`, `marketplace`, `restaurant`, `b2b`, `travel`, `fintech`, `healthcare`, `media`, `other`. |
| `country_code`      | string  | ISO 3166-1 alpha-2.                                                                                        |
| `region`            | enum    | `latam`, `north_america`, `europe`, `apac`, `africa`, `mena`.                                              |
| `skip_if_fresh`     | boolean | If true, returns the cached scan when it's under 7 days old (still costs 0 credits).                       |

Response is a full [`MerchantScan`](/scanner/data-model) object. The response includes a **`request_id`** field (also echoed in the `X-Request-ID` response header) — the same id appears as `source: "request:<uuid>"` on the credit ledger row that paid for the scan, so you can join consume rows back to scan results. See [audit trail](/scanner/credits-and-billing#ledger).

The response also includes an **`X-Credits-Remaining`** header so you can track your balance without an extra call. The TypeScript SDK reads it automatically — see the [SDK reference](/scanner/sdk).

### Errors

Validation typos and server errors are **automatically refunded** — see [auto-refund on 4xx and 5xx](/scanner/credits-and-billing#auto-refund-on-4xx-and-5xx). Common errors:

| Status | Meaning                                          | Body shape                                                                          |
| ------ | ------------------------------------------------ | ----------------------------------------------------------------------------------- |
| 400    | Validation error                                 | `{ error: "Validation error", details: { fieldErrors: { domain: ["Required"] } } }` |
| 401    | Bad / expired key                                | `{ error: "unauthorized" }`                                                         |
| 402    | Insufficient credits (not debited)               | `{ error: "insufficient_credits", balance, required, docs }`                        |
| 429    | Rate limited (not debited; honors `Retry-After`) | `{ error: "rate_limit_exceeded", limit, reset_seconds }`                            |

## GET /v1/scanner/scan/:id

Retrieve a specific scan by UUID.

**Scope required:** `read`   **Cost:** 0

## GET /v1/scanner/scans/by-domain/:domain

Look up the freshest scan across the shared corpus for a given domain.

**Scope required:** `read`   **Cost:** 0

```bash theme={null}
curl -H "Authorization: Bearer $SCANNER_KEY" \
  https://scanner.getsly.ai/v1/scanner/scans/by-domain/shopify.com
```

Returns `404` if no scan exists for the domain.

## GET /v1/scanner/scans

List scans with filters. Returns rows across all tenants — the shared scan corpus.

**Scope required:** `read`   **Cost:** 0

Query parameters:

| Param       | Notes                                  |
| ----------- | -------------------------------------- |
| `category`  | Merchant category filter               |
| `region`    | Region filter                          |
| `status`    | `completed`, `failed`, `pending`, etc. |
| `min_score` | Minimum `readiness_score`              |
| `max_score` | Maximum `readiness_score`              |
| `page`      | 1-indexed                              |
| `limit`     | Max 100                                |

Response:

```json theme={null}
{
  "data": [ /* MerchantScan[] */ ],
  "pagination": { "page": 1, "limit": 20, "total": 1423, "totalPages": 72 }
}
```

## GET /v1/scanner/scans/stats

Aggregate stats across the shared corpus.

```json theme={null}
{
  "total": 1423,
  "completed": 1398,
  "avg_readiness_score": 54,
  "by_category": { "retail": 412, "saas": 338, "marketplace": 201, ... },
  "by_region": { "north_america": 720, "europe": 388, ... }
}
```

## GET /v1/scanner/scans/protocol-adoption

Detected/functional adoption rates per protocol.

```json theme={null}
{
  "acp": { "detected": 201, "functional": 128, "total": 1398, "adoption_rate": 14 },
  "x402": { "detected": 33,  "functional": 29,  "total": 1398, "adoption_rate": 2 },
  ...
}
```
