List Data Validation Run Findings
Returns the per-record findings of a data validation run — which of the company’s stored records would not survive the scanned configuration, and exactly what is wrong with each one.
One finding is one record that did not cleanly adhere. Records that would
persist cleanly are counted in the run’s recordsAdhering total and produce no
finding here, so a run over a clean book returns an empty page.
Why this is a separate, paginated endpoint
GET /configuration/data-validation-runs/{runId} is a poll, made roughly
once a second, and a run over a broken book can produce tens of thousands of
findings. Carrying them on the poll would re-transfer the whole set on every
read, so the poll stays fixed-size and the findings are pulled here, page by
page, once the run has something to say.
Paging and grouping
page and pageSize are the standard 1-based pagination parameters
(pageSize defaults to 50 and is capped at 500 — a larger value is clamped,
not rejected). Findings come back oldest-first, and totalCount ignores the
pagination.
totalCount is only stable once the run is finished. Wait for the run’s
status to reach a terminal value (succeeded or failed) before sizing a
whole pull from the first page: a run still queued or running appends
findings as it scans, so page 1 of a live run can report a totalCount of 40
and page 2 report 95. Findings only ever append — they never reorder — so pages
you have already read stay valid either way.
entityType is how you group. The API returns a flat list and does not
group for you, because grouping is a presentation concern: request one entity
type at a time to build a per-type view. The filter narrows totalCount too, so
the count always describes the items beside it. An entityType this run
validated but found no problem in is a legitimate empty page; an entityType
that is not a real entity type is a 400, not an empty page — see below.
Reading a finding
extraKeys— keys the record holds that the configuration does not declare. Suspect, not necessarily fatal.violations— fields whose value would fail a write. ReadfieldPath(ordered segments) rather than splitting the legacy dottedfield; both arenull/[]for a record-level failure that names no single field.adheresis alwaysfalse. A finding exists only for a record that did not adhere, so the field carries no information here. It is part of the shape rather than omitted, and atruevalue cannot occur.
Run ids are scoped to their company: a run id belonging to another company
returns 404, exactly as an id that exists nowhere does.
How long findings stay readable
A run’s findings stay readable for as long as the run exists — nothing removes a run or its findings on a timer, and however long ago it completed this endpoint still returns them. A run’s age is never a failure: a run that exists returns its findings however long ago it finished, and no response reports a run as too old to read.
Required permission: company.configuration:export
This endpoint requires an API key created with the FMV1_CONFIGURATION_MANAGER role. See Authentication for how to create API keys with specific roles.
Authorizations
User-principal OAuth 2.0 Bearer authentication. Send a user-scoped Auth0 access token (audience = the app API audience) as Authorization: Bearer <jwt>. The request resolves to the user's identity and is authorized by their Role on the {companyId} in the path — the same role-based permissions the web app enforces. This is the path the MCP connector uses to act on a user's behalf; endpoints that accept it list both BearerAuth and ApiKeyAuth.
Path Parameters
Company identifier
The run identifier returned by POST /configuration/data-validation-runs. Runs are scoped to their company: a
run id belonging to another company returns 404, exactly as an id that
exists nowhere does.
Query Parameters
1-based page number. Defaults to the first page.
A page above 9007199254740991, or a page and pageSize whose product
skips past that many rows, is a 400 — such a page is past the end of any
collection, and the offset it asks for is not a number the database can
seek to.
1 <= x <= 9007199254740991Number of findings per page (default 50, maximum 500).
A pageSize above 500 is silently clamped to 500 rather than
rejected — it is not a 400. Read the length of items rather than
assuming you received the size you asked for, and page through the rest.
The cap exists because an unbounded page over a badly broken book would
load every finding row into one response, which is the exact cost this
endpoint is paginated to avoid.
The one exception is a pageSize above 9007199254740991, which is a 400
rather than a clamp: that is not a page size, it is a number too large for
the pagination arithmetic to be meaningful.
1 <= x <= 500Return only the findings for this entity type, and count only those in
totalCount. Omit it for every finding the run produced.
A value that is not one of the listed entity types is a 400, not an empty
page: ?entityType=Policies answering {"items":[],"totalCount":0} would
read as "none of my Policy records have a problem", which is silently wrong
on the one endpoint whose job is to report problems.
Event, Exposure, Quote, Submission, Person, Organization, Policy Response
One page of the run's findings, plus the unpaginated total
One page of a data-validation run's per-record findings, plus the total number of findings matching the request. A finding exists only for a record the scan judged NOT to adhere, so a run over a clean book returns an empty page.
The findings on this page, oldest-first
How many findings match this request IGNORING the pagination. When
entityType is sent it counts only that entity type, so it always
describes the items beside it. It is NOT any of the run's records*
counters: those count records SCANNED (clean ones included, which write no
finding at all), and none of them is broken down by entity type.
It is only stable between pages once the run has reached a terminal
status (succeeded or failed). A run still queued or running
appends findings as it scans, so page 1 can report a smaller total than a
later page of the same run. Findings only ever append and never reorder, so
already-read pages stay valid. Poll the run to a terminal status before
sizing a whole pull from the first page.
