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.POSTalways recordssource: "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"
}