---
title: "One site's health, latest crawl, trend and top issues"
method: GET
path: "/v1/sites/{site}"
tags: ["sites"]
---

# One site's health, latest crawl, trend and top issues

`GET /v1/sites/{site}`

## Request

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

One site's triage view: its health with the read it rests on, the latest crawl and what it left out, the score trend, the score taken apart, the issue counts and the top open issues by priority. Pass a site id, origin or domain (AMBIGUOUS_SITE when several match: then pass the id). Quote a score with its coverage, never alone; `inconclusive` means we could not read the site, never that it is healthy. `issue_counts` counts the whole queue, the ignored included, so an ignored backlog is never invisible. `latest_crawl.coverage` null means not measured, never nothing left out. Next: issues_list for the full queue, issues_get for one issue's work order.

## Path parameters

- `site` string, required: Site ID (site_…), origin (https://example.com), or bare domain, resolved server-side; the response carries the canonical ID.

## Response `200`

One site's health, latest crawl, trend and top issues

- 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.
  - `provenance` object, required
    - `crawl_seq` integer, nullable, required: The crawl the answer was read from; null when the site has none yet.
    - `data_freshness` string, required: When that crawl finished (ISO 8601) or `no completed crawl`; for a read of one committed crawl, `committed crawl (immutable snapshot)`, or `not committed (<reason>)` when nothing committed answered.
  - `site` object, required
    - `id` string, required
    - `origin` string, required
    - `display_name` string, nullable, required
    - `current_crawl_seq` integer, nullable, required
    - `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).
  - `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.
  - `redirected_to` object: Present only when health is inconclusive for the `redirected` reason. The two sites' histories are never merged: remove the duplicate or add the target, never read this site's score elsewhere.
    - `host` string, required: The host every page the crawl read redirected to.
    - `site_id` string, nullable, required: The workspace's site at that host; null when it is not tracked.
  - `score_breakdown` object, nullable, required: Null when the score cannot be explained: no score, or a score from an earlier formula.
    - `score` number, required: The score explained; always equal to `health.score`.
    - `floor` object, required
      - `applies` boolean, required: True when the 30-point critical floor was forfeited.
      - `earned` number, required
      - `of` number, required
      - `forfeited_by` string[], required: The critical checks that forfeited it.
    - `costs` object[], required: Every failed scored check and the points it costs, costliest first. The costs sum to 100 minus the score.
      - `rule_id` string, required
      - `points` number, required
    - `recoverable_top3` object, required: The score with the top three costs fixed (`fixed` of them, `points` back).
      - `fixed` integer, required
      - `points` number, required
      - `score` number, required
  - `search_health` union, required: The search-weighted score beside the health score, from the same crawl: each failed check discounted by the share of Search Console clicks that miss its pages (criticals count in full).
    - object
      - `state` 'ready', required
      - `crawl_seq` integer, required
      - `score` number, required: The search-weighted score: never below `health.score`.
      - `version` integer, required
      - `health` number, required: The health score it sits beside.
      - `window` object, required: The crawl's frozen Search Console window the clicks come from.
        - `crawl_seq` integer, required
        - `crawl_run_id` string, required
        - `window` object, required
          - `start` string, required
          - `end` string, required
        - `clicks` number, required
        - `impressions` number, required
        - `pages_listed` integer, required
        - `pages_read` integer, required
        - `capped_days` integer, required
        - `source_id` string, required
      - `sentence` string, required
      - `floor` object, required
        - `applies` boolean, required
        - `earned` number, required
        - `of` number, required
        - `forfeited_by` string[], required
      - `costs` object[], required
        - `rule_id` string, required
        - `critical` boolean, required
        - `health` number, required
        - `weighted` number, required
        - `discount` number, required
        - `clicks` number, nullable, required
      - `rest` object, required
        - `count` integer, required
        - `discount` number, required
    - object
      - `state` 'unavailable', required
      - `reason` 'no_run' | 'unscored' | 'formula_version' | 'no_frozen_config' | 'disagrees' | 'before_store' | 'not_joined' | 'no_clicks', required
      - `sentence` string, required
    - object
      - `state` 'withheld', required
      - `reason` 'scope' | 'gated', required: `scope`: the key lacks search:read; `gated`: the site's plan lacks Search.
    - object
      - `state` 'too_large', required
      - `sentence` string, required
  - `latest_crawl` object, nullable, required: The site's current crawl; null before the first.
    - `id` string, required
    - `status` 'queued' | 'leased' | 'running' | 'finalizing' | 'complete' | 'complete_with_exclusions' | 'partial_budget' | 'partial_blocked' | 'failed_infrastructure' | 'cancelled', required
    - `pages_crawled` integer, required
    - `coverage` object, nullable, required: What this crawl did not read, and why. Null means not measured, never nothing left out.
      - `left_out_by_reason` object, required: URLs the crawl admitted and did not read, by reason (excluded, max_urls, a fetch failure, ...).
      - `left_out_total` integer, required: The sum of `left_out_by_reason`.
      - `limit_reached` boolean, required: True when the crawl stopped at its page limit.
      - `pages_admitted` integer, required
      - `resources_admitted` integer, required
      - `external_total` integer, required
      - `external_admitted` integer, required
      - `by_kind` object, required
        - `page` object, required
          - `queued` integer, required
          - `leased` integer, required
          - `done` integer, required
          - `failed` integer, required
          - `skipped` integer, required
        - `resource` object, required
          - `queued` integer, required
          - `leased` integer, required
          - `done` integer, required
          - `failed` integer, required
          - `skipped` integer, required
        - `external` object, required
          - `queued` integer, required
          - `leased` integer, required
          - `done` integer, required
          - `failed` integer, required
          - `skipped` integer, required
    - `completed_at` string, nullable, required
  - `trend_headline` string, required: How the score moved over the last two complete crawls. Partial crawls are skipped, and scores from different formulas are never compared.
  - `top_issues` object[], required: At most 5 open issues, highest priority first; not ignored, not resolved.
    - `id` string, required
    - `rule_id` string, required
    - `severity` 'critical' | 'high' | 'medium' | 'low' | 'info', required
    - `priority_score` number, required
    - `state` 'open' | 'acknowledged' | 'ignored' | 'pending_fix' | 'awaiting_merge' | 'awaiting_deployment' | 'verification_queued' | 'verification_running' | 'verified_resolved' | 'verification_failed' | 'regression_detected' | 'needs_human_review' | 'no_longer_checked', required
    - `staleness` 'current' | 'not_seen_in_latest', required: `not_seen_in_latest`: the latest crawl did not see it. That is not a fix.
    - `affected_url_count` integer, required
    - `version` integer, required: Pass it back as `expected_version` when you act on the issue.
    - `dashboard_url` string, required: The page in Frontshelf to hand your human (app-relative).
  - `open_issue_count` integer, required: Open issues: not resolved, not ignored, not closed as no longer checked.
  - `issue_counts` object, required: Every state the queue holds, counted exactly over the whole queue.
    - `open` integer, required
    - `ignored` integer, required
    - `verified_resolved` integer, required
    - `no_longer_checked` integer, required: Closed, not fixed: the check cannot run (a setting or service off or not linked, a language spelling checks do not cover).
    - `counted_rows` integer, required: Issue rows this answer read to choose `top_issues` from.
    - `total_rows` integer, required: Issue rows the site has.
    - `truncated` boolean, required: True when the rows read were cut; the four counts above are exact anyway.
  - `top_issues_truncated` boolean, required: True when more open issues exist than `top_issues` shows.
  - `findings` object, required: What the open issues' findings add up to, counted at the unit of the fix. When they could not be counted (a read that failed on a very large crawl), every figure is null, never 0, and `headline` says so; the rest of the answer stands.
    - `scored` integer, nullable, required: Open findings of checks that lower the score (affected minus ignored).
    - `unscored` integer, nullable, required: Open findings of checks that do not lower it.
    - `ignored` integer, nullable, required: Ignored findings of scored checks: said, never subtracted in silence.
    - `patterns` integer, nullable, required: Distinct URL patterns among the scored findings; one pattern is one cause.
    - `single_pages` integer, nullable, required
    - `patterns_available` boolean, required: False: the crawl predates URL patterns, and no pattern figure is guessed.
    - `headline` string, nullable, required: The sentence every screen says; null with no open issue.
    - `quiet_line` string, nullable, required

## Other responses

- `400`: VALIDATION_FAILED
- `401`: UNAUTHENTICATED
- `403`: SCOPE_DENIED
- `404`: SITE_NOT_FOUND
- `409`: AMBIGUOUS_SITE, 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)
