Automation
Closed-loop automation: scenarios that turn audit violations into corrective tasks (who fixes, deadline, photo "after", confirmation, reminders, escalation), and the loop steps of such tasks — upload a photo "after", submit, accept or return. Scenarios require automation.manage and the paid feature automation.
GET List automation scenarios
GET /automation/scenarios
Token scope read
Permission
automation.manage
MCP tool automation_scenarios_list · read-only
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/automation/scenarios' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/scenarios', {
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/automation/scenarios",
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', 'automation/scenarios', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_scenarios_list",
"arguments": {}
}
}
{
"data": [
{
"id": 5,
"name": "Standard",
"is_default": true,
"definition": {
"v": 1,
"steps": [
{
"type": "assign",
"to": "responsible_role"
},
{
"type": "condition",
"field": "weight",
"op": "gte",
"value": 3,
"then": [
{
"type": "deadline",
"hours": 4
},
{
"type": "require_photo"
},
{
"type": "require_confirmation",
"by": "managers"
}
],
"else": [
{
"type": "deadline",
"hours": 24
},
{
"type": "require_photo"
}
]
}
]
},
"checklists": [
{
"id": 101,
"name": "Kitchen daily check"
}
],
"created_at": "2026-09-01T10:00:00+05:00",
"updated_at": "2026-10-20T09:00:00+05:00"
}
]
}
GET Retrieve a scenario
GET /automation/scenarios/{id}
Token scope read
Permission
automation.manage
MCP tool automation_scenarios_get · read-only
Path parameters
id
integer
Required
Scenario id.
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/automation/scenarios/42' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/scenarios/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/automation/scenarios/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', 'automation/scenarios/42', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_scenarios_get",
"arguments": {
"id": 42
}
}
}
{
"data": {
"id": 5,
"name": "Standard",
"is_default": true,
"definition": {
"v": 1,
"steps": [
{
"type": "assign",
"to": "responsible_role"
},
{
"type": "condition",
"field": "weight",
"op": "gte",
"value": 3,
"then": [
{
"type": "deadline",
"hours": 4
},
{
"type": "require_photo"
},
{
"type": "require_confirmation",
"by": "managers"
}
],
"else": [
{
"type": "deadline",
"hours": 24
},
{
"type": "require_photo"
}
]
}
]
},
"checklists": [
{
"id": 101,
"name": "Kitchen daily check"
}
],
"created_at": "2026-09-01T10:00:00+05:00",
"updated_at": "2026-10-20T09:00:00+05:00"
}
}
POST Create a scenario
POST /automation/scenarios
The definition is validated by the same engine as in the web editor; errors come back as validation_failed on definition.
Token scope write
Permission
automation.manage
Plan feature automation
MCP tool automation_scenarios_create
Request body
name
string
Required
Scenario name.
Maximum length 255.
definition
object
Required
Block tree {"steps": [...]}. Action blocks: assign, deadline, require_photo, require_confirmation, remind, escalate, group, ai_text, ai_verify, digest, skip; condition blocks on weight, section, checklist_question, department, is_repeat, audit_score with then / else branches; assign targets: responsible_role, role, managers, auditor, user, team. See automation.presets for complete examples.
is_default
boolean
Use for checklists without their own scenario.
checklist_ids
array<integer>
Checklists that use this scenario (replaces the list).
Responses
Status Description
201 Created
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage, is read-only, or the plan has no automation
422 validation_failed — Invalid parameters — see error.fields
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/scenarios' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/scenarios', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}),
});
const { data } = await res.json();
import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/automation/scenarios",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"name":"Replace the broken fridge seal","definition":[],"is_default":True,"checklist_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', 'automation/scenarios', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'name' => 'Replace the broken fridge seal',
'definition' => [
],
'is_default' => true,
'checklist_ids' => [
12,
14,
],
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_scenarios_create",
"arguments": {
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}
}
}
{
"data": {
"id": 5,
"name": "Standard",
"is_default": true,
"definition": {
"v": 1,
"steps": [
{
"type": "assign",
"to": "responsible_role"
},
{
"type": "condition",
"field": "weight",
"op": "gte",
"value": 3,
"then": [
{
"type": "deadline",
"hours": 4
},
{
"type": "require_photo"
},
{
"type": "require_confirmation",
"by": "managers"
}
],
"else": [
{
"type": "deadline",
"hours": 24
},
{
"type": "require_photo"
}
]
}
]
},
"checklists": [
{
"id": 101,
"name": "Kitchen daily check"
}
],
"created_at": "2026-09-01T10:00:00+05:00",
"updated_at": "2026-10-20T09:00:00+05:00"
}
}
PATCH Update a scenario
PATCH /automation/scenarios/{id}
Partial update; definition replaces the whole block tree.
Token scope write
Permission
automation.manage
Plan feature automation
MCP tool automation_scenarios_update
Path parameters
id
integer
Required
Scenario id.
Request body
name
string
Scenario name.
Maximum length 255.
definition
object
Block tree {"steps": [...]}. Action blocks: assign, deadline, require_photo, require_confirmation, remind, escalate, group, ai_text, ai_verify, digest, skip; condition blocks on weight, section, checklist_question, department, is_repeat, audit_score with then / else branches; assign targets: responsible_role, role, managers, auditor, user, team. See automation.presets for complete examples.
is_default
boolean
Use for checklists without their own scenario.
checklist_ids
array<integer>
Checklists that use this scenario (replaces the list).
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage, is read-only, or the plan has no automation
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X PATCH 'https://app.jecheck.io/api/ext/v1/automation/scenarios/42' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/scenarios/42', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}),
});
const { data } = await res.json();
import os, requests
res = requests.patch(
"https://app.jecheck.io/api/ext/v1/automation/scenarios/42",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"name":"Replace the broken fridge seal","definition":[],"is_default":True,"checklist_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('PATCH', 'automation/scenarios/42', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'name' => 'Replace the broken fridge seal',
'definition' => [
],
'is_default' => true,
'checklist_ids' => [
12,
14,
],
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_scenarios_update",
"arguments": {
"id": 42,
"name": "Replace the broken fridge seal",
"definition": [],
"is_default": true,
"checklist_ids": [
12,
14
]
}
}
}
{
"data": {
"id": 5,
"name": "Standard",
"is_default": true,
"definition": {
"v": 1,
"steps": [
{
"type": "assign",
"to": "responsible_role"
},
{
"type": "condition",
"field": "weight",
"op": "gte",
"value": 3,
"then": [
{
"type": "deadline",
"hours": 4
},
{
"type": "require_photo"
},
{
"type": "require_confirmation",
"by": "managers"
}
],
"else": [
{
"type": "deadline",
"hours": 24
},
{
"type": "require_photo"
}
]
}
]
},
"checklists": [
{
"id": 101,
"name": "Kitchen daily check"
}
],
"created_at": "2026-09-01T10:00:00+05:00",
"updated_at": "2026-10-20T09:00:00+05:00"
}
}
DEL Delete a scenario
DELETE /automation/scenarios/{id}
Checklists that used it fall back to the default scenario.
Token scope write
Permission
automation.manage
Plan feature automation
MCP tool automation_scenarios_delete · destructive
Path parameters
id
integer
Required
Scenario id.
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage, is read-only, or the plan has no automation
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X DELETE 'https://app.jecheck.io/api/ext/v1/automation/scenarios/42' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/scenarios/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/automation/scenarios/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', 'automation/scenarios/42', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_scenarios_delete",
"arguments": {
"id": 42
}
}
}
{
"data": {
"deleted": true
}
}
GET List scenario templates
GET /automation/presets
Ready-made scenarios with complete definitions, plus the catalog of block types the editor supports.
Token scope read
Permission
automation.manage
MCP tool automation_presets · read-only
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/automation/presets' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/presets', {
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/automation/presets",
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', 'automation/presets', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_presets",
"arguments": {}
}
}
{
"data": {
"presets": [
{
"key": "standard",
"name": "Standard",
"description": "Critical — 4 hours, photo and confirmation; others — 24 hours and photo.",
"definition": {
"v": 1,
"steps": [
{
"type": "assign",
"to": "responsible_role"
},
{
"type": "condition",
"field": "weight",
"op": "gte",
"value": 3,
"then": [
{
"type": "deadline",
"hours": 4
},
{
"type": "require_photo"
},
{
"type": "require_confirmation",
"by": "managers"
}
],
"else": [
{
"type": "deadline",
"hours": 24
},
{
"type": "require_photo"
}
]
}
]
}
}
],
"actions": [
"assign",
"deadline",
"require_photo",
"require_confirmation",
"remind",
"escalate",
"group",
"ai_text",
"ai_verify",
"digest",
"skip"
],
"condition_fields": [
"weight",
"section",
"checklist_question",
"department",
"is_repeat",
"audit_score"
],
"assign_to": [
"responsible_role",
"role",
"managers",
"auditor",
"user",
"team"
],
"escalate_to": [
"managers",
"role",
"user",
"admins"
]
}
}
POST Preview a scenario on an audit
POST /automation/preview
Dry run: what the (possibly unsaved) definition would do with each violation of a completed audit — no tasks are created.
Token scope write
Permission
automation.manage
Plan feature automation
MCP tool automation_preview
Request body
audit_id
integer
Required
Completed audit id.
definition
object
Required
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Token lacks automation.manage, is read-only, or the plan has no automation
422 validation_failed — Invalid parameters — see error.fields
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/preview' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"audit_id": 42,
"definition": []
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/preview', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"audit_id": 42,
"definition": []
}),
});
const { data } = await res.json();
import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/automation/preview",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"audit_id":42,"definition":[]},
)
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', 'automation/preview', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'audit_id' => 42,
'definition' => [
],
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_preview",
"arguments": {
"audit_id": 42,
"definition": []
}
}
}
{
"data": {
"errors": [],
"items": [
{
"action": "task",
"assign": {
"to": "responsible_role"
},
"deadline_hours": 4,
"require_photo": true,
"require_confirmation": "managers",
"question": "Fridge temperature is within norm",
"section": "Kitchen",
"weight": 3,
"assignees": [
"Aigerim"
],
"fallback": false,
"is_repeat": false,
"note": null
}
]
}
}
GET Get the corrective-action loop of a task
GET /automation/loop/{uuid}
For a task created from an audit violation: the audit, deadline, whether a photo "after" and confirmation are required, photos before/after, whether the acting user may accept it, AI verdict and the loop history.
Token scope read
Permission
Any employee; results follow the token's visibility
MCP tool automation_loop_get · read-only
Path parameters
uuid
uuid
Required
Task UUID.
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/loop/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/automation/loop/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', 'automation/loop/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": "automation_loop_get",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}
{
"data": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"status": "review",
"source": "auto",
"audit": {
"id": 99812,
"uuid": "0a9b8c7d-6e5f-4a3b-8c1d-2e3f4a5b6c7d",
"checklist": "Kitchen daily check",
"score": 82,
"confirmed_at": "2026-11-03T09:40:00+05:00"
},
"deadline_at": "2026-11-03T13:40:00+05:00",
"requires_photo": true,
"requires_confirmation": true,
"has_after_photo": true,
"can_confirm": true,
"is_repeat": false,
"reopen_count": 0,
"unassigned_role": false,
"seen_again": 0,
"before_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/audits/before.jpg"
],
"after_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/tasks/images/0001/after.jpg"
],
"ai_verdict": null,
"events": [
{
"type": "submitted",
"label": "Submitted for review",
"actor": "user",
"user": "Aigerim",
"payload": {
"comment": "Seal replaced"
},
"at": "2026-11-03T12:30:00+05:00"
}
]
}
}
POST Upload a photo "after"
POST /automation/loop/{uuid}/photo
Attaches a photo of the fixed violation (JPEG/PNG/HEIC…, up to 15 MB; resized to 1920 px). Required before submit when requires_photo is true.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool automation_loop_photo
Content type multipart/form-data application/json
Path parameters
uuid
uuid
Required
Task UUID.
Request body
photo
file
Required
Image file (multipart; in MCP — object with name and content_base64).
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/photo' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-F '[email protected] '
const form = new FormData();
form.append('photo', fileInput.files[0]);
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/photo', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.JECHECK_TOKEN}` },
body: form,
});
const { data } = await res.json();
import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/photo",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
data=[],
files=[("photo", open("photo.jpg", "rb"))],
)
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', 'automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/photo', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'multipart' => [
['name' => 'photo', 'contents' => fopen('photo.jpg', 'r')],
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_loop_photo",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}
{
"data": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"status": "review",
"source": "auto",
"audit": {
"id": 99812,
"uuid": "0a9b8c7d-6e5f-4a3b-8c1d-2e3f4a5b6c7d",
"checklist": "Kitchen daily check",
"score": 82,
"confirmed_at": "2026-11-03T09:40:00+05:00"
},
"deadline_at": "2026-11-03T13:40:00+05:00",
"requires_photo": true,
"requires_confirmation": true,
"has_after_photo": true,
"can_confirm": true,
"is_repeat": false,
"reopen_count": 0,
"unassigned_role": false,
"seen_again": 0,
"before_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/audits/before.jpg"
],
"after_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/tasks/images/0001/after.jpg"
],
"ai_verdict": null,
"events": [
{
"type": "submitted",
"label": "Submitted for review",
"actor": "user",
"user": "Aigerim",
"payload": {
"comment": "Seal replaced"
},
"at": "2026-11-03T12:30:00+05:00"
}
]
}
}
POST Mark the violation as fixed
POST /automation/loop/{uuid}/submit
The executor reports the fix: the task goes to review (if confirmation is required) or is completed. A queued team task becomes the acting user's.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool automation_loop_submit
Path parameters
uuid
uuid
Required
Task UUID.
Request body
comment
string
Maximum length 500.
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 — A photo "after" is required first
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/submit' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"comment": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/submit', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"comment": "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/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/submit",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"comment":"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', 'automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/submit', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'comment' => '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": "automation_loop_submit",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"comment": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
}
}
{
"data": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"status": "review",
"source": "auto",
"audit": {
"id": 99812,
"uuid": "0a9b8c7d-6e5f-4a3b-8c1d-2e3f4a5b6c7d",
"checklist": "Kitchen daily check",
"score": 82,
"confirmed_at": "2026-11-03T09:40:00+05:00"
},
"deadline_at": "2026-11-03T13:40:00+05:00",
"requires_photo": true,
"requires_confirmation": true,
"has_after_photo": true,
"can_confirm": true,
"is_repeat": false,
"reopen_count": 0,
"unassigned_role": false,
"seen_again": 0,
"before_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/audits/before.jpg"
],
"after_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/tasks/images/0001/after.jpg"
],
"ai_verdict": null,
"events": [
{
"type": "submitted",
"label": "Submitted for review",
"actor": "user",
"user": "Aigerim",
"payload": {
"comment": "Seal replaced"
},
"at": "2026-11-03T12:30:00+05:00"
}
]
}
}
POST Accept the fix
POST /automation/loop/{uuid}/confirm
A confirmer (location manager, auditor or the one set by the scenario — see can_confirm) accepts the fix; the task is completed.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool automation_loop_confirm
Path parameters
uuid
uuid
Required
Task UUID.
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 — The acting user is not a confirmer of this task or it is not on review
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/confirm' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/confirm', {
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/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/confirm",
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', 'automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/confirm', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "automation_loop_confirm",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}
{
"data": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"status": "review",
"source": "auto",
"audit": {
"id": 99812,
"uuid": "0a9b8c7d-6e5f-4a3b-8c1d-2e3f4a5b6c7d",
"checklist": "Kitchen daily check",
"score": 82,
"confirmed_at": "2026-11-03T09:40:00+05:00"
},
"deadline_at": "2026-11-03T13:40:00+05:00",
"requires_photo": true,
"requires_confirmation": true,
"has_after_photo": true,
"can_confirm": true,
"is_repeat": false,
"reopen_count": 0,
"unassigned_role": false,
"seen_again": 0,
"before_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/audits/before.jpg"
],
"after_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/tasks/images/0001/after.jpg"
],
"ai_verdict": null,
"events": [
{
"type": "submitted",
"label": "Submitted for review",
"actor": "user",
"user": "Aigerim",
"payload": {
"comment": "Seal replaced"
},
"at": "2026-11-03T12:30:00+05:00"
}
]
}
}
POST Return the fix for rework
POST /automation/loop/{uuid}/reject
A confirmer returns the task to the executor with a reason; reminders restart.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool automation_loop_reject
Path parameters
uuid
uuid
Required
Task UUID.
Request body
reason
string
Required
Maximum length 1000.
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
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/reject' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"reason": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/reject', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"reason": "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/automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/reject",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"reason":"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', 'automation/loop/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/reject', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'reason' => '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": "automation_loop_reject",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"reason": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
}
}
{
"data": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"status": "review",
"source": "auto",
"audit": {
"id": 99812,
"uuid": "0a9b8c7d-6e5f-4a3b-8c1d-2e3f4a5b6c7d",
"checklist": "Kitchen daily check",
"score": 82,
"confirmed_at": "2026-11-03T09:40:00+05:00"
},
"deadline_at": "2026-11-03T13:40:00+05:00",
"requires_photo": true,
"requires_confirmation": true,
"has_after_photo": true,
"can_confirm": true,
"is_repeat": false,
"reopen_count": 0,
"unassigned_role": false,
"seen_again": 0,
"before_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/audits/before.jpg"
],
"after_photos": [
"https://bucket.s3.eu-central-1.amazonaws.com/tasks/images/0001/after.jpg"
],
"ai_verdict": null,
"events": [
{
"type": "submitted",
"label": "Submitted for review",
"actor": "user",
"user": "Aigerim",
"payload": {
"comment": "Seal replaced"
},
"at": "2026-11-03T12:30:00+05:00"
}
]
}
}