Site facts

Site facts

A site fact is a verified piece of business reality — the company name and founding year, a phone number, a Google Business rating, a testimonial, a stat, an award, a client, a person — that content generation treats as ground truth instead of inventing. Every claim the generator makes about the business (a number, a name, a quote) is meant to come from a fact on file.

Read facts before you write content that states one of those things. If you're about to draft copy that mentions "over 500 clients" or quotes a customer, check here first — reusing what's on file (or adding to it) beats fabricating a number the business never gave you.

Facts come from three places:

  • Crawl extraction — pulled from the site's own pages (schema.org markup, visible testimonials, listed stats) during a crawl.
  • Google Business — pulled from a Google Business Profile listing whose domain matches the site's, found automatically via a Google Maps search on the business name and city. A listing a person pastes into the dashboard (a Maps or Business Profile URL) is accepted without the domain-match check — the user is asserting ownership.
  • This API's POST — facts a user states in conversation. POST always records source: "api" and never invents a fact; it's for writing down what you were told, not generating a plausible one.

A person can also edit a fact in the MetaMonster dashboard (source: "manual"). An edited fact is locked — extraction and this API's POST will never silently overwrite it; use PATCH on that fact instead.

Facts are per site. GET defaults to active facts only — a dismissed fact never appears, and status=all also returns stale ones (found on the site before, not any more) so you can see what changed.

Every fact can carry citations — the page(s) it was read from and the exact words on them — when the request passes include=citations. Check a citation before writing its fact's value into content; see Verifying a claim below.

Scope: sites:read for GET, content:write for POST/PATCH/DELETE.


GET /sites/{siteId}/facts

List a site's facts, filtered, searched, and paginated as needed.

Path parameters

Parameter Type Description
siteId integer The site's ID

Query parameters

Parameter Type Description
kind string Optional. One of identity, contact, listing, testimonial, stat, award, client, person. Omit to return every kind.
status string Optional. One of active (default), stale, or all (active + stale). A dismissed fact is never returned.
search string Optional, 1–200 chars. Case-insensitive match across quotes, names, labels, and values.
include string Optional. Pass citations to attach each fact's citations array. Omit for a smaller response.
limit integer Optional, 1–200, default 100.
offset integer Optional, default 0.

Request

curl -s "https://new.metamonster.ai/api/v1/sites/25/facts?kind=testimonial&include=citations" \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{
  "data": [
    {
      "id": "6f1e6f2a-9b3e-4c8a-8f0a-4a2c6d1f9b10",
      "kind": "testimonial",
      "key": null,
      "data": {
        "quote": "MetaMonster cut our content backlog in half in a month.",
        "author_name": "Jamie Rivera",
        "author_title": "Head of Marketing",
        "author_company": "Northwind Co.",
        "rating": 5,
        "platform": "site"
      },
      "source": "crawl",
      "source_url": "https://example.com/testimonials",
      "verified": false,
      "status": "active",
      "citation_count": 1,
      "last_verified_at": "2026-09-10T08:00:00Z",
      "in_sheet": true,
      "created_at": "2026-08-20T10:00:00Z",
      "updated_at": "2026-08-20T10:00:00Z",
      "citations": [
        {
          "id": "b2f1a0c4-2222-4a5b-9c1d-000000000009",
          "page_id": 42,
          "source": "crawl",
          "source_url": "https://example.com/testimonials",
          "evidence": "\"MetaMonster cut our content backlog in half in a month.\" — Jamie Rivera, Head of Marketing, Northwind Co.",
          "locator": null,
          "status": "active",
          "first_seen_at": "2026-08-20T10:00:00Z",
          "last_verified_at": "2026-09-10T08:00:00Z"
        }
      ]
    }
  ],
  "meta": { "total": 1, "sheet_count": 1 }
}

Field meanings

Field Description
id Fact ID (UUID) — use it as factId on PATCH/DELETE.
kind One of identity, contact, listing, testimonial, stat, award, client, person.
key Slot within the kind — e.g. identity's company_name/founding_year/…, contact's phone/email/…, listing's fixed google. null for kinds that don't use a key (testimonial, stat, award, client, person), since a site can have many of those.
data Shape depends on kind — see Fact kinds below.
source manual (dashboard edit), api (this endpoint's POST), crawl, schema_org, or google_business (extracted).
source_url Where this was extracted from, when known; null for manual/api facts.
verified Settable through the dashboard's confirm flow; not writable through this API.
status active or stale. A stale fact was found on the site before and is no longer there — don't use it in new content.
citation_count How many active citations back this fact. 0 means it predates citations, or a person entered it by hand — there's no receipt to check.
last_verified_at When a citation for this fact was last confirmed still present (for a stale fact, when it was last seen); null when the fact has never been cited.
in_sheet true when this fact is in the ranked, budgeted subset the content generator actually sees. The rest are readable here but not prompted with — use search to find them.
created_at / updated_at Timestamps.
citations Only present when the request passed include=citations. Each entry is a SiteFactCitation — see Citation fields below.
meta.total Total facts matching your filters, before limit/offset pagination.
meta.sheet_count How many of the matching facts are in_sheet.

Citation fields

Field Description
id Citation ID (UUID).
page_id The page this evidence was read from; null for a Google Business listing, which has no page.
source Same enum as a fact's source.
source_url Where the evidence was read from.
evidence The exact text this fact was extracted from — the receipt.
locator Where within the source the evidence was found, when known.
status active, or gone if a later crawl no longer found this evidence.
first_seen_at / last_verified_at Timestamps.

page_id's snapshot_id and a citation's gone_at are internal and not returned — status already tells you whether to trust the citation.

Verifying a claim through a citation

Before writing a fact's value into generated content, fetch it with citations and check the evidence actually supports the claim:

curl -s "https://new.metamonster.ai/api/v1/sites/25/facts?search=500&include=citations" \
  -H "Authorization: Bearer mm_YOUR_API_KEY"
{
  "data": [
    {
      "id": "9d2e1c40-1111-4a2b-8c3d-000000000001",
      "kind": "stat",
      "data": { "label": "Happy clients", "value": "500+" },
      "citation_count": 1,
      "citations": [
        {
          "id": "c1", "page_id": 12, "source": "crawl",
          "source_url": "https://example.com/about",
          "evidence": "Trusted by over 500 clients worldwide.",
          "status": "active", "first_seen_at": "2026-07-01T00:00:00Z", "last_verified_at": "2026-09-10T08:00:00Z"
        }
      ]
    }
  ],
  "meta": { "total": 1, "sheet_count": 1 }
}

The evidence says "over 500 clients", which supports the fact's 500+ value — safe to write "500+ clients" into copy. A citation_count: 0 fact has no citations entries to check even with include=citations; treat those more cautiously, since nothing on the site currently backs them.

Fact kinds

Kind key data
identity one of company_name, legal_name, tagline, founding_year, industry, service_area, team_size { value: string }
contact one of phone, email, address, hours, booking_url, or social:<platform> { value: string }
listing always google (singleton per site) { rating: number, review_count: integer, url: string, place_id?, cid?, address?, phone? }
testimonial null { quote: string, author_name: string, author_title?, author_company?, rating?, date?, platform: "site" | "google" }
stat null { label: string, value: string, context?, as_of? }
award null { name: string, issuer?, year? }
client null { name: string, type: "client" | "partner" | "press" | "integration", url? }
person null { name: string, role: string, bio?, credentials?, url? }

Errors

Status When
400 invalid_request kind/status/include isn't a recognized value, search is empty or over 200 chars, limit/offset is out of range, or the query includes an unrecognized parameter
404 not_found No such site in your organization

POST /sites/{siteId}/facts

Bulk-add facts a user stated in conversation. source is always api, regardless of what you send.

Path parameters

Parameter Type Description
siteId integer The site's ID

Body

Field Type Description
facts array (1–100) Each entry is { kind, key?, data } — see Fact kinds for the shape data must take for each kind.

Request

curl -s -X POST "https://new.metamonster.ai/api/v1/sites/25/facts" \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "facts": [
      { "kind": "stat", "data": { "label": "Happy clients", "value": "500+" } },
      { "kind": "identity", "key": "founding_year", "data": { "value": "2014" } }
    ]
  }'

Response 201

{
  "data": {
    "inserted": [
      {
        "id": "9d2e1c40-1111-4a2b-8c3d-000000000001",
        "kind": "stat",
        "key": null,
        "data": { "label": "Happy clients", "value": "500+" },
        "source": "api",
        "source_url": null,
        "verified": false,
        "status": "active",
        "citation_count": 0,
        "last_verified_at": null,
        "in_sheet": false,
        "created_at": "2026-09-02T12:00:00Z",
        "updated_at": "2026-09-02T12:00:00Z"
      }
    ],
    "updated": [],
    "skipped": []
  }
}

Field meanings

Field Description
inserted Newly created facts, presented the same as GET.
updated Existing facts whose value changed as a result of this call.
skipped Facts that were neither inserted nor updated, in request order. Each entry is { index, reason }, where index is the position of that fact in the facts array you sent.

skipped[].reason is one of:

Reason Meaning
invalid Failed schema validation for its kind
edited Collides with a fact a person edited in the dashboard — the API never overwrites those. PATCH that fact directly instead.
dismissed Collides with a fact that was deleted/dismissed — resubmitting doesn't resurrect it
lower_precedence An existing fact from a higher-precedence source already covers this
unchanged Identical to what's already on file — nothing to do
duplicate Duplicates another entry earlier in the same request
low_rating A testimonial rated below 4 stars; testimonials must be 4 or 5 stars to be stored

Errors

Status When
400 invalid_request facts is missing, empty, over 100 entries, or contains an unparseable entry (validation happens per-entry at write time too — a malformed single entry comes back in skipped with reason: "invalid", but a request body that fails to parse at all is rejected outright)
404 not_found No such site in your organization

PATCH /sites/{siteId}/facts/{factId}

Edit a fact's value in place. Marks the fact as user-edited, so a later extraction run leaves it alone.

Path parameters

Parameter Type Description
siteId integer The site's ID
factId string (UUID) The fact's ID, from GET

Body

Field Type Description
key string | null Optional. Only meaningful for kinds that use one (identity, contact, listing). Omit to leave the existing key unchanged.
data object Required. Validated against the fact's existing kind — see Fact kinds.

Request

curl -s -X PATCH "https://new.metamonster.ai/api/v1/sites/25/facts/9d2e1c40-1111-4a2b-8c3d-000000000001" \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "data": { "label": "Happy clients", "value": "600+" } }'

Response 200

{
  "data": {
    "id": "9d2e1c40-1111-4a2b-8c3d-000000000001",
    "kind": "stat",
    "key": null,
    "data": { "label": "Happy clients", "value": "600+" },
    "source": "api",
    "source_url": null,
    "verified": false,
    "status": "active",
    "citation_count": 0,
    "last_verified_at": null,
    "in_sheet": false,
    "created_at": "2026-09-02T12:00:00Z",
    "updated_at": "2026-09-02T12:10:00Z"
  }
}

Errors

Status When
400 invalid_request factId isn't a valid UUID, or data doesn't validate against the fact's kind
404 not_found No such site in your organization, or no such fact on that site

DELETE /sites/{siteId}/facts/{factId}

Remove a fact. A manual or api fact (one a person or POST created) is hard-deleted. An extracted fact (crawl, schema_org, google_business) is dismissed instead — kept but excluded from GET, so a later extraction run can't bring it back.

Path parameters

Parameter Type Description
siteId integer The site's ID
factId string (UUID) The fact's ID, from GET

Request

curl -s -X DELETE "https://new.metamonster.ai/api/v1/sites/25/facts/9d2e1c40-1111-4a2b-8c3d-000000000001" \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{ "data": { "mode": "deleted" } }

mode is "deleted" or "dismissed" depending on the fact's source (see above).

Errors

Status When
400 invalid_request factId isn't a valid UUID
404 not_found No such site in your organization, or no such fact on that site

Full examples

A testimonial:

{
  "id": "6f1e6f2a-9b3e-4c8a-8f0a-4a2c6d1f9b10",
  "kind": "testimonial",
  "key": null,
  "data": {
    "quote": "MetaMonster cut our content backlog in half in a month.",
    "author_name": "Jamie Rivera",
    "author_title": "Head of Marketing",
    "author_company": "Northwind Co.",
    "rating": 5,
    "date": "2026-06-01",
    "platform": "site"
  },
  "source": "crawl",
  "source_url": "https://example.com/testimonials",
  "verified": true,
  "status": "active",
  "citation_count": 1,
  "last_verified_at": "2026-09-10T08:00:00Z",
  "in_sheet": true,
  "created_at": "2026-08-20T10:00:00Z",
  "updated_at": "2026-08-20T10:00:00Z"
}

An identity:

{
  "id": "3a7c2e10-4444-4d5e-9a1b-000000000002",
  "kind": "identity",
  "key": "founding_year",
  "data": { "value": "2014" },
  "source": "api",
  "source_url": null,
  "verified": false,
  "status": "active",
  "citation_count": 0,
  "last_verified_at": null,
  "in_sheet": true,
  "created_at": "2026-09-02T12:00:00Z",
  "updated_at": "2026-09-02T12:00:00Z"
}