Dashboards
Custom dashboards of cards built from the metrics catalog (audits, tasks, HACCP, schedule…). List and read dashboards, get computed card data (always limited by the viewer's permissions and locations), create and edit dashboards and cards, share them with colleagues or the whole company (dashboards.company).
GETList dashboards
Dashboards visible to the acting user: own, shared with them and published to the whole company, in the user's tab order.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_list · read-only |
Query parameters
include_hidden
boolean
false. Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards?include_hidden=false' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards?include_hidden=false', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"include_hidden":False},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'include_hidden' => false,
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_list",
"arguments": {
"include_hidden": false
}
}
}{
"data": [
{
"uuid": "2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"title": "Location overview",
"icon": "dashboard",
"description": "Weekly picture of all coffee shops",
"filters": {
"period": "30d",
"date_from": null,
"date_to": null,
"location_ids": [
12,
14
],
"checklist_ids": [],
"auditor_ids": []
},
"visibility": "company",
"company_can_edit": false,
"refresh_sec": 0,
"template": "location",
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"is_owner": false,
"permissions": {
"edit": false,
"share": false,
"delete": false
},
"updated_at": "2026-11-03T12:10:00+05:00",
"url": "https://app.jecheck.io/ui/dashboards/2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"hidden": false
}
]
}GETRetrieve a dashboard
Dashboard settings, saved filters, the acting user's permissions and the cards with their layout on a 12-column grid. Card values — dashboards.data.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_get · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_get",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"uuid": "2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"title": "Location overview",
"icon": "dashboard",
"description": "Weekly picture of all coffee shops",
"filters": {
"period": "30d",
"date_from": null,
"date_to": null,
"location_ids": [
12,
14
],
"checklist_ids": [],
"auditor_ids": []
},
"visibility": "company",
"company_can_edit": false,
"refresh_sec": 0,
"template": "location",
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"is_owner": false,
"permissions": {
"edit": false,
"share": false,
"delete": false
},
"updated_at": "2026-11-03T12:10:00+05:00",
"url": "https://app.jecheck.io/ui/dashboards/2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"widgets": [
{
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
]
}
}GETGet computed data of all cards
Values of every card (or of widget_uuids), keyed by card UUID. Computed with the dashboard filters, or with the filters passed here (temporary, not saved). Data is always limited by the acting user's permissions; a card the user may not see returns {"error": "...", "message": "..."}.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_data · read-only |
Path parameters
uuid
uuid
Required Query parameters
widget_uuids
array<string>
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data?period=7d' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data?period=7d', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"period":"7d"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'period' => '7d',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_data",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"period": "7d"
}
}
}{
"data": {
"7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d": {
"kind": "value",
"value": 82.4,
"previous": 79.1,
"unit": "%",
"meta": {
"from": "2026-10-04",
"to": "2026-11-03"
}
}
}
}GETGet computed data of a card
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_widgets_data · read-only |
Path parameters
uuid
uuid
Required widget_uuid
uuid
Required Query parameters
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data?period=7d' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data?period=7d', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"period":"7d"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/data', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'period' => '7d',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_widgets_data",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"widget_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"period": "7d"
}
}
}{
"data": {
"kind": "value",
"value": 82.4,
"previous": 79.1,
"unit": "%",
"meta": {
"from": "2026-10-04",
"to": "2026-11-03"
}
}
}POSTCompute a card without saving it
Runs a card definition with the given filters — use it to try a spec before adding the card.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_preview |
Request body
spec
object
Required dashboards.catalog for metric, dimension, list and type keys.
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/preview' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"spec": [],
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/preview', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"spec": [],
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/preview",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"spec":[],"period":"7d","date_from":"2026-11-01","date_to":"2026-11-30"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/preview', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'spec' => [
],
'period' => '7d',
'date_from' => '2026-11-01',
'date_to' => '2026-11-30',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_preview",
"arguments": {
"spec": [],
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}
}
}{
"data": {
"kind": "value",
"value": 82.4,
"previous": 79.1,
"unit": "%",
"meta": {
"from": "2026-10-04",
"to": "2026-11-03"
}
}
}GETGet the metrics catalog
Everything a card can be built from: metric groups, metrics (unit, which direction is better, allowed dimensions, availability for the acting user), dimensions, card types and their rules, lists, periods, ready-made cards (presets) and dashboard templates.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_catalog · read-only |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards/catalog' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/catalog', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards/catalog",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards/catalog', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_catalog",
"arguments": {}
}
}{
"data": {
"groups": [
{
"key": "audits",
"label": "Audits",
"icon": "fact_check"
}
],
"dimensions": [
{
"key": "location",
"label": "Location",
"kind": "category"
}
],
"types": [
{
"key": "kpi",
"label": "Number",
"icon": "pin",
"metrics": [
1,
1
],
"dimension": false
}
],
"metrics": [
{
"key": "audits.avg_result",
"group": "audits",
"label": "Average score",
"description": "Average audit result",
"unit": "%",
"better": "up",
"dimensions": [
"time",
"location",
"checklist"
],
"snapshot": false,
"available": true,
"reason": null
}
],
"lists": [
{
"key": "tasks.overdue",
"group": "tasks",
"label": "Overdue tasks",
"description": "Open tasks past due",
"available": true,
"reason": null
}
],
"periods": [
{
"key": "30d",
"label": "30 days"
}
],
"presets": [
{
"key": "kpi_avg",
"group": "audits",
"label": "Average score",
"description": "Average audit result with trend",
"type": "kpi",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true
},
"w": 3,
"h": 2,
"available": true,
"reason": null
}
],
"templates": [
{
"key": "location",
"label": "Location overview",
"description": "Key figures of locations",
"icon": "storefront",
"presets": [
"kpi_avg"
]
}
]
}
}POSTCreate a dashboard
Creates a private dashboard of the acting user — empty, from a template (dashboards.catalog → templates) and/or with the given cards. Publish it with dashboards.share.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_create |
Request body
title
string
icon
string
description
string
template
string
networkqualityoperationslocationhaccptrainingmysterywidgets
array<object>
spec
object
Required x
integer
y
integer
w
integer
h
integer
preset
string
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"template": "network"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"template": "network"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"title":"Replace the broken fridge seal","icon":"string","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","template":"network"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'title' => 'Replace the broken fridge seal',
'icon' => 'string',
'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
'template' => 'network',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_create",
"arguments": {
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"template": "network"
}
}
}{
"data": {
"uuid": "2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"title": "Location overview",
"icon": "dashboard",
"description": "Weekly picture of all coffee shops",
"filters": {
"period": "30d",
"date_from": null,
"date_to": null,
"location_ids": [
12,
14
],
"checklist_ids": [],
"auditor_ids": []
},
"visibility": "company",
"company_can_edit": false,
"refresh_sec": 0,
"template": "location",
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"is_owner": false,
"permissions": {
"edit": false,
"share": false,
"delete": false
},
"updated_at": "2026-11-03T12:10:00+05:00",
"url": "https://app.jecheck.io/ui/dashboards/2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"widgets": [
{
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
]
}
}PATCHUpdate a dashboard
Title, icon, description, saved filters and auto-refresh. Requires edit access.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_update |
Path parameters
uuid
uuid
Required Request body
title
string
icon
string | null
description
string | null
filters
object
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
refresh_sec
integer
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X PATCH 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"filters": {
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"filters": {
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}
}),
});
const { data } = await res.json();import os, requests
res = requests.patch(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"title":"Replace the broken fridge seal","icon":"string","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","filters":{"period":"7d","date_from":"2026-11-01","date_to":"2026-11-30"}},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('PATCH', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'title' => 'Replace the broken fridge seal',
'icon' => 'string',
'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
'filters' => [
'period' => '7d',
'date_from' => '2026-11-01',
'date_to' => '2026-11-30',
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_update",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"title": "Replace the broken fridge seal",
"icon": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"filters": {
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30"
}
}
}
}{
"data": {
"uuid": "2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"title": "Location overview",
"icon": "dashboard",
"description": "Weekly picture of all coffee shops",
"filters": {
"period": "30d",
"date_from": null,
"date_to": null,
"location_ids": [
12,
14
],
"checklist_ids": [],
"auditor_ids": []
},
"visibility": "company",
"company_can_edit": false,
"refresh_sec": 0,
"template": "location",
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"is_owner": false,
"permissions": {
"edit": false,
"share": false,
"delete": false
},
"updated_at": "2026-11-03T12:10:00+05:00",
"url": "https://app.jecheck.io/ui/dashboards/2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"widgets": [
{
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
]
}
}DELDelete a dashboard
Allowed to the owner; a company dashboard — also with dashboards.company.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_delete · destructive |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X DELETE 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.delete(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('DELETE', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_delete",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"deleted": true
}
}POSTDuplicate a dashboard
Creates a private copy owned by the acting user.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_duplicate |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_duplicate",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"uuid": "2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"title": "Location overview",
"icon": "dashboard",
"description": "Weekly picture of all coffee shops",
"filters": {
"period": "30d",
"date_from": null,
"date_to": null,
"location_ids": [
12,
14
],
"checklist_ids": [],
"auditor_ids": []
},
"visibility": "company",
"company_can_edit": false,
"refresh_sec": 0,
"template": "location",
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"is_owner": false,
"permissions": {
"edit": false,
"share": false,
"delete": false
},
"updated_at": "2026-11-03T12:10:00+05:00",
"url": "https://app.jecheck.io/ui/dashboards/2a1b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"widgets": [
{
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
]
}
}PUTReorder and hide dashboard tabs
Personal tab order of the acting user; hidden — dashboards to hide from the tabs.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_reorder |
Request body
uuids
array<string>
Required hidden
array<string>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X PUT 'https://app.jecheck.io/api/ext/v1/dashboards/order' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"uuids": [
"example"
],
"hidden": [
"example"
]
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/order', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"uuids": [
"example"
],
"hidden": [
"example"
]
}),
});
const { data } = await res.json();import os, requests
res = requests.put(
"https://app.jecheck.io/api/ext/v1/dashboards/order",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"uuids":["example"],"hidden":["example"]},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('PUT', 'dashboards/order', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'uuids' => [
'example',
],
'hidden' => [
'example',
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_reorder",
"arguments": {
"uuids": [
"example"
],
"hidden": [
"example"
]
}
}
}{
"data": {
"ok": true
}
}GETGet dashboard sharing
Who has access: visibility (private / company), whether everyone may edit a company dashboard, and colleagues with personal access. For the owner (and dashboards.company on company dashboards).
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_sharing · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/share' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/share', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/share",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/share', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_sharing",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"visibility": "private",
"company_can_edit": false,
"owner": {
"id": 120,
"uuid": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"name": "Daniyar Omarov"
},
"shares": [
{
"user": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"can_edit": true
}
],
"can_publish_to_company": true
}
}PUTChange the card layout
Positions and sizes of cards on the 12-column grid. Requires edit access.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_layout |
Path parameters
uuid
uuid
Required Request body
items
array<object>
Required uuid
uuid
Required x
integer
Required y
integer
Required w
integer
Required h
integer
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X PUT 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/layout' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"items": [
{
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"x": 42,
"y": 42,
"w": 42,
"h": 42
}
]
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/layout', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"items": [
{
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"x": 42,
"y": 42,
"w": 42,
"h": 42
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.put(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/layout",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"items":[{"uuid":"3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b","x":42,"y":42,"w":42,"h":42}]},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('PUT', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/layout', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'items' => [
[
'uuid' => '3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b',
'x' => 42,
'y' => 42,
'w' => 42,
'h' => 42,
],
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_layout",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"items": [
{
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"x": 42,
"y": 42,
"w": 42,
"h": 42
}
]
}
}
}{
"data": [
{
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
]
}POSTAdd a card
Adds a card (custom spec or a ready-made preset spec from the catalog). Without x/y it goes below the existing cards. Up to 60 cards per dashboard. Requires edit access.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_widgets_create |
Path parameters
uuid
uuid
Required Request body
spec
object
Required dashboards.catalog for metric, dimension, list and type keys.
x
integer
y
integer
w
integer
h
integer
preset
string
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"spec": [],
"x": 42,
"y": 42,
"w": 42
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"spec": [],
"x": 42,
"y": 42,
"w": 42
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"spec":[],"x":42,"y":42,"w":42},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'spec' => [
],
'x' => 42,
'y' => 42,
'w' => 42,
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_widgets_create",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"spec": [],
"x": 42,
"y": 42,
"w": 42
}
}
}{
"data": {
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
}PUTReplace a card definition
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_widgets_update |
Path parameters
uuid
uuid
Required widget_uuid
uuid
Required Request body
spec
object
Required dashboards.catalog for metric, dimension, list and type keys.
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X PUT 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"spec": []
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"spec": []
}),
});
const { data } = await res.json();import os, requests
res = requests.put(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"spec":[]},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('PUT', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'spec' => [
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_widgets_update",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"widget_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"spec": []
}
}
}{
"data": {
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg"
}
}DELDelete a card
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_widgets_delete · destructive |
Path parameters
uuid
uuid
Required widget_uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X DELETE 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data } = await res.json();import os, requests
res = requests.delete(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('DELETE', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_widgets_delete",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"widget_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"deleted": true
}
}POSTCopy a card to another dashboard
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | dashboards_widgets_copy |
Path parameters
uuid
uuid
Required widget_uuid
uuid
Required Request body
target_uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/copy' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"target_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/copy', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"target_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/copy",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"target_uuid":"3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/copy', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'target_uuid' => '3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_widgets_copy",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"widget_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"target_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"uuid": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "library",
"preset": "kpi_avg",
"dashboard_uuid": "9f8e7d6c-5b4a-4c3d-8e2f-1a0b9c8d7e6f"
}
}POSTBuild a card from a description (AI)
AI turns a request in plain words ("average score by location for 90 days") into a card definition and computes it. Nothing is saved — add it with dashboards.widgets.create. Daily AI limits apply.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | ai |
| MCP tool | dashboards_ai_card |
Request body
prompt
string
Required spec
object
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/ai/card' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"prompt": "string",
"spec": [],
"period": "7d",
"date_from": "2026-11-01"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/ai/card', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"prompt": "string",
"spec": [],
"period": "7d",
"date_from": "2026-11-01"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/ai/card",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"prompt":"string","spec":[],"period":"7d","date_from":"2026-11-01"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/ai/card', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'prompt' => 'string',
'spec' => [
],
'period' => '7d',
'date_from' => '2026-11-01',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_ai_card",
"arguments": {
"prompt": "string",
"spec": [],
"period": "7d",
"date_from": "2026-11-01"
}
}
}{
"data": {
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"explanation": "Average audit score with comparison to the previous period",
"size": {
"w": 3,
"h": 2
},
"data": {
"kind": "value",
"value": 82.4,
"previous": 79.1,
"unit": "%",
"meta": {
"from": "2026-10-04",
"to": "2026-11-03"
}
}
}
}POSTDraft a dashboard from a description (AI)
Returns a draft (title, cards and layout) — nothing is saved; pass widgets to dashboards.create.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | ai |
| MCP tool | dashboards_ai_dashboard |
Request body
prompt
string
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/ai/dashboard' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"prompt": "string"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/ai/dashboard', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"prompt": "string"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/ai/dashboard",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"prompt":"string"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/ai/dashboard', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'prompt' => 'string',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_ai_dashboard",
"arguments": {
"prompt": "string"
}
}
}{
"data": {
"title": "Kitchen quality",
"icon": "restaurant",
"explanation": "Scores, failed questions and overdue tasks",
"widgets": [
{
"spec": {
"v": 1,
"type": "kpi",
"metrics": [
"audits.avg_result"
],
"compare": true,
"title": "Average score"
},
"x": 0,
"y": 0,
"w": 3,
"h": 2,
"source": "ai"
}
]
}
}POSTExplain card data (AI)
A short explanation of what the card shows for the acting user's data and filters.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | ai |
| MCP tool | dashboards_ai_explain |
Path parameters
uuid
uuid
Required widget_uuid
uuid
Required Request body
period
string
custom needs date_from and date_to.
7d30d90d12mcustomdate_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/explain' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30",
"location_ids": [
12,
14
]
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/explain', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30",
"location_ids": [
12,
14
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/explain",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"period":"7d","date_from":"2026-11-01","date_to":"2026-11-30","location_ids":[12,14]},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'dashboards/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/widgets/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/explain', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'period' => '7d',
'date_from' => '2026-11-01',
'date_to' => '2026-11-30',
'location_ids' => [
12,
14,
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dashboards_ai_explain",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"widget_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"period": "7d",
"date_from": "2026-11-01",
"date_to": "2026-11-30",
"location_ids": [
12,
14
]
}
}
}{
"data": {
"text": "The average score grew from 79% to 82%, mostly thanks to Abay Ave."
}
}