Audits
Conducted audits (inspections by checklist): the audit journal with filters, the result card with sections, failed questions, comments and photos, PDF reports, deletion and submitting a new audit. Visibility follows the web journal — audits of the locations where the token has audits.view.
GETList audits
The audit journal, newest first: checklist, location, auditor, result and status. status: completed — result 70% or higher, failed — below 70%, in_progress — not finished. Mystery-shopper audits have mystery: true and no auditor.
| Token scope | read |
|---|---|
| Permission |
audits.view |
| MCP tool | audits_list · read-only |
Query parameters
page
integer
1. Minimum 1.
per_page
integer
25. Value 1–100.
date_from
date
date_to
date
location_ids
array<integer>
checklist_ids
array<integer>
auditor_ids
array<integer>
status
array<string>
result_from
number
result_to
number
search
string
created_since
date-time
sort
string
date_desc. date_descdate_ascresult_ascresult_descResponses
| Status | Description |
|---|---|
| 200 | OK — a page of results with meta |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Token lacks audits.view
|
| 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/audits?date_from=2026-11-01' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/audits?date_from=2026-11-01', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
},
});
const { data, meta } = await res.json();import os, requests
res = requests.get(
"https://app.jecheck.io/api/ext/v1/audits",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"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('GET', 'audits', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'date_from' => '2026-11-01',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "audits_list",
"arguments": {
"date_from": "2026-11-01"
}
}
}{
"data": [
{
"id": 99812,
"uuid": "9a72f859-63a3-4046-9616-8aaf730073ff",
"checklist": {
"id": 5845,
"name": "Daily dining room check"
},
"location": {
"id": 12,
"name": "Abay Ave"
},
"auditor": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"mystery": false,
"status": "completed",
"result": 82.4,
"report_status": "ready",
"conducted_at": "2026-11-03T09:40:00+05:00",
"created_at": "2026-11-03T09:41:12+05:00",
"report_url": "https://app.jecheck.io/api/reports/newVersionSavePdf/9a72f859-63a3-4046-9616-8aaf730073ff"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"has_more": false
}
}GETRetrieve an audit result
The result card, calculated exactly like the PDF report: score, target and level (bad — not passed, warn — passed below target, ok — target reached / excellent), sections with their results, every answered question (result: ok, violation, na, info for unscored answers) with comments and photos, violations sorted by weight and repetition, previous audit of the same checklist at the location, the AI report if enabled, and corrective tasks created from this audit. Own audits are always visible; others need audits.view on the location.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | audits_get · read-only |
Path parameters
id
integer
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/audits/42' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/audits/42', {
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/audits/42",
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', 'audits/42', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "audits_get",
"arguments": {
"id": 42
}
}
}{
"data": {
"id": 99812,
"uuid": "9a72f859-63a3-4046-9616-8aaf730073ff",
"checklist": {
"id": 5845,
"name": "Daily dining room check"
},
"location": {
"id": 12,
"name": "Abay Ave"
},
"auditor": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"mystery": false,
"status": "completed",
"result": 82.4,
"report_status": "ready",
"conducted_at": "2026-11-03T09:40:00+05:00",
"created_at": "2026-11-03T09:41:12+05:00",
"report_url": "https://app.jecheck.io/api/reports/newVersionSavePdf/9a72f859-63a3-4046-9616-8aaf730073ff",
"scoring": "points",
"target": 85,
"level": "warn",
"failed_by": [],
"counts": {
"checked": 18,
"ok": 15,
"violations": 3,
"na": 1,
"critical": 1,
"repeats": 1,
"photos": 6
},
"previous": {
"result": 76.5,
"date": "2026-10-27",
"delta": 5.9
},
"sections": [
{
"id": 21626,
"name": "Kitchen",
"result": 71.4,
"checked": 7,
"ok": 5,
"violations": 2,
"na": 0,
"questions": [
{
"question_id": 197426,
"number": "1.2",
"text": "Fridge temperature is within the norm",
"result": "violation",
"answer": "9.1 °C",
"weight": 5,
"tier": "critical",
"repeat": 2,
"fail_all": false,
"comment": "Door seal is torn",
"photos": [
{
"url": "https://jecheck.s3.eu-west-1.amazonaws.com/audits/761/fridge.jpg",
"name": "fridge.jpg"
}
],
"files": []
}
]
}
],
"violations": [
{
"question_id": 197426,
"number": "1.2",
"text": "Fridge temperature is within the norm",
"result": "violation",
"answer": "9.1 °C",
"weight": 5,
"tier": "critical",
"repeat": 2,
"fail_all": false,
"comment": "Door seal is torn",
"photos": [
{
"url": "https://jecheck.s3.eu-west-1.amazonaws.com/audits/761/fridge.jpg",
"name": "fridge.jpg"
}
],
"files": [],
"section": "Kitchen"
}
],
"ai": {
"summary": "Cold chain is the main risk: two fridges out of range.",
"verdict": "Needs attention",
"recommendations": [
"Replace the door seal of fridge #2"
],
"plan": [
{
"priority": "high",
"action": "Replace the seal",
"owner": "Chef",
"section": "Kitchen"
}
]
},
"signature_url": null,
"geo": {
"lat": 43.23811,
"lon": 76.94572
},
"tasks": [
{
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"title": "Replace the broken fridge seal",
"status": "in_progress",
"due_date": "2026-11-04",
"question_id": 197426
}
]
}
}GETGet the PDF report link
Returns a public link to the PDF report (no login needed — share it carefully) and the online report link. ready: false — the PDF is still being generated, try again in a minute. Requires audits.export on the audit location; each call is recorded in the access log.
| Token scope | read |
|---|---|
| Permission |
audits.export |
| MCP tool | audits_pdf · read-only |
Path parameters
id
integer
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Token lacks audits.export
|
| 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/audits/42/pdf' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/audits/42/pdf', {
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/audits/42/pdf",
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', 'audits/42/pdf', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "audits_pdf",
"arguments": {
"id": 42
}
}
}{
"data": {
"ready": true,
"pdf_url": "https://app.jecheck.io/api/reports/pdf/9a72f859-63a3-4046-9616-8aaf730073ff",
"online_url": "https://app.jecheck.io/api/reports/newVersionSavePdf/9a72f859-63a3-4046-9616-8aaf730073ff"
}
}POSTSubmit an audit
Submits a conducted audit for a checklist at a location — the same processing as the mobile app: the server scores every answer by the question type and settings, calculates the result, starts the PDF report and runs automation (corrective tasks for violations). The token user becomes the auditor; the checklist must be available to them and the location must be one where they work or may view audits. yes_no questions take result (ok, violation, na); text — text; other types — value (e.g. {"number": 4.5}, {"option": "a1"}, {"options": ["a1","b2"]}, {"date": "2026-11-03"}, {"code": "4870001234567"}, {"user_id": 311}). Photos cannot be attached through the API yet.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| MCP tool | audits_create |
Request body
checklist_id
integer
Required location_id
integer
Required conducted_at
date-time
answers
array<object>
Required question_id
integer
Required checklists.get).
result
string
yes_no: ok, violation or na; na also skips a question of another type.
okviolationnatext
string
text type).
Maximum length 5000. value
object
comment
string | null
latitude
number
longitude
number
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/audits' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"checklist_id": 42,
"location_id": 12,
"conducted_at": "2026-11-03T09:00:00+05:00",
"answers": [
{
"question_id": 42,
"result": "ok",
"text": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
]
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/audits', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"checklist_id": 42,
"location_id": 12,
"conducted_at": "2026-11-03T09:00:00+05:00",
"answers": [
{
"question_id": 42,
"result": "ok",
"text": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/audits",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"checklist_id":42,"location_id":12,"conducted_at":"2026-11-03T09:00:00+05:00","answers":[{"question_id":42,"result":"ok","text":"Seal on fridge #2 is torn, temperature rises to +9 °C."}]},
)
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', 'audits', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'checklist_id' => 42,
'location_id' => 12,
'conducted_at' => '2026-11-03T09:00:00+05:00',
'answers' => [
[
'question_id' => 42,
'result' => 'ok',
'text' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
],
],
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "audits_create",
"arguments": {
"checklist_id": 42,
"location_id": 12,
"conducted_at": "2026-11-03T09:00:00+05:00",
"answers": [
{
"question_id": 42,
"result": "ok",
"text": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
]
}
}
}{
"data": {
"id": 99812,
"uuid": "9a72f859-63a3-4046-9616-8aaf730073ff",
"checklist": {
"id": 5845,
"name": "Daily dining room check"
},
"location": {
"id": 12,
"name": "Abay Ave"
},
"auditor": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"mystery": false,
"status": "completed",
"result": 82.4,
"report_status": "ready",
"conducted_at": "2026-11-03T09:40:00+05:00",
"created_at": "2026-11-03T09:41:12+05:00",
"report_url": "https://app.jecheck.io/api/reports/newVersionSavePdf/9a72f859-63a3-4046-9616-8aaf730073ff",
"scoring": "points",
"target": 85,
"level": "warn",
"failed_by": [],
"counts": {
"checked": 18,
"ok": 15,
"violations": 3,
"na": 1,
"critical": 1,
"repeats": 1,
"photos": 6
},
"previous": {
"result": 76.5,
"date": "2026-10-27",
"delta": 5.9
},
"sections": [
{
"id": 21626,
"name": "Kitchen",
"result": 71.4,
"checked": 7,
"ok": 5,
"violations": 2,
"na": 0,
"questions": [
{
"question_id": 197426,
"number": "1.2",
"text": "Fridge temperature is within the norm",
"result": "violation",
"answer": "9.1 °C",
"weight": 5,
"tier": "critical",
"repeat": 2,
"fail_all": false,
"comment": "Door seal is torn",
"photos": [
{
"url": "https://jecheck.s3.eu-west-1.amazonaws.com/audits/761/fridge.jpg",
"name": "fridge.jpg"
}
],
"files": []
}
]
}
],
"violations": [
{
"question_id": 197426,
"number": "1.2",
"text": "Fridge temperature is within the norm",
"result": "violation",
"answer": "9.1 °C",
"weight": 5,
"tier": "critical",
"repeat": 2,
"fail_all": false,
"comment": "Door seal is torn",
"photos": [
{
"url": "https://jecheck.s3.eu-west-1.amazonaws.com/audits/761/fridge.jpg",
"name": "fridge.jpg"
}
],
"files": [],
"section": "Kitchen"
}
],
"ai": {
"summary": "Cold chain is the main risk: two fridges out of range.",
"verdict": "Needs attention",
"recommendations": [
"Replace the door seal of fridge #2"
],
"plan": [
{
"priority": "high",
"action": "Replace the seal",
"owner": "Chef",
"section": "Kitchen"
}
]
},
"signature_url": null,
"geo": {
"lat": 43.23811,
"lon": 76.94572
},
"tasks": [
{
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"title": "Replace the broken fridge seal",
"status": "in_progress",
"due_date": "2026-11-04",
"question_id": 197426
}
]
}
}DELDelete an audit
Permanently deletes the audit with its answers and attachments: it disappears from the journal, analytics and reports and cannot be restored. Corrective tasks created from it stay. Requires audits.delete on the audit location.
| Token scope | write |
|---|---|
| Permission |
audits.delete |
| MCP tool | audits_delete · destructive |
Path parameters
id
integer
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Token lacks audits.delete, is read-only
|
| 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/audits/42' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/audits/42', {
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/audits/42",
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', 'audits/42', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "audits_delete",
"arguments": {
"id": 42
}
}
}{
"data": {
"deleted": true
}
}