Quality templates and suggestions
GET /api/v1/quality/recommendations
Read 24 templates, matching fields on accessible sites, and a summary without creating rules.
Access
Use a Bearer API key for the active workspace and runs.read permission. Writes also require a writable key and sites.write on the selected site. Only a platform operator with settings.manage, not an external key, may change platform-wide definitions. Sites and history are scoped to the current team. An agent rejects POST/PATCH/DELETE; edit definitions in the cloud.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
site_id |
query | no | Limit suggestions to one accessible site. An inaccessible site returns 404. sites and summary still cover all accessible resources. |
locale |
query | no | Language of vocabulary, suggestions, and explanations. If omitted, akmelo_locale cookie is used, otherwise ru. User-defined field names are not translated. |
No body is required. locale=ru|en selects labels and explanations; without an explicit parameter the akmelo_locale cookie is used, then Russian. Kind codes and field names are not translated.
Response 200
This is a shortened example with placeholder numeric IDs; full fields are documented below and in the downloadable OpenAPI schema.
{
"presets": [],
"sites": [],
"recommendations": [],
"summary": {
"rules_count": 3,
"site_rules_count": 0,
"global_rules_count": 3,
"active_rules_count": 3,
"findings_count": 0,
"scripts_count": 1,
"can_manage_global": false,
"can_create_rules": true
},
"scan_limit": 5000
}
| Field | Meaning |
|---|---|
presets[] |
All 24 templates: id, kind, category_id, category, title, description, benefit, example, image, params, action, and field_role |
sites[] |
Accessible sites only: ID, code, name, fields[] with code, name, type, is_required, and is_key, plus scenario count and can_manage |
recommendations[] |
Up to 200 suggestions: preset_id, site_id, matched field, populated params, reason, score, and used |
summary |
Visible rule, platform-wide rule, site-specific rule, active rule, finding, and scenario counts, plus can_manage_global and can_create_rules |
scan_limit |
Field-check record limit, currently 5000 |
availability |
Definition and report compatibility with the cloud: definitions and reports |
summary.site_rules_count excludes platform-wide rules. Summary counts are independent of UI table filters. used relates to a specific site, kind, and parameter set; it does not prevent using a card again. To create a rule, send params and preset_id to POST rules. Select the site from accessible resources and review the field match.
In the main application both availability values are supported. On an agent, definitions=unsupported means its signed snapshot does not confirm quality-definition support; update the agent/cloud, and note that local creation remains forbidden. reports=unsupported means report support has not been negotiated, pending means quality reports specifically are awaiting delivery, and supported means supported with no waiting quality queue. pending does not mean there are no findings. Results remain local while the cloud is unavailable, until delivery is acknowledged.
Behavior and limits
Lists in the example are shortened. The response contains all 24 cards. Suggestions use declared fields, with no external model. used indicates an existing rule with the same site, kind, and parameters; it does not prevent another check. Review the field and conditions before POST. can_manage reflects owner permissions; a read-only API key still cannot write.
Numeric examples retain the legacy v1 contract. Use X-Identifier-Format: uuid or the same method under /api/v2 for public UUIDs, including nested site, rule, and collection references. preset_id, category_id, and field remain string codes. Identifier formats.
See Data quality for all 24 template examples and the interface workflow. For parameter definitions, see the vocabulary.
Send the request
Set BASE to your installation URL without a trailing slash and API_KEY to a secret stored on your server. Client setup and browser JavaScript.
curl
curl --fail-with-body -X GET "$BASE/api/v1/quality/recommendations?site_id=1&locale=en" \
-H "Authorization: Bearer $API_KEY" \
-H "Accept: application/json"
Node.js · server
// Node.js server example. Save as request.mjs.
const response = await fetch(process.env.BASE + "/api/v1/quality/recommendations?site_id=1&locale=en", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
Accept: "application/json"
},
signal: AbortSignal.timeout(120000)
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
console.log(await response.json());
Python
import json
import os
import urllib.request
import urllib.error
request = urllib.request.Request(
os.environ["BASE"] + "/api/v1/quality/recommendations?site_id=1&locale=en",
method="GET",
headers={"Authorization": "Bearer " + os.environ["API_KEY"],
"Accept": "application/json"},
)
try:
with urllib.request.urlopen(request, timeout=120) as response:
print(json.load(response))
except urllib.error.HTTPError as error:
print(error.code, error.read().decode("utf-8", errors="replace"))
raise
PHP · external client
<?php
$handle = curl_init(getenv("BASE") . "/api/v1/quality/recommendations?site_id=1&locale=en");
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("API_KEY"),
"Accept: application/json",
],
]);
$content = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
if ($content === false) {
throw new RuntimeException(curl_error($handle));
}
curl_close($handle);
if ($status < 200 || $status >= 300) {
throw new RuntimeException("HTTP $status: $content");
}
print_r(json_decode($content, true, 512, JSON_THROW_ON_ERROR));
Go
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
request, err := http.NewRequest("GET", os.Getenv("BASE") + "/api/v1/quality/recommendations?site_id=1&locale=en", nil)
if err != nil { panic(err) }
request.Header.Set("Authorization", "Bearer " + os.Getenv("API_KEY"))
request.Header.Set("Accept", "application/json")
client := &http.Client{Timeout: 120 * time.Second}
response, err := client.Do(request)
if err != nil { panic(err) }
defer response.Body.Close()
content, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, content))
}
fmt.Println(string(content))
}
If the request fails
401: check the key and its expiry. 403: check permissions, read/write scope, and 2FA. 404: check the ID and workspace. 422: check fields and resource state. 429: respect Retry-After. Errors and retries.