The public data model
Five shapes cross the public boundary: the page record, the corpus status object, the capability status manifest, the error envelope, and the event envelope from the published webhook contract. Everything else — people, companies, opportunities, follow-ups — is a product concept with documentation pages, not an object any public endpoint returns.
The page record#
This is the one you will handle most. It is returned by search (with a score added), by the list route, and by the page route (with related and, when asked, body added). One shape everywhere, because one function builds it.
{
"id": "D0032",
"kind": "developer",
"url": "https://connectbyjbrh.com/developers/data-model-public/",
"markdown": "https://connectbyjbrh.com/developers/data-model-public/index.md",
"title": "The public data model",
"description": "…", // the meta description
"summary": "…", // the answer-first paragraph
"status": "available", // one of five words
"audiences": ["developer"], // owner | customer | both | developer
"channels": [], // empty unless the page is channel-specific
"updated": "2026-09-10",
"related": ["/developers/entity-ids/", "…"], // page route only
"body": "# The public data model\n…", // page route, body=true
"body_format": "markdown", // or "unavailable"
"score": 12.804 // search route only
}related holds site-relative paths while url and markdown are absolute. That asymmetry is worth handling once in your client rather than discovering it in a link resolver.
The other four#
| Shape | Route | Fields |
|---|---|---|
| Corpus status | /api/public/docs/status | product, operator, version, generated, statuses, capabilities, documentation.pages, documentation.by_kind |
| Capability manifest | /docs-data/status.json, or /api/public/docs/manifest/status | statuses — the vocabulary — and capabilities — the map of capability to status |
| Error envelope | Any failing public route | error.code, error.message. Codes seen here: rate_limited, not_found |
| Event envelope | The published webhook contract | id, type, occurredAt, workspaceId, data |
The error envelope is always the same object, which means a client can parse failures without branching on the route it called. error.code is a stable string to switch on; error.message is prose for a person and may be reworded.
How they relate#
- A page record points at its Markdown alternate by URL and at other pages by path. Nothing points back; the graph is one-directional and cycles are ordinary.
- The capability manifest and a page record meet on the status word. A page's
statusis one of the five keys in the manifest'sstatusesmap, which is how a client can render the word with its full definition. - The corpus status object embeds the capability manifest's two maps, so one request gets both the vocabulary and the per-capability values.
- The event envelope shares nothing with the documentation shapes. Its
workspaceIdis workspace data, and no documentation object carries one.
There is no pagination object anywhere in this list. The list route takes a limit up to 1,000 and returns a plain array with a count; the corpus is small enough that a cursor would be ceremony.
What is deliberately not a public object#
Connect's own records — Person, Company, Identity, Opportunity, Support Case, Follow-up, Memory, Knowledge, Fact — are real, documented concepts with pages of their own under relationships and elsewhere. None of them is returned by a public endpoint, and none has a published field list in this corpus.
That is a boundary, not an omission. Those records live inside a workspace behind three independent layers of isolation, and publishing a field list would create the expectation of an endpoint that does not exist. The only place workspace-shaped data appears in any public description is the event envelope's data object — and that carries identifiers and a reason, not a record.
The practical consequence for a client: if you need business data, you are not on the public developer surface, and the documentation you want is the product documentation rather than this section.
Questions#
Will new fields appear on a page record?
They can, and they are additive. Ignore what you do not recognise. Nothing documented here is removed without the change appearing in the changelog.
Why does the search result carry score but the list result not?
Because a list has no query to be relevant to. The list route returns records in path order, which is stable and makes a diff between two fetches readable.
Is body_format ever anything other than markdown?
It is unavailable when the Markdown alternate could not be read. The body is then an empty string rather than absent, so a client that reads both fields can tell a missing representation from an empty page.