Field envelopes
Every leaf value in a source envelope — name, head count, description, anything — is wrapped in the same FieldEnvelope shape. There is no field on ABM.dev that returns a bare string with no provenance. This page is the contract.
The shape
{
"value": "Monzo Bank Limited",
"source": "companies-house",
"sources_observed": ["companies-house", "linkedin", "perplexity"],
"confidence": 0.97,
"rationale": "Three sources agree on the registered legal name. Companies House is canonical for UK registrations.",
"citations": [
"https://find-and-update.company-information.service.gov.uk/company/09446231"
],
"as_of_date": "2024-11-01",
"observed_at": "2026-05-14T09:21:00Z",
"volatility_class": "slow",
"privacy_class": "public_record",
"conflicts": [
{
"value": "Monzo Bank",
"source": "perplexity",
"confidence": 0.82,
"citations": ["https://en.wikipedia.org/wiki/Monzo"],
"as_of_date": "2024-08-15"
}
]
}The TypeScript and Python SDKs (when Plan 6 ships them) will expose this as a generic FieldEnvelope<T> where T is the underlying value type — string, number, enum, nested object.
Field by field
| Field | Type | What it carries |
|---|---|---|
| value | T | The winning value. Typed (string, integer, enum, nested object). Null only when no source produced a defensible answer. |
| source | string | The source that won — e.g. companies-house, linkedin, perplexity, tavily, synthesis. When two sources agreed equally, the more authoritative one wins. |
| sources_observed | string[] | Every source that produced a value for this field, agreement or not. Useful for auditing breadth of coverage. |
| confidence | number | Between 0 and 1. How sure we are, given everything we looked at. See Confidence, citations, conflicts for bands. |
| rationale | string | One-line explanation of why this value won. Read by the audit log and the approval surface. |
| citations | string[] | URLs we actually pulled the value from. No citations, no claim. Click through and audit. |
| as_of_date | date | ISO date — when the fact was true in the world. A registered name from 2015 has as_of_date: 2015-01-23 even if we checked it yesterday. |
| observed_at | timestamp | ISO timestamp — when we last verified the value. Drives staleness checks. |
| volatility_class | enum | slow (legal name, founding year), steady (head count, tech stack), volatile (open roles, recent news). Tells your scheduler what’s worth re-fetching. |
| privacy_class | enum | public_record, derived_inference, personal_data, special_category, regulated. Helps your downstream workflows route values into the right tooling. |
| conflicts | ConflictValue[] | When two sources disagreed, we kept the loser here with its own citation. You decide whether to override the winner. |
Four pieces of provenance, four reasons
Two dates, not one
as_of_date tells you when the fact was true; observed_attells you when we last looked. A registered name hasn’t changed since 2015 — we still re-checked yesterday. Both matter to a downstream decision-maker.
Volatility, not freshness alone
A monthly re-check on legal name is wasted money. A monthly re-check on head count is barely enough. The volatility class is how your scheduler tells the two apart.
Conflicts preserved
Other enrichment APIs collapse disagreement silently. We don’t. The runner-up is in conflicts[] with its own citation. If your domain knowledge says the loser is right, you have everything you need to override.
Privacy class as a routing key
personal_data and special_category tell your pipelines “send this through the consented- marketing channel, not the lead-router.” The shape doesn’t make the choice for you — it makes the choice possible.
Where you’ll see them
Source v2 only — for now
/v1/enrichments/{id}/source is wrapped in this envelope. Legacy /v1/enrichments/{id} still returns the flatresult_data shape during the migration period; new code should target /source.Research-angle results carry the same envelope shape — same confidence, same citations, same dates. Destination values carry a slightly different shape (they record the composition inputs instead of the winning source) but the same provenance contract.