Sites

Sites

A site is a website you've added to MetaMonster. Sites are the top of the hierarchy — pages, snapshots, analysis, and drafts all belong to a site.

All site endpoints require the sites:read scope.

Site-scoped operations over pages are documented with the pages they act on: GET /sites/{siteId}/pages, PATCH /sites/{siteId}/pages (bulk edit), and POST /sites/{siteId}/analyze (bulk analyze, content:write).


GET /sites

List your organization's sites, newest first. Paginated.

Scope: sites:read

Query parameters

Parameter Type Default Notes
page integer 1 1-indexed. Minimum 1.
limit integer 15 Items per page. Minimum 1, maximum 100.

Request

curl "https://new.metamonster.ai/api/v1/sites?page=1&limit=15" \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{
  "data": [
    {
      "id": 42,
      "domain": "example.com",
      "url": "https://example.com",
      "name": "Example",
      "created_at": "2026-05-01T12:00:00Z",
      "last_crawled_at": "2026-07-20T09:30:00Z",
      "page_count": 128,
      "draft_count": 5
    }
  ],
  "meta": { "total": 1, "page": 1, "per_page": 15 }
}

Each item (site summary shape):

Field Type Description
id integer Site ID
domain string The site's domain
url string | null The site's homepage URL, derived from domain: https:// + the lowercased domain, with no trailing slash (e.g. https://example.com). null when domain is not a valid bare hostname — a planned (pre-launch) site whose domain holds a display name, a missing domain, or a domain that includes a path.
name string | null Display name
created_at string | null When the site was added (ISO 8601)
last_crawled_at string | null When the site was last crawled — the latest crawl's completion time, or its start time if still running, else null
page_count integer Number of pages discovered
draft_count integer Number of active field drafts across the site

POST /sites

Add a site to your organization and queue the standard setup job (page discovery → GSC enrichment → crawl) — the API twin of the dashboard's add-site form, minus GSC wiring (API keys carry no user; connect Google Search Console from the dashboard).

Scope: content:write

Request body

Field Type Default Notes
domain string Required. With or without a scheme/trailing slash (e.g. example.com or https://example.com/).
auto_run_keyword_scope string none One of none, homepage, top, all. Have the setup job also generate keywords for this scope.
auto_run_analysis_scope string none One of none, homepage, top, all. Have the setup job also run analysis for this scope.

Both scopes default to none so adding a site over the API never spends keyword or analysis allowance by itself — pass a wider scope only if you want the setup job to run keyword generation and/or analysis right away.

Unsubscribed orgs are capped at one free site-run, and have any wider scope clamped down rather than rejected: all keywords → top; top/all analysis → homepage. This mirrors the free-tier rules the dashboard's add-site form enforces.

Request

curl -X POST https://new.metamonster.ai/api/v1/sites \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "example.com" }'

Response 201

{
  "data": {
    "id": 42,
    "domain": "example.com",
    "url": "https://example.com",
    "name": null,
    "business_context": null,
    "voice_tone": null,
    "gsc_connected": false,
    "gsc_property_url": null,
    "background_status": "discovering",
    "score_curve": null,
    "location": { "country_code": null, "country_name": null, "city_code": null, "city_name": null },
    "llms_txt": null,
    "setup_completed_at": null,
    "discovery_completed_at": null,
    "created_at": "2026-08-19T00:00:00Z",
    "updated_at": "2026-08-19T00:00:00Z",
    "last_crawled_at": null,
    "latest_crawl": null,
    "page_count": 0,
    "draft_count": 0
  }
}

Same site detail shape as GET /sites/{siteId}. background_status starts at discovering — poll GET /sites/{siteId} until it returns to null before expecting a full page list or opportunity scores.

Errors

Status When
400 invalid_request domain is missing or not a valid domain
402 payment_required Unsubscribed org has already used its one free site-run (message: Start your free trial to add more sites.)

GET /sites/{siteId}

Fetch a single site with full detail, including its latest crawl.

Scope: sites:read

Path parameters

Parameter Type Description
siteId integer The site's ID

Request

curl https://new.metamonster.ai/api/v1/sites/42 \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{
  "data": {
    "id": 42,
    "domain": "example.com",
    "url": "https://example.com",
    "name": "Example",
    "business_context": "B2B SaaS for SEO teams",
    "voice_tone": "Professional, concise",
    "gsc_connected": true,
    "gsc_property_url": "sc-domain:example.com",
    "background_status": null,
    "score_curve": "proportional",
    "location": {
      "country_code": 2840,
      "country_name": "United States",
      "city_code": null,
      "city_name": null
    },
    "llms_txt": "…",
    "setup_completed_at": "2026-05-01T12:30:00Z",
    "discovery_completed_at": "2026-05-01T13:00:00Z",
    "created_at": "2026-05-01T12:00:00Z",
    "updated_at": "2026-07-20T09:30:00Z",
    "last_crawled_at": "2026-07-20T09:30:00Z",
    "latest_crawl": {
      "id": 900,
      "status": "completed",
      "total_pages": 128,
      "crawled_pages": 128,
      "started_at": "2026-07-20T09:00:00Z",
      "completed_at": "2026-07-20T09:30:00Z"
    },
    "page_count": 128,
    "draft_count": 5
  }
}

Site detail shape:

Field Type Description
id integer Site ID
domain string The site's domain
url string | null The site's homepage URL, derived from domain: https:// + the lowercased domain, with no trailing slash (e.g. https://example.com). null when domain is not a valid bare hostname — a planned (pre-launch) site whose domain holds a display name, a missing domain, or a domain that includes a path.
name string | null Display name
business_context string | null Business context used to guide content generation
voice_tone string | null Voice & tone guidance
gsc_connected boolean | null Whether Google Search Console is connected
gsc_property_url string | null The connected GSC property
background_status string | null Non-null while site setup / crawling / keyword generation runs in the background: discovering, enriching, crawling, generating_context. null = idle. Opportunity scores and page lists may be incomplete until it returns to null.
score_curve string | null Site-level grade-curve setting
location object Target market — { country_code, country_name, city_code, city_name }, each nullable
llms_txt string | null Generated llms.txt content
setup_completed_at string | null When site setup finished
discovery_completed_at string | null When page discovery finished
created_at string | null When the site was added
updated_at string | null Last update
last_crawled_at string | null Derived from latest_crawl (completion, else start, else null)
latest_crawl object | null The most recent crawl (see below), or null if never crawled
page_count integer Number of pages discovered
draft_count integer Number of active field drafts across the site

latest_crawl object:

Field Type Description
id integer Crawl ID
status string Crawl status (e.g. completed, running, failed)
total_pages integer | null Pages the crawl intended to fetch
crawled_pages integer | null Pages fetched so far
started_at string | null When the crawl started
completed_at string | null When the crawl finished

Errors

Status When
404 not_found No site with that ID in your organization (message: Site not found)