AI Quality Suggestions API
AI Quality Suggestions generate draft quality checks from a product's schema,
column profiling data, and existing check coverage. Suggestions stay inert until
a reviewer accepts them. Accepted suggestions create real QualityCheck rows
and link those checks back to the product.
All endpoints are served under /api/v1.0/ai. Paths below omit that prefix.
The API is feature-gated by ai.quality_suggestion_enabled.
Endpoint Overview
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /products/{product_id}/quality/suggestions | Generate and persist pending AI quality-check suggestions for a product. |
| GET | /products/{product_id}/quality/suggestions | List persisted suggestions for a product. |
| PUT | /quality/suggestions/{suggestion_id}/review | Accept or reject one suggestion. |
| POST | /quality/suggestions/bulk-review | Accept or reject multiple suggestions. |
Permissions
| Endpoint | Required permission |
|---|---|
| Generate suggestions | product:edit on {product_id} |
| List suggestions | product:view on {product_id} |
| Review one suggestion | product:edit on the suggestion's product |
| Bulk review | product:edit on every product represented by suggestion_ids |
Bulk review first verifies that every suggestion id exists. If any id is
missing, the endpoint returns 404 before applying reviews.
Suggestion Generation
POST /products/{product_id}/quality/suggestions
Content-Type: application/json
{
"max_suggestions": 10
}
max_suggestions must be between 5 and 10; the default is 10.
The service builds LLM context from:
- Product field metadata, including field name, data type, nullability, and field descriptions.
- Column profile statistics, including row count, null ratio, distinct count, min/max, and top values when available.
- Existing non-deprecated quality checks linked to the product, so duplicate recommendations can be avoided.
The response contains only suggestions that passed the backend filters.
{
"product_id": "6d1506b3-41b8-4ce0-8a7f-057c7bb80c07",
"total_suggestions": 2,
"suggestions": [
{
"id": "5e4f58f6-4da3-46ea-9d19-7a4dd93186ff",
"product_id": "6d1506b3-41b8-4ce0-8a7f-057c7bb80c07",
"space_id": "a186c40f-febd-4623-a481-ff7fc7043714",
"check_name": "Customer email should be present",
"check_type": "null_check",
"configuration": {
"field_name": "email"
},
"threshold_config": {},
"field_name": "email",
"reasoning": "Email is a key customer contact field and should not be null.",
"confidence": "high",
"confidence_score": 0.91,
"status": "pending",
"accepted_check_id": null,
"reviewed_by_id": null,
"reviewed_at": null,
"created_at": "2026-06-26T13:45:22.419000Z"
}
]
}
Generation logs an AI interaction with feature: "quality_check_generation" and
action: "suggest_checks". The endpoint response does not include an AI log id.
Structured Output Contract
The LLM response is contract-validated before suggestions are stored. The
backend accepts either a root list or an object with one of these wrapper keys:
suggestions, checks, or quality_checks.
Each LLM suggestion has this shape:
{
"check_name": "Order total should be non-negative",
"check_type": "range_check",
"field_name": "order_total",
"configuration": {
"field_name": "order_total"
},
"threshold_config": {
"min": 0
},
"confidence": 0.86,
"reasoning": "Negative order totals usually indicate refund handling or ingestion defects."
}
Supported check_type values are:
| Check type | Typical use |
|---|---|
null_check | Required fields. |
uniqueness | Keys and unique identifiers. |
range_check | Numeric minimum/maximum checks. |
freshness_check | Timeliness checks for date/time fields. |
pattern_check | Regex or format checks. |
enum_check | Allowed-value checks. |
sql_condition | Custom SQL conditions. |
Backend filtering rules:
- Unknown
check_typevalues are skipped. - Suggestions with
confidence < 0.5are skipped. confidence_scoreis clamped to0.0..1.0.confidenceis bucketed ashighfor scores>= 0.8,mediumfor scores>= 0.5, andlowbelow that threshold. Low-confidence suggestions are normally filtered out by the0.5persistence threshold.configurationandthreshold_configare parsed through the same typed quality-check payload parsers used by runtime quality checks.
If the AI output contract fails, the service uses a controlled fallback that can return zero persisted suggestions instead of storing malformed checks.
List Suggestions
GET /products/{product_id}/quality/suggestions?status=pending&skip=0&limit=50
Query parameters:
| Parameter | Notes |
|---|---|
status | Optional status filter. Common values are pending, accepted, and rejected. |
skip | Offset, default 0, minimum 0. |
limit | Page size, default 50, range 1..200. |
Responses are sorted by confidence_score descending. The endpoint returns a
JSON array and does not include a total count in the response body.
Review One Suggestion
PUT /quality/suggestions/{suggestion_id}/review
Content-Type: application/json
{
"action": "accepted"
}
action must be accepted or rejected.
Review side effects:
| Action | Side effect |
|---|---|
accepted | Creates a real QualityCheck, links it to the product, sets accepted_check_id, and records reviewer metadata. |
rejected | Updates the suggestion status and reviewer metadata without creating a check. |
Accepted quality checks inherit:
namefromcheck_name.check_type,configuration, andthreshold_configfrom the suggestion.space_idfrom the suggestion.descriptionasAI-suggested: {reasoning}when reasoning exists.
The endpoint returns the updated suggestion.
Bulk Review
POST /quality/suggestions/bulk-review
Content-Type: application/json
{
"suggestion_ids": [
"5e4f58f6-4da3-46ea-9d19-7a4dd93186ff",
"bff9155b-61e9-4bda-88db-d85b2a7722d4"
],
"action": "accepted"
}
Response:
{
"updated_count": 2,
"action": "accepted"
}
Bulk review applies the same side effects as single review. An empty
suggestion_ids list is valid and returns updated_count: 0.
Failure Cases
| Status | Cause |
|---|---|
400 | Bulk review received an invalid review action after request validation. |
403 | Feature gate is disabled, the user is not authenticated, or the caller lacks product permissions. |
404 | A suggestion id does not exist, or the product/suggestion cannot be resolved for permission checks. |
422 | Request validation failed, such as max_suggestions outside 5..10, invalid UUID, invalid pagination range, or action outside `accepted |
500 | Unexpected AI provider, prompt rendering, database, or quality-check creation failure. |
Generation can legitimately return total_suggestions: 0 when existing checks
already cover the product, the product has limited schema/profile context, the
LLM returns only low-confidence suggestions, or the structured output contract
falls back after invalid AI output.