The knowledge-source feed
Integrating a product with Forumulate? Already built for you names what exists, with the one call for each.
Any chat or answer product — Intercom, Zendesk, Crisp, Drift, Help Scout, Freshchat, Front, a retrieval pipeline you run yourself, or Chatly — can keep its index exactly in step with what you publish. The vendor is only a label; the feed is the same for all of them.
Credentials
Read-only, any one of:
an integration token with
kb.read(see Give a third party read access);a connector token of a connected chat provider;
a partner link access token with
kb:read(see Partner links and token exchange).
Syncing
GET /connector/kb/pages answers published pages, whole, as Markdown:
{
"data": [
{
"pageId": "…", "spaceId": "…", "kind": "page",
"url": "https://docs.acme.com/getting-started",
"title": "Getting started", "description": null,
"markdown": "# Getting started\n…",
"contentHash": "sha256:…",
"updatedAt": "2026-10-24T09:12:03Z",
"visibility": "public",
"freshness": { "verifiedAt": "2026-10-01T14:00:00.000Z", "ageDays": 23, "stale": false, "confidence": 0.89 },
"locale": "en"
}
],
"tombstones": [{ "pageId": "…", "spaceId": "…", "deletedAt": "…", "reason": "unpublished" }],
"page": { "limit": 50, "hasMore": false, "nextCursor": null },
"sync": { "checkpoint": "…" }
}The first call (no
since) is a full sync: every published page, no tombstones.Store
sync.checkpointverbatim and send it back assince. You get what changed after it — pages that were published or edited, and tombstones for pages that were trashed, unpublished or destroyed.page.hasMore: truemeans call again now, withsince=page.nextCursor;falsemeans you are caught up.Re-index a page only when its
contentHashchanges.freshnessandlocaleare the same valuesGET …/itemsreports for the page, computed by the same code:verifiedAtis when someone last confirmed the page is correct, or null if no one has.ageDayscounts days since that, or since the last edit if the page was never confirmed.staleis true whenageDayspasses the organization's staleness policy.confidenceruns from 0 to 1 and falls slowly over the policy window, so multiply it into your ranking. A page no one has confirmed is discounted to 80%.localeis the language declared for the page (canonical BCP-47, such aspt-BR), or null. It is never filled in from the space's default language.Confirming a page or correcting its language doesn't move it into the next sync. Refresh these values on your full re-sync.
spaceIds=narrows the call to some of the spaces the credential covers; a space it does not cover is403 space_not_granted.
Instead of polling, subscribe to kb.changed. It fires per burst of publishing with {spaceId, pageIds, cursor}; pass cursor as since. An integration token or a partner link subscribes itself — POST /connector/kb/webhook {"url": "https://…"}, no org member needed (see Give a third party read access) — and hears only its own spaces.
Seeing who reads
The studio's chat panel shows "Read by Intercom, last at …" for each integration that has read a space, from GET /orgs/{orgId}/spaces/{spaceId}/kb-readers — so a sync that went quiet is visible.
Identity in chat
A signed-in reader should not be asked who they are again by the chat widget. A widget whose vendor declares how to receive an identity token is handed one after it loads:
the organization signs a 120-second ES256 assertion for the reader —
sub,email,name, and their sign-in subject{iss, sub}when they signed in through your identity provider — withaudset to that one widget;the vendor verifies it against the organization's public keys at
GET /public/orgs/{orgId}/connector-identity/jwks.json.
Rotate the signing key with POST /orgs/{orgId}/connector-identity/rotate; the old key stays published for a day so nothing in flight fails.
Consent
Chat widgets load through the consent contract: a chat widget waits for the suite's support_chat category (a consent platform without it answers as preferences). Chatly is told to follow the page's window.__fdConsent rather than show a banner of its own.
In the API
Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go SDKs are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP agent server — its api_* family tools, or call_api. Where a CLI command or a hand-made MCP tool exists too, the last column names it. Operation names link to the API reference.
Connector Knowledge Admin
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| Who reads this space’s knowledge base, and when they last did |
| |
| Rotate the key that signs chat identity assertions |
|