Validation API
Overview
The Validation API runs SDAC analyses for a report and returns a normalized issue list designed for dashboards, widgets, and triage views.
Authentication
Widget clients call the same-origin proxy. Direct APIM callers must use an environment-published route and send:
Authorization: Bearer {access_token}Ocp-Apim-Subscription-Key: {subscription_key}
See Authentication for the full header contract.
Endpoint
| Attribute | Value |
|---|---|
| Endpoint | POST /api/ingestion/sdac/validate |
| Method | POST |
| Content-Type | application/json |
| Response | JSON |
Request
{
"reportId": "8201EDC2-2EDE-4CA1-AF44-D0F5AA185CDB",
"forceRefresh": false
}
| Field | Type | Required | Description |
|---|---|---|---|
reportId | UUID string | Yes | Uploaded SDAC report identifier |
forceRefresh | boolean | No | Accepted for compatibility. The current route validates the field but does not vary execution based on it |
Response
{
"reportId": "8201EDC2-2EDE-4CA1-AF44-D0F5AA185CDB",
"districtName": "Maplewood Richmond Heights",
"quarter": "Q3",
"totalRecords": 21,
"issues": [
{
"id": 1,
"priority": "high",
"title": "FRINGE: Speech-Language Pathologist",
"description": "Fringe rate exceeds the expected range after position-level aggregation.",
"amount": 5300,
"category": "FRINGE",
"recordId": 16,
"positionLabel": "Speech-Language Pathologist",
"mainRowNumber": 16,
"linkedRecordIds": [16, 39],
"occupants": ["Jordan Williams", "Avery Lee"],
"reasons": ["High fringe rate", "Split occupancy across linked rows"],
"confidence": "HIGH"
}
],
"summary": {
"errorCount": 2,
"warningCount": 1,
"passedCount": 4,
"analysisTime": 1843
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
reportId | UUID string | Report that was validated |
districtName | string | District display name |
quarter | string | Reporting quarter |
totalRecords | number | Canonical record or position count used by the response |
issues | array | Normalized issues sorted by priority |
summary.errorCount | number | Total errors across completed analyses |
summary.warningCount | number | Total warnings across completed analyses |
summary.passedCount | number | Current aggregate returned by the route. When any errors or warnings exist, the handler subtracts one from summary.completed rather than counting clean analyses individually |
summary.analysisTime | number | Total execution time in milliseconds |
Issue Fields
| Field | Description |
|---|---|
id | Stable issue row identifier within the response payload |
priority | high, medium, or low |
title | Short category-and-target label |
description | Human-readable issue summary |
amount | Optional numeric amount associated with the issue |
category | Analysis category that produced the issue |
recordId | Primary linked record identifier when the issue is tied to a specific row or position |
positionLabel | Position-first label when available |
mainRowNumber | Main-roster row number when the issue maps to a canonical position row |
linkedRecordIds | Related rows that contributed to the finding |
occupants | Occupant names associated with the flagged position |
reasons | Structured reasons returned by the underlying analysis |
confidence | Confidence value when position-level analysis provides one |
Error Cases
| Status | Description |
|---|---|
| 400 | Invalid request body |
| 401 | Missing or expired bearer token |
| 403 | Invalid subscription key or insufficient scope |
| 404 | Report not found |
| 500 | Validation failed |
Side Effects
- The endpoint runs SDAC analyses for the requested report and assembles a normalized issue list.
- The current handler reruns ingestion analyses regardless of whether
forceRefreshis omitted or set. - This route does not create a new report or a chat conversation.
Example
curl -X POST "$WIDGET_BASE_URL/api/ingestion/sdac/validate" \
-H "Content-Type: application/json" \
-d '{
"reportId": "8201EDC2-2EDE-4CA1-AF44-D0F5AA185CDB"
}'
Operational Notes
- This endpoint is the fastest way to populate a review queue or widget issue pane.
- For narrative, conversational follow-up on the same report, use the Chat API.
- For header metadata only, use the lighter Report Info API.