jeCheckDevelopers
Get an API key

GETList planned audits

GET /planner/audits

Planned audits (calendar entries) in a date range, ordered by date. The status is computed on read: done — marked manually (done_by: manual) or matched by a conducted audit of the same checklist and location within the window date ± tolerance (done_by: audit, audit_id); planned, inprogress (today, start time passed), overdue (date passed, window still open), missed (window closed). Visible: locations where the token has planner.view or planner.manage, plus audits assigned to the token user.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_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
From date (inclusive); default — today.
date_to date
To date (inclusive); default — 30 days after date_from; the range is limited to 366 days.
location_ids array<integer>
Only these locations.
auditor_ids array<integer>
Only these auditors.
checklist_ids array<integer>
Only these checklists.
status array<string>
Filter by status: planned, inprogress, overdue, missed, done.
mine boolean
Only audits assigned to the token user.

Responses

StatusDescription
200OK — a page of results with meta
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Plan without API access
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/planner/audits?date_from=2026-11-01' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/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/planner/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', 'planner/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": "planner_audits_list",
        "arguments": {
            "date_from": "2026-11-01"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 48211,
      "date": "2026-11-05",
      "time": "09:00",
      "duration_min": 60,
      "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"
      },
      "status": "planned",
      "done_by": null,
      "audit_id": null,
      "audit_date": null,
      "window_from": "2026-11-04",
      "window_to": "2026-11-06",
      "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
      "series_id": 1842,
      "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "has_more": false
  }
}

GETRetrieve a planned audit

GET /planner/audits/{id}
Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_get · read-only

Path parameters

id integer Required
Planned 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/planner/audits/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/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/planner/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', 'planner/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": "planner_audits_get",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 48211,
    "date": "2026-11-05",
    "time": "09:00",
    "duration_min": 60,
    "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"
    },
    "status": "planned",
    "done_by": null,
    "audit_id": null,
    "audit_date": null,
    "window_from": "2026-11-04",
    "window_to": "2026-11-06",
    "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "series_id": 1842,
    "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
  }
}

POSTReschedule a planned audit

POST /planner/audits/{id}/reschedule

Moves the planned audit to another date and/or time; reminders are sent again. Requires planner.manage on its location.

Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_reschedule

Path parameters

id integer Required
Planned audit id.

Request body

date date Required
New date.
time string
New start time HH:MM (kept if omitted).

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
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 POST 'https://app.jecheck.io/api/ext/v1/planner/audits/42/reschedule' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "date": "2026-11-01",
    "time": "string"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/audits/42/reschedule', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "date": "2026-11-01",
      "time": "string"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/planner/audits/42/reschedule",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"date":"2026-11-01","time":"string"},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'planner/audits/42/reschedule', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'date' => '2026-11-01',
        'time' => 'string',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_audits_reschedule",
        "arguments": {
            "id": 42,
            "date": "2026-11-01",
            "time": "string"
        }
    }
}
Response 200
{
  "data": {
    "id": 48211,
    "date": "2026-11-05",
    "time": "09:00",
    "duration_min": 60,
    "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"
    },
    "status": "planned",
    "done_by": null,
    "audit_id": null,
    "audit_date": null,
    "window_from": "2026-11-04",
    "window_to": "2026-11-06",
    "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "series_id": 1842,
    "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
  }
}

POSTReassign a planned audit

POST /planner/audits/{id}/reassign

Assigns the planned audit to another auditor; the checklist must be available to them. Requires planner.manage on its location.

Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_reassign

Path parameters

id integer Required
Planned audit id.

Request body

auditor_id integer Required
New auditor (user id).

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
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 POST 'https://app.jecheck.io/api/ext/v1/planner/audits/42/reassign' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "auditor_id": 42
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/audits/42/reassign', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "auditor_id": 42
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/planner/audits/42/reassign",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"auditor_id":42},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'planner/audits/42/reassign', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'auditor_id' => 42,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_audits_reassign",
        "arguments": {
            "id": 42,
            "auditor_id": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 48211,
    "date": "2026-11-05",
    "time": "09:00",
    "duration_min": 60,
    "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"
    },
    "status": "planned",
    "done_by": null,
    "audit_id": null,
    "audit_date": null,
    "window_from": "2026-11-04",
    "window_to": "2026-11-06",
    "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "series_id": 1842,
    "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
  }
}

POSTMark a planned audit as done

POST /planner/audits/{id}/complete

Manual "done" mark (e.g. the audit was done on paper). Allowed with planner.manage on the location or to the assigned auditor.

Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_complete

Path parameters

id integer Required
Planned audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
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 POST 'https://app.jecheck.io/api/ext/v1/planner/audits/42/complete' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/audits/42/complete', {
  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/planner/audits/42/complete",
    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', 'planner/audits/42/complete', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_audits_complete",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 48211,
    "date": "2026-11-05",
    "time": "09:00",
    "duration_min": 60,
    "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"
    },
    "status": "planned",
    "done_by": null,
    "audit_id": null,
    "audit_date": null,
    "window_from": "2026-11-04",
    "window_to": "2026-11-06",
    "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "series_id": 1842,
    "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
  }
}

POSTRemove the manual done mark

POST /planner/audits/{id}/uncomplete

The status is computed again. Fails with 422 if the audit was not marked manually.

Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_uncomplete

Path parameters

id integer Required
Planned audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
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 POST 'https://app.jecheck.io/api/ext/v1/planner/audits/42/uncomplete' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/audits/42/uncomplete', {
  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/planner/audits/42/uncomplete",
    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', 'planner/audits/42/uncomplete', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_audits_uncomplete",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 48211,
    "date": "2026-11-05",
    "time": "09:00",
    "duration_min": 60,
    "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"
    },
    "status": "planned",
    "done_by": null,
    "audit_id": null,
    "audit_date": null,
    "window_from": "2026-11-04",
    "window_to": "2026-11-06",
    "plan_key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "series_id": 1842,
    "url": "https://app.jecheck.io/ui/planner?date=2026-11-05"
  }
}

DELCancel a planned audit

DELETE /planner/audits/{id}

Removes one planned audit from its plan. A done audit cannot be cancelled. Requires planner.manage on its location.

Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolplanner_audits_cancel · destructive

Path parameters

id integer Required
Planned audit id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Read-only token
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/planner/audits/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/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/planner/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', 'planner/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": "planner_audits_cancel",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

GETList audit plans

GET /planner/plans

Active plans whose locations are all within the token's planner.manage permission. A plan is a set of recurring series of one checklist on several locations.

Token scoperead
Permission planner.manage
MCP toolplanner_plans_list · read-only

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/planner/plans' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/plans', {
  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/planner/plans",
    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', 'planner/plans', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_plans_list",
        "arguments": {}
    }
}
Response 200
{
  "data": [
    {
      "key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
      "title": "Weekly hall check",
      "checklist": {
        "id": 5845,
        "name": "Daily dining room check"
      },
      "locations": [
        {
          "id": 12,
          "name": "Abay Ave"
        },
        {
          "id": 14,
          "name": "Dostyk Plaza"
        }
      ],
      "auditor": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "recur": "weekly",
      "weekdays": [
        1,
        4
      ],
      "month_days": [],
      "time": "09:00",
      "duration_min": 60,
      "start_date": "2026-11-03",
      "end_date": "2027-02-03",
      "tolerance_days": 1,
      "notify": {
        "email": true,
        "day1": true,
        "hour1": false,
        "escalate": true
      },
      "series_ids": [
        1842,
        1843
      ]
    }
  ]
}

GETRetrieve an audit plan

GET /planner/plans/{key}
Token scoperead
Permission planner.manage
MCP toolplanner_plans_get · read-only

Path parameters

key string Required
Plan key (UUID, or s<id> for older single-series plans).

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage
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/planner/plans/string' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/plans/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/planner/plans/string",
    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', 'planner/plans/string', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_plans_get",
        "arguments": {
            "key": "string"
        }
    }
}
Response 200
{
  "data": {
    "key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
    "title": "Weekly hall check",
    "checklist": {
      "id": 5845,
      "name": "Daily dining room check"
    },
    "locations": [
      {
        "id": 12,
        "name": "Abay Ave"
      },
      {
        "id": 14,
        "name": "Dostyk Plaza"
      }
    ],
    "auditor": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "recur": "weekly",
    "weekdays": [
      1,
      4
    ],
    "month_days": [],
    "time": "09:00",
    "duration_min": 60,
    "start_date": "2026-11-03",
    "end_date": "2027-02-03",
    "tolerance_days": 1,
    "notify": {
      "email": true,
      "day1": true,
      "hour1": false,
      "escalate": true
    },
    "series_ids": [
      1842,
      1843
    ]
  }
}

POSTCreate an audit plan

POST /planner/plans

Creates a plan: one series per location with planned audits generated by the recurrence rule. Requires planner.manage on every location of the plan. The response contains the plan and how many audits were scheduled.

Token scopewrite
Permission planner.manage
MCP toolplanner_plans_create

Request body

title string | null
Plan title; default "Plan: ". Maximum length 255.
checklist_id integer Required
Checklist to audit.
location_ids array<integer> Required
Locations — one series per location. Minimum items 1.
auditor_id integer Required
Auditor (user id); the checklist must be available to them.
recur string Required
none — once on start_date, daily, weekdays (Mon–Fri), weekly (on weekdays), monthly (on month_days).
nonedailyweekdaysweeklymonthly
weekdays array<integer>
For weekly: days of week, 0 = Sunday … 6 = Saturday.
month_days array<integer>
For monthly: days of month 1–31.
time string
Start time HH:MM, default 09:00.
duration_min integer
Planned duration, minutes (default 60). Value 5–1440.
start_date date Required
First day of the plan.
end_date date | null
Last day; default depends on the recurrence.
tolerance_days integer
An audit conducted within ± this many days of the planned date counts; default depends on the frequency. Value 0–14.
notify object
Notifications.
email boolean
Email the auditor about the plan.
day1 boolean
Remind a day before.
hour1 boolean
Remind an hour before.
escalate boolean
Notify managers about missed audits.

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage, is read-only
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/planner/plans' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Replace the broken fridge seal",
    "checklist_id": 42,
    "location_ids": [
        12,
        14
    ],
    "auditor_id": 42,
    "recur": "none",
    "start_date": "2026-11-01"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/plans', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "title": "Replace the broken fridge seal",
      "checklist_id": 42,
      "location_ids": [
          12,
          14
      ],
      "auditor_id": 42,
      "recur": "none",
      "start_date": "2026-11-01"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/planner/plans",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"title":"Replace the broken fridge seal","checklist_id":42,"location_ids":[12,14],"auditor_id":42,"recur":"none","start_date":"2026-11-01"},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'planner/plans', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'title' => 'Replace the broken fridge seal',
        'checklist_id' => 42,
        'location_ids' => [
            12,
            14,
        ],
        'auditor_id' => 42,
        'recur' => 'none',
        'start_date' => '2026-11-01',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_plans_create",
        "arguments": {
            "title": "Replace the broken fridge seal",
            "checklist_id": 42,
            "location_ids": [
                12,
                14
            ],
            "auditor_id": 42,
            "recur": "none",
            "start_date": "2026-11-01"
        }
    }
}
Response 201
{
  "data": {
    "plan": {
      "key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
      "title": "Weekly hall check",
      "checklist": {
        "id": 5845,
        "name": "Daily dining room check"
      },
      "locations": [
        {
          "id": 12,
          "name": "Abay Ave"
        },
        {
          "id": 14,
          "name": "Dostyk Plaza"
        }
      ],
      "auditor": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "recur": "weekly",
      "weekdays": [
        1,
        4
      ],
      "month_days": [],
      "time": "09:00",
      "duration_min": 60,
      "start_date": "2026-11-03",
      "end_date": "2027-02-03",
      "tolerance_days": 1,
      "notify": {
        "email": true,
        "day1": true,
        "hour1": false,
        "escalate": true
      },
      "series_ids": [
        1842,
        1843
      ]
    },
    "scheduled": 28
  }
}

PUTUpdate an audit plan

PUT /planner/plans/{key}

Replaces the plan settings. Past audits stay as they are; upcoming ones (from today, except done) are regenerated. Removed locations lose their series, added ones get new series. Requires planner.manage on the old and new locations. upcoming — planned audits from today.

Token scopewrite
Permission planner.manage
MCP toolplanner_plans_update

Path parameters

key string Required
Plan key (UUID, or s<id> for older single-series plans).

Request body

title string | null
Plan title; default "Plan: ". Maximum length 255.
checklist_id integer Required
Checklist to audit.
location_ids array<integer> Required
Locations — one series per location. Minimum items 1.
auditor_id integer Required
Auditor (user id); the checklist must be available to them.
recur string Required
none — once on start_date, daily, weekdays (Mon–Fri), weekly (on weekdays), monthly (on month_days).
nonedailyweekdaysweeklymonthly
weekdays array<integer>
For weekly: days of week, 0 = Sunday … 6 = Saturday.
month_days array<integer>
For monthly: days of month 1–31.
time string
Start time HH:MM, default 09:00.
duration_min integer
Planned duration, minutes (default 60). Value 5–1440.
start_date date Required
First day of the plan.
end_date date | null
Last day; default depends on the recurrence.
tolerance_days integer
An audit conducted within ± this many days of the planned date counts; default depends on the frequency. Value 0–14.
notify object
Notifications.
email boolean
Email the auditor about the plan.
day1 boolean
Remind a day before.
hour1 boolean
Remind an hour before.
escalate boolean
Notify managers about missed audits.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage, 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 PUT 'https://app.jecheck.io/api/ext/v1/planner/plans/string' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Replace the broken fridge seal",
    "checklist_id": 42,
    "location_ids": [
        12,
        14
    ],
    "auditor_id": 42,
    "recur": "none",
    "start_date": "2026-11-01"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/plans/string', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "title": "Replace the broken fridge seal",
      "checklist_id": 42,
      "location_ids": [
          12,
          14
      ],
      "auditor_id": 42,
      "recur": "none",
      "start_date": "2026-11-01"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/planner/plans/string",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"title":"Replace the broken fridge seal","checklist_id":42,"location_ids":[12,14],"auditor_id":42,"recur":"none","start_date":"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('PUT', 'planner/plans/string', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'title' => 'Replace the broken fridge seal',
        'checklist_id' => 42,
        'location_ids' => [
            12,
            14,
        ],
        'auditor_id' => 42,
        'recur' => 'none',
        'start_date' => '2026-11-01',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_plans_update",
        "arguments": {
            "key": "string",
            "title": "Replace the broken fridge seal",
            "checklist_id": 42,
            "location_ids": [
                12,
                14
            ],
            "auditor_id": 42,
            "recur": "none",
            "start_date": "2026-11-01"
        }
    }
}
Response 200
{
  "data": {
    "plan": {
      "key": "0b7c1f9e-2d4a-4f6b-8e3c-5a9d7b1c2e4f",
      "title": "Weekly hall check",
      "checklist": {
        "id": 5845,
        "name": "Daily dining room check"
      },
      "locations": [
        {
          "id": 12,
          "name": "Abay Ave"
        },
        {
          "id": 14,
          "name": "Dostyk Plaza"
        }
      ],
      "auditor": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "recur": "weekly",
      "weekdays": [
        1,
        4
      ],
      "month_days": [],
      "time": "09:00",
      "duration_min": 60,
      "start_date": "2026-11-03",
      "end_date": "2027-02-03",
      "tolerance_days": 1,
      "notify": {
        "email": true,
        "day1": true,
        "hour1": false,
        "escalate": true
      },
      "series_ids": [
        1842,
        1843
      ]
    },
    "upcoming": 18
  }
}

DELDelete an audit plan

DELETE /planner/plans/{key}

Stops the plan: its series are retired and upcoming planned audits (except done) are removed; history stays. removed — how many upcoming audits were removed.

Token scopewrite
Permission planner.manage
MCP toolplanner_plans_delete · destructive

Path parameters

key string Required
Plan key (UUID, or s<id> for older single-series plans).

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage, 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/planner/plans/string' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/plans/string', {
  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/planner/plans/string",
    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', 'planner/plans/string', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_plans_delete",
        "arguments": {
            "key": "string"
        }
    }
}
Response 200
{
  "data": {
    "deleted": true,
    "removed": 12
  }
}

GETList plan templates

GET /planner/templates

Saved plan settings shared in the company, to create similar plans quickly.

Token scoperead
Permission planner.manage
MCP toolplanner_templates_list · read-only

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/planner/templates' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/templates', {
  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/planner/templates",
    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', 'planner/templates', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_templates_list",
        "arguments": {}
    }
}
Response 200
{
  "data": [
    {
      "id": 7,
      "name": "Weekly hall check",
      "settings": {
        "title": "Weekly hall check",
        "checklist_id": 5845,
        "location_ids": [
          12,
          14
        ],
        "auditor_id": 311,
        "recur": "weekly",
        "weekdays": [
          1,
          4
        ],
        "month_days": [],
        "time": "09:00",
        "duration_min": 60,
        "tolerance_days": 1,
        "notify": {
          "email": true,
          "day1": true,
          "hour1": false,
          "escalate": true
        }
      }
    }
  ]
}

POSTSave a plan template

POST /planner/templates
Token scopewrite
Permission planner.manage
MCP toolplanner_templates_create

Request body

name string Required
Template name. Length 1–255.
settings object Required
Any subset of the plan fields (same names as in planner.plans.create).
title string | null
checklist_id integer | null
location_ids array<integer>
auditor_id integer | null
recur string | null
nonedailyweekdaysweeklymonthly
weekdays array<integer>
month_days array<integer>
time string | null
Maximum length 5.
duration_min integer | null
Value 5–1440.
tolerance_days integer | null
Value 0–14.
notify object

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage, is read-only
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/planner/templates' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "settings": {
        "title": "Replace the broken fridge seal",
        "checklist_id": 42,
        "location_ids": [
            12,
            14
        ]
    }
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/templates', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "settings": {
          "title": "Replace the broken fridge seal",
          "checklist_id": 42,
          "location_ids": [
              12,
              14
          ]
      }
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/planner/templates",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","settings":{"title":"Replace the broken fridge seal","checklist_id":42,"location_ids":[12,14]}},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'planner/templates', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'settings' => [
            'title' => 'Replace the broken fridge seal',
            'checklist_id' => 42,
            'location_ids' => [
                12,
                14,
            ],
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_templates_create",
        "arguments": {
            "name": "Replace the broken fridge seal",
            "settings": {
                "title": "Replace the broken fridge seal",
                "checklist_id": 42,
                "location_ids": [
                    12,
                    14
                ]
            }
        }
    }
}
Response 201
{
  "data": {
    "id": 7,
    "name": "Weekly hall check",
    "settings": {
      "title": "Weekly hall check",
      "checklist_id": 5845,
      "location_ids": [
        12,
        14
      ],
      "auditor_id": 311,
      "recur": "weekly",
      "weekdays": [
        1,
        4
      ],
      "month_days": [],
      "time": "09:00",
      "duration_min": 60,
      "tolerance_days": 1,
      "notify": {
        "email": true,
        "day1": true,
        "hour1": false,
        "escalate": true
      }
    }
  }
}

DELDelete a plan template

DELETE /planner/templates/{id}
Token scopewrite
Permission planner.manage
MCP toolplanner_templates_delete · destructive

Path parameters

id integer Required
Template id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks planner.manage, 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/planner/templates/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/planner/templates/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/planner/templates/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', 'planner/templates/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "planner_templates_delete",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}