jeCheckDevelopers
Get an API key

Analytics

Audit analytics with the same numbers as the web analytics pages: company overview, location ranking and drill-down, checklist and question statistics, top violations, auditor strictness, plan fulfilment, corrective tasks, the AI control brief and employee tests. Figures cover only the locations where the token has analytics.view. Long lists end with an item {"_truncated": N} saying how many rows were cut.

GETGet the audit overview

GET /analytics/overview

Company summary for a period with the previous period for comparison: number of audits, average score, pass rate (≥ 70%), violations, location coverage, plan fulfilment, open and overdue tasks; trend by day/week/month; score distribution; 5 best and 5 worst locations; top violations; locations without audits; ready-made insights. Start here for "how are we doing" questions.

Token scoperead
Permission analytics.view
MCP toolanalytics_overview · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/overview?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/overview?period=30d', {
  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/analytics/overview",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/overview', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_overview",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "kpis": {
      "audits": {
        "value": 18,
        "prev": 48
      },
      "avg": {
        "value": 80,
        "prev": 75.9
      },
      "pass": {
        "value": 83.3,
        "prev": 64.6
      },
      "violations": {
        "value": 28,
        "prev": 90,
        "per_audit": 1.6,
        "prev_per_audit": 1.9,
        "rate": 19.4
      },
      "coverage": {
        "value": 5,
        "total": 5,
        "prev": 5
      },
      "auditors": {
        "value": 4,
        "prev": 6
      },
      "plan": {
        "value": 33,
        "prev": 75,
        "done": 8,
        "planned": 24
      },
      "tasks": {
        "open": 37,
        "overdue": 35
      }
    },
    "trend": [
      {
        "bucket": "2026-10-05",
        "audits": 1,
        "avg": 82.4,
        "pass": 100,
        "violations": 1
      }
    ],
    "distribution": [
      {
        "label": "under 50%",
        "value": 0,
        "tone": "danger"
      }
    ],
    "best_locations": [
      {
        "id": 4638,
        "name": "Park St",
        "audits": 3,
        "avg": 86.3,
        "delta": 30.9
      }
    ],
    "worst_locations": [
      {
        "id": 4638,
        "name": "Station Sq",
        "audits": 3,
        "avg": 72.2,
        "delta": 3.4
      }
    ],
    "top_violations": [
      {
        "id": 197426,
        "question": "Cleaning log is filled in",
        "checklist": "Daily dining room check",
        "section": "Restroom",
        "fails": 5,
        "answered": 10,
        "rate": 50,
        "locations": 4
      }
    ],
    "locations_without_audits": [],
    "insights": [
      "Average score rose by 4.1 pp: 80% vs 75.9% in the previous period."
    ]
  }
}

GETRank locations

GET /analytics/locations

Location ranking for a period: audits, average score and change vs the previous period, pass rate, violations per audit, last audit and days since. For "which locations are worst", "where have we not audited for a long time".

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_locations · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.
sort string
Sort order. Default worst.
worstbestmost_auditslongest_unauditedbiggest_drop
limit integer
How many locations to return. Default 20. Value 1–50.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/locations?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/locations?period=30d', {
  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/analytics/locations",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/locations', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_locations",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "total_locations": 5,
    "locations": [
      {
        "id": 4638,
        "name": "Station Sq",
        "audits": 3,
        "prev_audits": 12,
        "avg": 72.2,
        "prev_avg": 68.8,
        "delta": 3.4,
        "pass_rate": 67,
        "violations": 6,
        "viol_per_audit": 2,
        "last_audit": "2026-10-15",
        "days_since": 19
      }
    ]
  }
}

GETGet location analytics

GET /analytics/locations/{location_id}

One location in detail for a period: KPIs with the previous period, checklists, top violations of the location, the last 12 audits with report links, auditors.

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_location · read-only

Path parameters

location_id integer Required
Location id.

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
404not_found — The record does not exist or is not visible to the token
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/locations/12?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/locations/12?period=30d', {
  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/analytics/locations/12",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/locations/12', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_location",
        "arguments": {
            "location_id": 12,
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "id": 4638,
    "name": "Embankment",
    "address": "Embankment, 3",
    "cur": {
      "audits": 7,
      "avg": 78.2,
      "pass_rate": 100,
      "locations": 1,
      "auditors": 3,
      "violations": 13,
      "viol_per_audit": 1.9,
      "viol_rate": 21.7
    },
    "prev": {
      "audits": 7,
      "avg": 90.4,
      "pass_rate": 100,
      "locations": 1,
      "auditors": 3,
      "violations": 5,
      "viol_per_audit": 0.7,
      "viol_rate": 10
    },
    "checklists": [
      {
        "id": 5845,
        "name": "Daily dining room check",
        "audits": 4,
        "avg": 77.8,
        "min": 72.2,
        "last": "2026-10-14"
      }
    ],
    "violations": [
      {
        "id": 197428,
        "question": "Staff wear uniforms and badges",
        "checklist": "Daily dining room check",
        "section": "Staff",
        "fails": 3,
        "answered": 4,
        "rate": 75,
        "locations": 1
      }
    ],
    "recent": [
      {
        "result": 77.8,
        "date": "2026-10-14 17:19",
        "checklist": "Daily dining room check",
        "auditor": "Marina Lebedeva",
        "report_url": "https://app.jecheck.io/api/reports/newVersionSavePdf/9a72f859-63a3-4046-9616-8aaf730073ff"
      }
    ],
    "auditors": [
      {
        "id": 6321,
        "name": "Marina Lebedeva",
        "audits": 4,
        "avg": 80.4
      }
    ]
  }
}

GETGet checklist statistics

GET /analytics/checklists

Checklists for a period: audits, average score and change, pass rate, violations. With checklist_id — also selected: compliance by section, questions sorted by violation rate (most problematic first), locations, and violations repeated at the same location. Useful to find weak spots of a checklist.

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_checklists · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.
checklist_id integer
Checklist id for a detailed breakdown.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/checklists?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/checklists?period=30d', {
  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/analytics/checklists",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/checklists', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_checklists",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "checklists": [
      {
        "id": 5845,
        "name": "Daily dining room check",
        "type": "points",
        "audits": 10,
        "prev_audits": 16,
        "avg": 79.1,
        "prev_avg": 77.7,
        "delta": 1.4,
        "pass_rate": 90,
        "locations": 5,
        "violations": 17,
        "viol_rate": 19.5,
        "last": "2026-10-15"
      }
    ],
    "selected": {
      "id": 5845,
      "name": "Daily dining room check",
      "cur": {
        "audits": 10,
        "avg": 79.1,
        "pass_rate": 90,
        "locations": 5,
        "auditors": 2,
        "violations": 17,
        "viol_per_audit": 1.7,
        "viol_rate": 19.5
      },
      "prev": {
        "audits": 16,
        "avg": 77.7,
        "pass_rate": 62.5,
        "locations": 5,
        "auditors": 2,
        "violations": 29,
        "viol_per_audit": 1.8,
        "viol_rate": 20.9
      },
      "sections": [
        {
          "id": 21626,
          "name": "Hall",
          "questions": 4,
          "violations": 6,
          "compliance": 83.8
        }
      ],
      "questions_by_violations": [
        {
          "n": 6,
          "question": "Cleaning log is filled in",
          "section": "Restroom",
          "yes": 5,
          "no": 5,
          "skip": 0,
          "rate": 50,
          "locations": 4,
          "comments": 5
        }
      ],
      "locations": [
        {
          "id": 4638,
          "name": "Park St",
          "audits": 1,
          "avg": 58.8,
          "min": 58.8
        }
      ],
      "repeat_violations": [
        {
          "location": "Embankment",
          "question": "Staff wear uniforms and badges",
          "fails": 3,
          "audits": 4,
          "last": "2026-10-14"
        }
      ]
    }
  }
}

GETList top violations

GET /analytics/violations

The most frequent violations (checklist questions answered "violation") for a period: how many times, out of how many answers, rate %, on how many locations, checklist and section.

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_violations · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.
limit integer
How many violations to return. Default 10. Value 1–30.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/violations?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/violations?period=30d', {
  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/analytics/violations",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/violations', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_violations",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "violations": [
      {
        "id": 197426,
        "question": "Cleaning log is filled in",
        "checklist": "Daily dining room check",
        "section": "Restroom",
        "fails": 5,
        "answered": 10,
        "rate": 50,
        "locations": 4
      }
    ]
  }
}

GETGet auditor statistics

GET /analytics/team

Auditors for a period: number of audits, average score and deviation from the company average (strictness), locations, checklists, active days, photos / violations / comments per audit, last audit. Requires analytics.team; only audits of the token's locations are counted.

Token scoperead
Permission analytics.team
Plan featureanalytics_pro
MCP toolanalytics_team · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.team, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/team?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/team?period=30d', {
  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/analytics/team",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/team', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_team",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "company_avg": 80,
    "auditors": [
      {
        "id": 6321,
        "name": "Marina Lebedeva",
        "audits": 10,
        "prev_audits": 19,
        "avg": 82.7,
        "deviation": 3.6,
        "locations": 5,
        "checklists": 3,
        "active_days": 7,
        "photos_per_audit": 0.6,
        "viol_per_audit": 1.4,
        "comments_per_audit": 1.4,
        "last": "2026-10-14"
      }
    ]
  }
}

GETGet plan fulfilment

GET /analytics/plan

Audit plan fulfilment for a period by the planner rules (an audit counts within "planned date ± tolerance" for the same checklist and location): due / done / overdue (window still open) / missed and % with the previous period; breakdowns by location, auditor and checklist (worst first); missed audits; audits planned for the next 7 days; share of unplanned audits.

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_plan · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/plan?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/plan?period=30d', {
  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/analytics/plan",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/plan', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_plan",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "cur": {
      "due": 24,
      "done": 8,
      "overdue": 0,
      "missed": 16,
      "rate": 33
    },
    "prev": {
      "due": 24,
      "done": 18,
      "overdue": 0,
      "missed": 6,
      "rate": 75
    },
    "byLocation": [
      {
        "id": 4638,
        "name": "Park St",
        "due": 8,
        "done": 1,
        "overdue": 0,
        "missed": 7,
        "rate": 13
      }
    ],
    "byAuditor": [
      {
        "id": 6324,
        "name": "Artem Volkov",
        "due": 4,
        "done": 0,
        "overdue": 0,
        "missed": 4,
        "rate": 0
      }
    ],
    "byChecklist": [
      {
        "id": 5848,
        "name": "Shift opening",
        "due": 4,
        "done": 0,
        "overdue": 0,
        "missed": 4,
        "rate": 0
      }
    ],
    "missed": [
      {
        "date": "2026-10-30",
        "location": "Park St",
        "checklist": "Shift opening",
        "auditor": "Artem Volkov"
      }
    ],
    "upcoming": 9,
    "unplanned": {
      "total": 18,
      "unplanned": 14
    },
    "hasPlan": true
  }
}

GETGet task statistics

GET /analytics/tasks

Tasks (including corrective actions from audits) for a period: created / closed / overdue, completion %, average closing time, on time; a snapshot of open tasks now (new, in progress, in review, overdue); breakdowns by priority, assignee and location; overdue tasks.

Token scoperead
Permission analytics.view
Plan featureanalytics_pro
MCP toolanalytics_tasks · read-only

Query parameters

period string
Period; custom requires from and to. Default 30d.
7d30d90d12mcustom
from date
Start of a custom period.
to date
End of a custom period.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks analytics.view, or the plan has no analytics_pro
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/tasks?period=30d' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/tasks?period=30d', {
  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/analytics/tasks",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"period":"30d"},
)
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', 'analytics/tasks', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'period' => '30d',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_tasks",
        "arguments": {
            "period": "30d"
        }
    }
}
Response 200
{
  "data": {
    "period": {
      "from": "2026-10-05",
      "to": "2026-11-03",
      "previous": {
        "from": "2026-09-04",
        "to": "2026-10-04"
      },
      "bucket": "day",
      "restricted_to_user_locations": false
    },
    "cur": {
      "created": 63,
      "created_done": 25,
      "created_rejected": 1,
      "created_open": 37,
      "created_overdue": 35,
      "completion": 40,
      "done": 25,
      "close_days": 0.4,
      "on_time": 56
    },
    "prev": {
      "created": 0,
      "created_done": 0,
      "created_rejected": 0,
      "created_open": 0,
      "created_overdue": 0,
      "completion": null,
      "done": 0,
      "close_days": null,
      "on_time": null
    },
    "snapshot": {
      "open": 37,
      "new": 30,
      "progress": 4,
      "review": 3,
      "overdue": 35,
      "soon": 0,
      "no_deadline": 0
    },
    "trackedSince": "2026-10-08 17:07:00",
    "byPriority": [
      {
        "key": 0,
        "label": "Urgent",
        "open": 1,
        "overdue": 1
      }
    ],
    "byExecutor": [
      {
        "id": 6323,
        "name": "Elena Morozova",
        "open": 14,
        "overdue": 12,
        "done": 5,
        "assigned": 19,
        "completion": 26,
        "close_days": 0.1,
        "on_time": 60
      }
    ],
    "byLocation": [
      {
        "id": 4637,
        "name": "Central",
        "open": 20,
        "overdue": 18,
        "done": 13
      }
    ],
    "overdueList": [
      {
        "uuid": "25180680-8ef5-a075-575b-cceed90f6bc0",
        "title": "Replace the broken fridge seal",
        "deadline": "2026-10-12",
        "days": 22,
        "priority": 1,
        "location": "Central",
        "executor": "Daria Kim"
      }
    ]
  }
}

GETGet the AI control brief

GET /analytics/control-brief

The AI control brief from the home page: open problems found automatically (unstable and chronic violations, score drops, reused photos, soft auditors, missed plan, overdue tasks, HACCP, tests, instructions) with title, text, evidence facts, severity and status — most severe first, up to 15. With signal — one card by its UUID. Visibility follows audits.view; staff-related cards need control.manage.

Token scoperead
Permission audits.view
MCP toolanalytics_control_brief · read-only

Query parameters

signal uuid
UUID of one brief card.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks audits.view
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/control-brief?signal=3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/control-brief?signal=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/analytics/control-brief",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"signal":"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('GET', 'analytics/control-brief', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'signal' => '3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_control_brief",
        "arguments": {
            "signal": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "signals": [
      {
        "uuid": "4a4007c6-b9a3-461b-8f1b-e584fbe7c45d",
        "detector": "haccp",
        "severity": 3,
        "status": "open",
        "title": "Central: HACCP risk",
        "text": "1 critical deviation not fixed on time (log \"Storage temperature\", 21 h overdue).",
        "facts": {
          "dept": "Central",
          "deviations": 1,
          "overdue_hours": 21
        },
        "location_id": 4637,
        "checklist_id": null,
        "ai": {
          "why": "The fridge alarm was ignored overnight.",
          "advice": "Check the fridge and log the corrective action."
        },
        "since": "2026-10-17"
      }
    ]
  }
}

GETGet employee test statistics

GET /analytics/tests

Employee tests (Testing section): title, status, pass score, questions, attempts, average %, passed; assigned / passed / overdue assignments; answers waiting for manual review. Up to 40 tests, recently changed first.

Token scoperead
Permission testing.manage
Plan featuretesting
MCP toolanalytics_tests · read-only

Query parameters

query string
Part of the test title. Maximum length 200.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks testing.manage, or the plan has no testing
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/analytics/tests?query=string' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/analytics/tests?query=string', {
  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/analytics/tests",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"query":"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('GET', 'analytics/tests', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'query' => 'string',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "analytics_tests",
        "arguments": {
            "query": "string"
        }
    }
}
Response 200
{
  "data": {
    "tests": [
      {
        "id": 12,
        "title": "Barista standards",
        "status": "published",
        "category": "Barista",
        "pass_score": 80,
        "questions": 8,
        "attempts": 4,
        "avg_percent": 68.5,
        "passed_attempts": 2,
        "assigned": 7,
        "assigned_passed": 2,
        "overdue": 4,
        "pending_review": 1,
        "url": "https://app.jecheck.io/ui/testing/12/edit"
      }
    ]
  }
}