jeCheckDevelopers
Get an API key

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

GET /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 scoperead
Permission audits.view
MCP toolaudits_list · read-only

Query parameters

page integer
Page number, starting from 1. Default 1. Minimum 1.
per_page integer
Items per page (max 100). Default 25. Value 1–100.
date_from date
Conducted on or after this date.
date_to date
Conducted on or before this date.
location_ids array<integer>
Only these locations.
checklist_ids array<integer>
Only these checklists.
auditor_ids array<integer>
Only audits by these users.
status array<string>
Filter by status: completed, failed, in_progress.
result_from number
Result from, %. Value 0–100.
result_to number
Result to, %. Value 0–100.
search string
Search by location, checklist or auditor name. Maximum length 200.
created_since date-time
Only audits received after this moment — use for incremental sync.
sort string
Default date_desc.
date_descdate_ascresult_ascresult_desc

Responses

StatusDescription
200OK — a page of results with meta
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/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"
        }
    }
}
Response 200
{
  "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

GET /audits/{id}

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 scoperead
Permission Any employee; results follow the token's visibility
MCP toolaudits_get · read-only

Path parameters

id integer Required
Audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Plan without API access
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/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
        }
    }
}
Response 200
{
  "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

GET /audits/{id}/pdf

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 scoperead
Permission audits.export
MCP toolaudits_pdf · read-only

Path parameters

id integer Required
Audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks audits.export
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/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
        }
    }
}
Response 200
{
  "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

POST /audits

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 scopewrite
Permission Any employee; results follow the token's visibility
MCP toolaudits_create

Request body

checklist_id integer Required
Checklist id.
location_id integer Required
Location id.
conducted_at date-time
When the audit was conducted (ISO 8601); default — now.
answers array<object> Required
Answers; questions without an answer are not saved. Items 1–1000.
question_id integer Required
Question id (from checklists.get).
result string
For yes_no: ok, violation or na; na also skips a question of another type.
okviolationna
text string
Text answer (text type). Maximum length 5000.
value object
Value for the other answer types.
comment string | null
Auditor comment. Maximum length 5000.
latitude number
Auditor geolocation.
longitude number
Auditor geolocation.

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
422validation_failed — Invalid parameters — see error.fields
429rate_limited — Too many requests — retry after Retry-After seconds
Request
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."
                }
            ]
        }
    }
}
Response 201
{
  "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

DELETE /audits/{id}

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 scopewrite
Permission audits.delete
MCP toolaudits_delete · destructive

Path parameters

id integer Required
Audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks audits.delete, is read-only
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 -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
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}