---
title: "List the sites this key can see, with health"
method: GET
path: "/v1/sites"
tags: ["sites"]
---

# List the sites this key can see, with health

`GET /v1/sites`

## Request

- Base URL: `https://frontshelf.io/api`
- URL: `https://frontshelf.io/api/v1/sites`
- Auth: HTTP bearer

Every site this key can see, each with its health, what lowers its score, its billing state and its latest crawl. Call it first: it gives the site ids the other capabilities take (a domain works too). A site missing here means this key cannot reach it, not that it does not exist. Quote a score with `health.coverage` beside it, never alone: it is a claim about the pages the crawl read. A null score or `inconclusive` is never a healthy site, and zero findings is never evidence of health. A site with `billing.read_only` refuses crawls and verification: give your human `billing.checkout_url`. Next: sites_get for one site's detail, issues_list for its issue queue.

## Response `200`

List the sites this key can see, with health

- object
  - `summary` string, required: The answer in one or two sentences, with the numbers it rests on.
  - `warnings` string[], required: What limits this answer (a cap, a read that was cut short). Empty when nothing does.
  - `next_actions` object[], required: What to call next, best first. Follow them.
    - `capability` string, required: What to call next: a capability.
    - `arguments` object, required: Its arguments, complete; pass them as they are.
    - `instruction` string, required: What to do, written to you.
  - `items` object[], required
    - `id` string, required: The canonical site id every other capability takes.
    - `origin` string, required
    - `display_name` string, nullable, required
    - `crawl_frequency` 'manual' | 'daily' | 'weekly' | 'monthly', required
    - `current_crawl_seq` integer, nullable, required: The crawl the site's figures come from; null before the first.
    - `last_crawled_at` string, nullable, required: When the latest crawl finished, accepted or not (ISO 8601); null until one has.
    - `latest_run_status` string, nullable, required: The latest crawl's status, live (`queued`, `running`) or final; null when none was started.
    - `health` object, required
      - `score` integer, nullable, required: 0 to 100, a claim about the pages the crawl read. Null unless the latest finished crawl read at least one page; null is never healthy.
      - `status` 'scored' | 'inconclusive' | 'never_crawled', required: `scored`; `inconclusive`: we crawled and could not score honestly (`reason` says why), never a sign of health; `never_crawled`: no crawl exists.
      - `reason` string: Why an unscored verdict is unscored (`redirected`, `no_content`, ...).
      - `coverage` object: The read the verdict was computed over. Absent only for `never_crawled` and verdicts older than coverage.
        - `status` 'complete' | 'complete_with_exclusions' | 'partial_budget' | 'partial_blocked' | 'failed_infrastructure' | 'cancelled', required: How the crawl the verdict comes from ended.
        - `reason` string, nullable, required: Why the read covers less than it seems (page_budget_reached, rate_limited, render_incomplete, ...); null when nothing limited it.
        - `pages_read` integer, required: Pages the crawl read.
        - `page_limit` integer, nullable, required: The page limit the crawl ran with; null when not recorded.
        - `pages_found` integer, nullable, required: Pages the crawler had found when it ended; null when not recorded.
        - `partial` boolean, required: True when the score is over a partial read. Quote it with the score, never the score alone.
    - `findings` object, nullable, required: What lowers the score as of the crawl that produced it, no ignores subtracted (sites_get says those). Null when the crawl predates the count, never zero.
      - `scored` integer, required: Findings of checks that lower the score.
      - `unscored` integer, required: Findings of checks that do not lower it (opportunities and information).
      - `patterns` integer, required: Distinct URL patterns among the scored findings; one pattern is one cause (a template, a route).
      - `single_pages` integer, required: Lone pages among the scored findings.
      - `patterns_available` boolean, required: False: the crawl predates URL patterns, and `patterns` and `single_pages` are not counted (0 by absence).
    - `billing` object, required
      - `phase` 'unpaid' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unmetered' | 'comped', required: `unpaid` and `canceled` sites are read-only; `unmetered` means billing is off; `comped` means Frontshelf includes the site, fully on (`current_period_end` is when that ends, null for no end); nothing is charged for it unless `whop_renewal` says a Whop subscription still renews.
      - `read_only` boolean, required: True: reads work, crawls and verification refuse with BILLING_REQUIRED. Give your human `checkout_url`.
      - `trial_ends_at` string, nullable, required: While trialing: when the card is charged (ISO 8601).
      - `current_period_end` string, nullable, required: The end of the paid period, or when a cancellation takes effect (ISO 8601).
      - `cancel_at_period_end` boolean, required
      - `checkout_url` string, nullable, required: Present exactly when the site needs a checkout to run. Hand it to your human word for word.
      - `trial_offered` boolean, required: True: the checkout starts with the free trial (the workspace's first site, card required). False: it charges at checkout. Say which to your human; false whenever `checkout_url` is null.
      - `whop_renewal` object, nullable, required: Only while `comped`: a Whop subscription bought for this site still renews, so your human is still charged until it is cancelled (on the site's Plan and billing in the Frontshelf app, a signed-in person's act; the site stays included). `renews_at` is its next charge (ISO 8601) when known. Null otherwise.
        - `renews_at` string, nullable, required
    - `dashboard_url` string, required: The page in Frontshelf to hand your human (app-relative).
  - `truncated` boolean, required: Always false today: the list is never cut.
  - `total` integer, required: How many sites this key can see.

## Other responses

- `400`: VALIDATION_FAILED
- `401`: UNAUTHENTICATED
- `403`: SCOPE_DENIED
- `409`: AGENT_STOPPED
- `503`: DEPENDENCY_UNAVAILABLE

---

[API](https://skmtc.dev/frontshelf/apis/frontshelf-api.md) · [All operations](https://skmtc.dev/frontshelf/apis/frontshelf-api/llms.txt) · [OpenAPI document](https://skmtc.dev/frontshelf/apis/frontshelf-api/revisions/ce3602d26c7c?raw)
