Recurring projects
Recurring projects such as month-end closing: a template of items with due dates in working days relative to the period anchor date (e.g. the last day of the month), owners (a person, a team, a position at each location or the location manager), items repeated for every location, and dependencies. On schedule a regular project is created for each period (see the Projects and Tasks sections). The period summary is a matrix of items × locations with readiness, delays and the chains they hold. Configuring requires projects.cycles or the admin role in the recurring project; available on plans with recurring projects.
GETList recurring projects
Recurring projects the token can see: all with projects.cycles, otherwise those it owns or is a member of, and those open to the company. Each has the latest period and its progress.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_list · read-only |
Query parameters
page
integer
1. Minimum 1.
per_page
integer
25. Value 1–100.
Responses
| Status | Description |
|---|---|
| 200 | OK — a page of results with meta |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles', {
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/project-cycles",
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', 'project-cycles', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_list",
"arguments": {}
}
}{
"data": [
{
"id": 7,
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations and the owner report",
"icon": "event_available",
"color": "#0e9aa7",
"key": "CLS",
"active": true,
"owner": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"schedule": {
"frequency": "monthly",
"anchor": "end",
"day": 25,
"weekday": 5,
"create_offset": -5,
"hour": 9,
"holidays": [
"2026-12-16"
]
},
"schedule_text": "every month, by the last day; the project is created 5 working days before",
"next_run_at": "2026-12-24T04:00:00+00:00",
"last_period": "2026-11",
"items_count": 13,
"per_location_items": 6,
"location_ids": null,
"members": [
{
"user": {
"id": 412,
"uuid": "2f3e4d5c-6b7a-4899-8a0b-2c3d4e5f6a7b",
"name": "Daniyar Ospanov"
},
"role": "viewer"
}
],
"settings": {
"visibility": "members",
"notify_start": true,
"notify_unblocked": true
},
"role": "admin",
"created_at": "2026-11-06T10:00:00+05:00",
"updated_at": "2026-11-06T10:05:00+05:00",
"url": "https://app.jecheck.io/ui/projects/cycles/4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"template": {
"sections": [
"Location documents",
"Stocktaking"
],
"items": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"description": "",
"section": 0,
"per_location": true,
"assign": {
"type": "manager",
"ids": []
},
"start_offset": null,
"due_offset": -1,
"priority": "medium",
"requires_photo": false,
"requires_review": false,
"subtasks": [],
"tags": [],
"after": []
}
]
}
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"has_more": false
}
}GETList ready-made templates
Built-in recurring project templates (month-end closing, stocktaking, quarter closing, blank). Pass the id as template when creating.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_templates · read-only |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/templates' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/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/project-cycles/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', 'project-cycles/templates', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_templates",
"arguments": {}
}
}{
"data": [
{
"id": "month_close",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations…",
"icon": "event_available",
"items": 13,
"frequency": "monthly",
"per_location_items": 6
}
]
}GETRetrieve a recurring project
Card, schedule and the full template (sections and items).
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_get · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/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/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('GET', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_get",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"id": 7,
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations and the owner report",
"icon": "event_available",
"color": "#0e9aa7",
"key": "CLS",
"active": true,
"owner": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"schedule": {
"frequency": "monthly",
"anchor": "end",
"day": 25,
"weekday": 5,
"create_offset": -5,
"hour": 9,
"holidays": [
"2026-12-16"
]
},
"schedule_text": "every month, by the last day; the project is created 5 working days before",
"next_run_at": "2026-12-24T04:00:00+00:00",
"last_period": "2026-11",
"items_count": 13,
"per_location_items": 6,
"location_ids": null,
"members": [
{
"user": {
"id": 412,
"uuid": "2f3e4d5c-6b7a-4899-8a0b-2c3d4e5f6a7b",
"name": "Daniyar Ospanov"
},
"role": "viewer"
}
],
"settings": {
"visibility": "members",
"notify_start": true,
"notify_unblocked": true
},
"role": "admin",
"created_at": "2026-11-06T10:00:00+05:00",
"updated_at": "2026-11-06T10:05:00+05:00",
"url": "https://app.jecheck.io/ui/projects/cycles/4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"template": {
"sections": [
"Location documents",
"Stocktaking"
],
"items": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"description": "",
"section": 0,
"per_location": true,
"assign": {
"type": "manager",
"ids": []
},
"start_offset": null,
"due_offset": -1,
"priority": "medium",
"requires_photo": false,
"requires_review": false,
"subtasks": [],
"tags": [],
"after": []
}
]
}
}
}POSTCreate a recurring project
From a ready-made template, from the tasks of an existing project (from_project_uuid: sections, owners, dependencies, due dates as working days from the project due date) or blank. The first period is planned right away. Requires projects.cycles.
| Token scope | write |
|---|---|
| Permission |
projects.cycles |
| Plan feature | project_cycles |
| MCP tool | cycles_create |
Request body
name
string
key
string
CLS → CLS2611.
Maximum length 5. description
string | null
icon
string
color
string
schedule
object
frequency
string
monthlyquarterlyweeklyanchor
string
day of the month.
endstartdayday
integer
anchor: day.
Value 1–31.
weekday
integer
create_offset
integer
hour
integer
holidays
array<string>
template_sections
array<string>
template_items
array<object>
id
string
i_ + letters/digits); generated if omitted. Used by after and as the summary row.
title
string
Required description
string
section
integer | null
template_sections.
per_location
boolean
assign
object
type
string
users — the listed people; team — a team queue; position — employees with the position at the task location; manager — the location manager; owner — the recurring project owner.
noneusersteampositionmanagerownerids
array<integer>
start_offset
integer | null
due_offset
integer | null
priority
string
urgenthighmediumlowrequires_photo
boolean
requires_review
boolean
subtasks
array<string>
tags
array<string>
after
array<string>
location_ids
array<integer> | null
owner_id
integer
members
array<object>
user_id
integer
Required role
string
admin also configures the recurring project.
admineditorcommenterviewersettings
object
visibility
string
memberscompanynotify_start
boolean
notify_unblocked
boolean
active
boolean
template
string
cycles.templates).
Maximum length 40. from_project_uuid
uuid
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Token lacks projects.cycles, is read-only, or the plan has no project_cycles
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/project-cycles' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/project-cycles",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"name":"Replace the broken fridge seal","key":"string","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","icon":"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', 'project-cycles', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'name' => 'Replace the broken fridge seal',
'key' => 'string',
'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
'icon' => 'string',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_create",
"arguments": {
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}
}
}{
"data": {
"id": 7,
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations and the owner report",
"icon": "event_available",
"color": "#0e9aa7",
"key": "CLS",
"active": true,
"owner": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"schedule": {
"frequency": "monthly",
"anchor": "end",
"day": 25,
"weekday": 5,
"create_offset": -5,
"hour": 9,
"holidays": [
"2026-12-16"
]
},
"schedule_text": "every month, by the last day; the project is created 5 working days before",
"next_run_at": "2026-12-24T04:00:00+00:00",
"last_period": "2026-11",
"items_count": 13,
"per_location_items": 6,
"location_ids": null,
"members": [
{
"user": {
"id": 412,
"uuid": "2f3e4d5c-6b7a-4899-8a0b-2c3d4e5f6a7b",
"name": "Daniyar Ospanov"
},
"role": "viewer"
}
],
"settings": {
"visibility": "members",
"notify_start": true,
"notify_unblocked": true
},
"role": "admin",
"created_at": "2026-11-06T10:00:00+05:00",
"updated_at": "2026-11-06T10:05:00+05:00",
"url": "https://app.jecheck.io/ui/projects/cycles/4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"template": {
"sections": [
"Location documents",
"Stocktaking"
],
"items": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"description": "",
"section": 0,
"per_location": true,
"assign": {
"type": "manager",
"ids": []
},
"start_offset": null,
"due_offset": -1,
"priority": "medium",
"requires_photo": false,
"requires_review": false,
"subtasks": [],
"tags": [],
"after": []
}
]
}
}
}PATCHUpdate a recurring project
Partial update. Template changes apply to the next periods; existing period projects are not changed. Requires the admin role in the recurring project.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_update |
Path parameters
uuid
uuid
Required Request body
name
string
key
string
CLS → CLS2611.
Maximum length 5. description
string | null
icon
string
color
string
schedule
object
frequency
string
monthlyquarterlyweeklyanchor
string
day of the month.
endstartdayday
integer
anchor: day.
Value 1–31.
weekday
integer
create_offset
integer
hour
integer
holidays
array<string>
template_sections
array<string>
template_items
array<object>
id
string
i_ + letters/digits); generated if omitted. Used by after and as the summary row.
title
string
Required description
string
section
integer | null
template_sections.
per_location
boolean
assign
object
type
string
users — the listed people; team — a team queue; position — employees with the position at the task location; manager — the location manager; owner — the recurring project owner.
noneusersteampositionmanagerownerids
array<integer>
start_offset
integer | null
due_offset
integer | null
priority
string
urgenthighmediumlowrequires_photo
boolean
requires_review
boolean
subtasks
array<string>
tags
array<string>
after
array<string>
location_ids
array<integer> | null
owner_id
integer
members
array<object>
user_id
integer
Required role
string
admin also configures the recurring project.
admineditorcommenterviewersettings
object
visibility
string
memberscompanynotify_start
boolean
notify_unblocked
boolean
active
boolean
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X PATCH 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}),
});
const { data } = await res.json();import os, requests
res = requests.patch(
"https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"name":"Replace the broken fridge seal","key":"string","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","icon":"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('PATCH', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'name' => 'Replace the broken fridge seal',
'key' => 'string',
'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
'icon' => 'string',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_update",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"name": "Replace the broken fridge seal",
"key": "string",
"description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
"icon": "string"
}
}
}{
"data": {
"id": 7,
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations and the owner report",
"icon": "event_available",
"color": "#0e9aa7",
"key": "CLS",
"active": true,
"owner": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"schedule": {
"frequency": "monthly",
"anchor": "end",
"day": 25,
"weekday": 5,
"create_offset": -5,
"hour": 9,
"holidays": [
"2026-12-16"
]
},
"schedule_text": "every month, by the last day; the project is created 5 working days before",
"next_run_at": "2026-12-24T04:00:00+00:00",
"last_period": "2026-11",
"items_count": 13,
"per_location_items": 6,
"location_ids": null,
"members": [
{
"user": {
"id": 412,
"uuid": "2f3e4d5c-6b7a-4899-8a0b-2c3d4e5f6a7b",
"name": "Daniyar Ospanov"
},
"role": "viewer"
}
],
"settings": {
"visibility": "members",
"notify_start": true,
"notify_unblocked": true
},
"role": "admin",
"created_at": "2026-11-06T10:00:00+05:00",
"updated_at": "2026-11-06T10:05:00+05:00",
"url": "https://app.jecheck.io/ui/projects/cycles/4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"template": {
"sections": [
"Location documents",
"Stocktaking"
],
"items": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"description": "",
"section": 0,
"per_location": true,
"assign": {
"type": "manager",
"ids": []
},
"start_offset": null,
"due_offset": -1,
"priority": "medium",
"requires_photo": false,
"requires_review": false,
"subtasks": [],
"tags": [],
"after": []
}
]
}
}
}DELDelete a recurring project
Stops creating periods and removes the recurring project. Period projects already created stay as regular projects.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_delete · destructive |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X DELETE 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
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/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('DELETE', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_delete",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"deleted": true
}
}POSTDuplicate a recurring project
Copy of the template and schedule, paused, without periods. Requires projects.cycles.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_duplicate |
Path parameters
uuid
uuid
Required Request body
name
string
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Replace the broken fridge seal"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Replace the broken fridge seal"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"name":"Replace the broken fridge seal"},
)
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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'name' => 'Replace the broken fridge seal',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_duplicate",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"name": "Replace the broken fridge seal"
}
}
}{
"data": {
"id": 7,
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing",
"description": "Documents, stocktaking, reconciliations and the owner report",
"icon": "event_available",
"color": "#0e9aa7",
"key": "CLS",
"active": true,
"owner": {
"id": 311,
"uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
"name": "Aigerim Sadykova"
},
"schedule": {
"frequency": "monthly",
"anchor": "end",
"day": 25,
"weekday": 5,
"create_offset": -5,
"hour": 9,
"holidays": [
"2026-12-16"
]
},
"schedule_text": "every month, by the last day; the project is created 5 working days before",
"next_run_at": "2026-12-24T04:00:00+00:00",
"last_period": "2026-11",
"items_count": 13,
"per_location_items": 6,
"location_ids": null,
"members": [
{
"user": {
"id": 412,
"uuid": "2f3e4d5c-6b7a-4899-8a0b-2c3d4e5f6a7b",
"name": "Daniyar Ospanov"
},
"role": "viewer"
}
],
"settings": {
"visibility": "members",
"notify_start": true,
"notify_unblocked": true
},
"role": "admin",
"created_at": "2026-11-06T10:00:00+05:00",
"updated_at": "2026-11-06T10:05:00+05:00",
"url": "https://app.jecheck.io/ui/projects/cycles/4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"template": {
"sections": [
"Location documents",
"Stocktaking"
],
"items": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"description": "",
"section": 0,
"per_location": true,
"assign": {
"type": "manager",
"ids": []
},
"start_offset": null,
"due_offset": -1,
"priority": "medium",
"requires_photo": false,
"requires_review": false,
"subtasks": [],
"tags": [],
"after": []
}
]
}
}
}POSTPreview a period
Dates of every item for the next period (or period), when the project is created, how many tasks it will have, and hints about the template (no due date, no owner, due before a dependency).
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_preview |
Path parameters
uuid
uuid
Required Request body
period
string
2026-11, 2026-Q4 or 2026-W45.
Maximum length 10. Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/preview' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"period": "string"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/preview', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"period": "string"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/preview",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"period":"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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/preview', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'period' => 'string',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_preview",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"period": "string"
}
}
}{
"data": {
"period": "2026-12",
"label": "December 2026",
"anchor": "2026-12-31",
"create_at": "2026-12-24T04:00:00+00:00",
"exists": false,
"items": [
{
"id": "i_k2m9qa",
"start": null,
"due": "2026-12-30",
"tasks": 4
}
],
"tasks": 31,
"warnings": [
{
"item": "i_p8x1za",
"kind": "no_assignee",
"text": "No owner"
}
],
"schedule_text": "every month, by the last day"
}
}POSTStart a period now
Creates the project of the next period (or of period) right away instead of waiting for the schedule. Returns the period project. Requires the admin role in the recurring project.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_run |
Path parameters
uuid
uuid
Required Request body
period
string
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/run' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"period": "string"
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/run', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"period": "string"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/run",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"period":"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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/run', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'period' => 'string',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_run",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"period": "string"
}
}
}{
"data": {
"project_uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"key": "CLS2612",
"name": "Month-end closing · December 2026",
"period": "2026-12",
"url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
}
}GETList periods
Period projects, newest first: progress, tasks done late, overdue now, when the period was closed and how many working days after (+) or before (−) the planned finish (the latest due date of its tasks).
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_periods · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/periods' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/periods', {
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/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/periods",
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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/periods', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_periods",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": [
{
"project_uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"key": "CLS2611",
"period": "2026-11",
"label": "November 2026",
"anchor": "2026-11-30",
"status": "active",
"total": 19,
"done": 19,
"progress": 100,
"done_late": 3,
"overdue": 0,
"on_time": 84,
"planned": "2026-12-10",
"finished": "2026-12-08",
"finish_delta": -2
}
]
}GETDelay rankings
Who is late most often over the last periods periods: locations, teams, people and items, with the share of late tasks and the average delay in working days.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_rankings · read-only |
Path parameters
uuid
uuid
Required Query parameters
periods
integer
6. Value 1–24.
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rankings?periods=6' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rankings?periods=6', {
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/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rankings",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"periods":6},
)
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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rankings', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'periods' => 6,
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_rankings",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"periods": 6
}
}
}{
"data": {
"periods": 6,
"locations": [
{
"id": "12",
"label": "Abay 10",
"total": 54,
"late": 9,
"late_days": 21,
"rate": 17,
"avg_days": 2.3
}
],
"teams": [],
"people": [],
"items": []
}
}GETChange log
History of the recurring project: created, template and schedule changes, pause, periods started, due dates shifted.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_events · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/events' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/events', {
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/project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/events",
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', 'project-cycles/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/events', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_events",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": [
{
"id": 41,
"type": "shifted",
"payload": {
"period": "2026-11",
"days": 2,
"tasks": 6,
"cascade": true
},
"user": {
"id": 311,
"name": "Aigerim Sadykova"
},
"at": "2026-11-30T12:00:00+05:00"
}
]
}GETPeriod summary
The summary matrix of a period project: rows — template items, columns — locations (cells by location id; items not per location are in general). Cell state: done, done_late, overdue, blocked (waits for another task), review, in_progress, todo, planned (starts later). Also readiness by location, team, person and section, delays (overdue tasks and the number of open tasks waiting for them down the chain), plan/fact chart by day and a finish forecast. Requires access to the period project.
| Token scope | read |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_summary · read-only |
Path parameters
uuid
uuid
Required Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Plan without API access
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl 'https://app.jecheck.io/api/ext/v1/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/summary' \
-H 'Authorization: Bearer $JECHECK_TOKEN'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/summary', {
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/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/summary",
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', 'project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/summary', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_summary",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}
}
}{
"data": {
"project": {
"uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"key": "CLS2611",
"name": "Month-end closing · November 2026",
"period": "2026-11",
"anchor": "2026-11-30",
"start": "2026-11-23",
"status": "active"
},
"cycle": {
"uuid": "4b0e6c2a-1d3f-4a5b-9c8d-7e6f5a4b3c2d",
"name": "Month-end closing"
},
"today": "2026-11-30",
"sections": [
"Location documents"
],
"locations": [
{
"id": "12",
"name": "Abay 10"
}
],
"rows": [
{
"id": "i_k2m9qa",
"title": "All supplier invoices entered",
"section": 0,
"per_location": true,
"extra": false,
"cells": {
"12": [
{
"key": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"seq": 1,
"title": "All supplier invoices entered",
"state": "overdue",
"open": true,
"status": 0,
"due": "2026-11-27",
"start": null,
"done_at": null,
"late": 1,
"blockers": 0,
"assignees": [
"311"
],
"team": null,
"location": "12",
"section": 201,
"item": "i_k2m9qa"
}
]
},
"general": [],
"total": 2,
"done": 1,
"progress": 50,
"overdue": 1,
"due": "2026-11-27"
}
],
"totals": {
"total": 19,
"done": 4,
"progress": 21,
"plan": 37,
"overdue": 3,
"blocked": 6,
"done_late": 1,
"unassigned": 2,
"states": {
"overdue": 3,
"done": 3
}
},
"by_location": [
{
"id": "12",
"total": 9,
"done": 2,
"overdue": 2,
"done_late": 0,
"blocked": 4,
"late_days": 3,
"progress": 22
}
],
"by_team": [],
"by_person": [],
"by_section": [],
"delays": [
{
"key": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"seq": 1,
"title": "All supplier invoices entered",
"state": "overdue",
"open": true,
"status": 0,
"due": "2026-11-27",
"start": null,
"done_at": null,
"late": 1,
"blockers": 0,
"assignees": [
"311"
],
"team": null,
"location": "12",
"section": 201,
"item": "i_k2m9qa",
"downstream": 7,
"waiting": 2
}
],
"chart": [
{
"date": "2026-11-23",
"plan": 0,
"fact": 0
}
],
"forecast": {
"done": false,
"date": "2026-12-08",
"late": 2,
"left": 15,
"pace": 1.6
}
}
}POSTShift due dates
Moves due dates and start dates of open tasks by days working days (weekends and company days off are skipped). task_uuids — which tasks (empty — all open); cascade — together with the tasks that depend on them down the chain. Each change is recorded in the task history; assignees get one notification. Requires the editor role in the period project.
| Token scope | write |
|---|---|
| Permission | Any employee; results follow the token's visibility |
| Plan feature | project_cycles |
| MCP tool | cycles_shift |
Path parameters
uuid
uuid
Required Request body
days
integer
Required task_uuids
array<string>
cascade
boolean
true. reason
string
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 401 | unauthorized — Missing, invalid, revoked or expired token
|
| 403 | forbidden · insufficient_scope · plan_required — Read-only token
|
| 404 | not_found — The record does not exist or is not visible to the token
|
| 422 | validation_failed — Invalid parameters — see error.fields
|
| 429 | rate_limited — Too many requests — retry after Retry-After seconds
|
curl -X POST 'https://app.jecheck.io/api/ext/v1/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/shift' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"days": 42,
"task_uuids": [
"example"
],
"cascade": true,
"reason": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}'const res = await fetch('https://app.jecheck.io/api/ext/v1/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/shift', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"days": 42,
"task_uuids": [
"example"
],
"cascade": true,
"reason": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/shift",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"days":42,"task_uuids":["example"],"cascade":True,"reason":"Seal on fridge #2 is torn, temperature rises to +9 °C."},
)
res.raise_for_status()
data = res.json()["data"]$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);
$res = $client->request('POST', 'project-cycles/periods/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/shift', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'days' => 42,
'task_uuids' => [
'example',
],
'cascade' => true,
'reason' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
],
]);
$data = json_decode($res->getBody(), true)['data'];{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cycles_shift",
"arguments": {
"uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"days": 42,
"task_uuids": [
"example"
],
"cascade": true,
"reason": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}
}
}{
"data": {
"moved": 6,
"tasks": [
"3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
]
}
}