jeCheckDevelopers
Get an API key

Projects

Projects with task numbers (KEY-N), sections, board columns, milestones, custom fields, members with project roles, external guests, status updates and automation rules. Access follows the project role (viewer, commenter, editor, admin); projects.manage acts as admin in every project. Tasks themselves are managed in the Tasks section with project_id.

Operations
GET/projectsList projects GET/projects/templatesList project templates GET/projects/{uuid}Retrieve a project POST/projectsCreate a project PATCH/projects/{uuid}Update a project POST/projects/{uuid}/archiveArchive a project DELETE/projects/{uuid}Delete a project POST/projects/{uuid}/duplicateDuplicate a project POST/projects/{uuid}/templateSave a project as a company template DELETE/projects/templates/{template_uuid}Delete a company template POST/projects/{uuid}/starStar or unstar a project POST/projects/{uuid}/joinJoin a project GET/projects/{uuid}/statsGet project statistics GET/projects/{uuid}/activityList project activity GET/projects/{uuid}/membersList project members POST/projects/{uuid}/membersAdd project members PATCH/projects/{uuid}/members/{user_id}Change a member's project role DELETE/projects/{uuid}/members/{user_id}Remove a project member GET/projects/{uuid}/guestsList project guests POST/projects/{uuid}/guestsInvite a project guest PATCH/projects/{uuid}/guests/{guest_id}Update a project guest DELETE/projects/{uuid}/guests/{guest_id}Revoke a guest link GET/projects/{uuid}/tasksList project tasks (board) POST/projects/{uuid}/tasks/{task_uuid}/moveMove a task on the board GET/projects/tasks/{uuid}Get the project part of a task PATCH/projects/tasks/{uuid}Update the project part of a task POST/projects/tasks/{uuid}/linksLink two tasks DELETE/projects/tasks/{uuid}/links/{id}Remove a task link POST/projects/tasks/{uuid}/timeLog time on a task DELETE/projects/tasks/{uuid}/time/{id}Delete a time log GET/projects/{uuid}/updatesList status updates POST/projects/{uuid}/updatesPost a status update DELETE/projects/{uuid}/updates/{id}Delete a status update GET/projects/{uuid}/rulesList automation rules POST/projects/{uuid}/rulesCreate an automation rule PUT/projects/{uuid}/rules/{id}Replace an automation rule POST/projects/{uuid}/rules/{id}/toggleEnable or disable a rule DELETE/projects/{uuid}/rules/{id}Delete an automation rule GET/projects/{uuid}/rules/{id}/runsList rule runs POST/projects/{uuid}/sectionsCreate a section PATCH/projects/{uuid}/sections/{id}Update a section DELETE/projects/{uuid}/sections/{id}Delete a section PUT/projects/{uuid}/sections/orderReorder sections POST/projects/{uuid}/columnsCreate a column PATCH/projects/{uuid}/columns/{id}Update a column DELETE/projects/{uuid}/columns/{id}Delete a column PUT/projects/{uuid}/columns/orderReorder columns POST/projects/{uuid}/milestonesCreate a milestone PATCH/projects/{uuid}/milestones/{id}Update a milestone DELETE/projects/{uuid}/milestones/{id}Delete a milestone PUT/projects/{uuid}/milestones/orderReorder milestones POST/projects/{uuid}/fieldsCreate a field PATCH/projects/{uuid}/fields/{id}Update a field DELETE/projects/{uuid}/fields/{id}Delete a field PUT/projects/{uuid}/fields/orderReorder fields

GETList projects

GET /projects

Projects the token can open: where it is a member or owner, projects open to the whole company, and with projects.manage — all projects. Ordered by status (active first), then by last change.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_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.
status array<string>
Filter by status: active, paused, done, archived.
starred boolean
Only projects starred by the acting user.
member boolean
Only projects where the acting user is a member or owner.
search string
Search in name and key. Maximum length 200.

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/projects?starred=true' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects?starred=true', {
  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/projects",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"starred":True},
)
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', 'projects', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'starred' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_list",
        "arguments": {
            "starred": true
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 58,
      "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
      "key": "OPEN",
      "name": "Opening: Abay Ave",
      "description": "Launch of the new coffee shop on Abay Ave.",
      "icon": "rocket_launch",
      "color": "#5b54e8",
      "status": "active",
      "health": "on_track",
      "visibility": "members",
      "start_date": "2026-11-01",
      "due_date": "2026-12-15",
      "owner": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "role": "admin",
      "created_at": "2026-10-28T09:00:00+05:00",
      "updated_at": "2026-11-03T12:10:00+05:00",
      "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
      "stats": {
        "total": 42,
        "done": 18,
        "open": 23,
        "overdue": 3,
        "progress": 44
      },
      "members_count": 6,
      "guests_count": 1,
      "starred": true,
      "last_update_at": "2026-11-02T18:00:00+05:00"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "has_more": false
  }
}

GETList project templates

GET /projects/templates

Built-in templates and the company's own templates (saved from projects). Pass the template id as template when creating a project. Company templates are listed only with projects.create.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_templates_list · read-only

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Plan without API access
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/projects/templates' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/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/projects/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', 'projects/templates', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_templates_list",
        "arguments": {}
    }
}
Response 200
{
  "data": [
    {
      "id": "opening",
      "name": "Opening a new location",
      "description": "Everything from lease to soft opening",
      "icon": "storefront",
      "company": false,
      "tasks_count": 34,
      "days": 60
    }
  ]
}

GETRetrieve a project

GET /projects/{uuid}

Project card with the acting user's role and permissions, sections, board columns, milestones, custom fields, members, guests (only for project admins with projects.guests) and progress figures.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_get · read-only

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/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/projects/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', 'projects/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": "projects_get",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

POSTCreate a project

POST /projects

Creates a project, empty or from a template (see projects.templates.list). The creator and the owner become project admins. Requires projects.create.

Token scopewrite
Permission projects.create
MCP toolprojects_create

Request body

name string Required
Project name. Length 2–200.
key string
Task number prefix: 2–10 Latin letters/digits starting with a letter (e.g. OPEN). Generated from the name if omitted. Maximum length 10.
description string | null
Description. Maximum length 20000.
icon string
Material Symbols icon name, e.g. rocket_launch. Maximum length 40.
color string
Hex color, e.g. #5b54e8. Maximum length 9.
visibility string
members — only members see the project; company — every employee can open it and join.
memberscompany
start_date date | null
Start date.
due_date date | null
Due date.
owner_id integer
Owner (user id); always an admin of the project.
template string
Template id: a built-in template key or a company template UUID. Maximum length 64.
members array<object>
Members to add. Maximum items 200.
user_id integer Required
User id.
role string
Project role, default editor.
admineditorcommenterviewer

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.create, 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/projects' \
  -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/projects', {
  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/projects",
    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', 'projects', [
    '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": "projects_create",
        "arguments": {
            "name": "Replace the broken fridge seal",
            "key": "string",
            "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
            "icon": "string"
        }
    }
}
Response 201
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

PATCHUpdate a project

PATCH /projects/{uuid}

Partial update of project settings. Requires the admin role in the project (or projects.manage). Setting status to done stamps the completion time.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

name string
Project name. Length 2–200.
key string
Task number prefix: 2–10 Latin letters/digits starting with a letter (e.g. OPEN). Generated from the name if omitted. Maximum length 10.
description string | null
Description. Maximum length 20000.
icon string
Material Symbols icon name, e.g. rocket_launch. Maximum length 40.
color string
Hex color, e.g. #5b54e8. Maximum length 9.
visibility string
members — only members see the project; company — every employee can open it and join.
memberscompany
start_date date | null
Start date.
due_date date | null
Due date.
owner_id integer
Owner (user id); always an admin of the project.
status string
Project status.
activepauseddonearchived
health string | null
Health indicator.
on_trackat_riskoff_track
guest_scope string
What guests see: all tasks or only tasks assigned to them.
allassigned
time_tracking boolean
Enable time logging in tasks.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/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/projects/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/projects/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', 'projects/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": "projects_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"
        }
    }
}
Response 200
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

POSTArchive a project

POST /projects/{uuid}/archive

Moves the project to the archive (status archived). Restore it with projects.update and status: active. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/archive' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/archive', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/archive",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/archive', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_archive",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

DELDelete a project

DELETE /projects/{uuid}

Deletes the project together with its tasks (soft delete) and revokes guest links. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/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/projects/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', 'projects/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": "projects_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

POSTDuplicate a project

POST /projects/{uuid}/duplicate

Creates a copy with the same structure and, optionally, tasks (dates shift relative to the new start date) and people. Requires projects.create.

Token scopewrite
Permission projects.create
MCP toolprojects_duplicate

Path parameters

uuid uuid Required
Project UUID.

Request body

name string
Name of the copy, default " (copy)". Length 2–200.
start_date date
Start date of the copy, default today.
tasks boolean
Copy tasks. Default true.
people boolean
Keep assignees in copied tasks. Default false.

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.create, 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 POST 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "start_date": "2026-11-01",
    "tasks": true,
    "people": false
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/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",
      "start_date": "2026-11-01",
      "tasks": true,
      "people": false
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","start_date":"2026-11-01","tasks":True,"people":False},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/duplicate', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'start_date' => '2026-11-01',
        'tasks' => true,
        'people' => false,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_duplicate",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal",
            "start_date": "2026-11-01",
            "tasks": true,
            "people": false
        }
    }
}
Response 201
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

POSTSave a project as a company template

POST /projects/{uuid}/template

Saves the project structure and tasks as a company template. Requires projects.create.

Token scopewrite
Permission projects.create
MCP toolprojects_templates_create

Path parameters

uuid uuid Required
Project UUID.

Request body

name string
Template name, default — project name. Length 2–200.

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.create, 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 POST 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/template' \
  -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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/template', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/template",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/template', [
    '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": "projects_templates_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal"
        }
    }
}
Response 201
{
  "data": {
    "id": "6d5c4b3a-2f1e-4d0c-9b8a-7f6e5d4c3b2a",
    "name": "Opening a location",
    "company": true
  }
}

DELDelete a company template

DELETE /projects/templates/{template_uuid}
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_templates_delete · destructive

Path parameters

template_uuid uuid Required
Company template UUID.

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/projects/templates/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/templates/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/projects/templates/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', 'projects/templates/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": "projects_templates_delete",
        "arguments": {
            "template_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

POSTStar or unstar a project

POST /projects/{uuid}/star

Starred projects are shown in the side menu of the acting user.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

on boolean
true — star, false — unstar. Default true.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/star' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "on": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/star', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "on": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/star",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"on":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/star', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'on' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_star",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "on": true
        }
    }
}
Response 200
{
  "data": {
    "starred": true
  }
}

POSTJoin a project

POST /projects/{uuid}/join

Joins a project open to the whole company as an editor.

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

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/join' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/join', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/join",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/join', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_join",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "id": 58,
    "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "key": "OPEN",
    "name": "Opening: Abay Ave",
    "description": "Launch of the new coffee shop on Abay Ave.",
    "icon": "rocket_launch",
    "color": "#5b54e8",
    "status": "active",
    "health": "on_track",
    "visibility": "members",
    "start_date": "2026-11-01",
    "due_date": "2026-12-15",
    "owner": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "role": "admin",
    "created_at": "2026-10-28T09:00:00+05:00",
    "updated_at": "2026-11-03T12:10:00+05:00",
    "url": "https://app.jecheck.io/ui/projects/8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "completed_at": null,
    "starred": true,
    "settings": {
      "guest_scope": "all",
      "time_tracking": true
    },
    "permissions": {
      "edit": true,
      "comment": true,
      "manage": true,
      "invite_guests": true,
      "join": false
    },
    "sections": [
      {
        "id": 201,
        "name": "Equipment"
      }
    ],
    "columns": [
      {
        "id": 301,
        "name": "In progress",
        "status": "in_progress",
        "color": "#f59e0b",
        "wip_limit": 5
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "description": "",
        "due_date": "2026-12-01",
        "done": false
      }
    ],
    "fields": [
      {
        "id": 501,
        "name": "Supplier",
        "type": "select",
        "options": [
          {
            "id": "o_k2m9qa",
            "label": "Metro",
            "color": "#22c55e"
          }
        ],
        "on_card": true
      }
    ],
    "members": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "role": "admin"
      }
    ],
    "guests": [
      {
        "id": 12,
        "name": "Ivan Petrov",
        "email": "[email protected]",
        "company": "BuildCo",
        "role": "editor",
        "tasks_count": 4,
        "last_seen_at": "2026-11-02T15:30:00+05:00",
        "invited_at": "2026-10-29T10:00:00+05:00",
        "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
      }
    ],
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "unassigned": 2,
      "progress": 44,
      "forecast": "2026-12-20"
    }
  }
}

GETGet project statistics

GET /projects/{uuid}/stats

Progress, workload by assignee, milestones progress, weekly velocity (8 weeks), burn-up and the completion forecast.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_stats · read-only

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/stats' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/stats', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/stats",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/stats', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_stats",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "total": 42,
    "done": 18,
    "open": 23,
    "overdue": 3,
    "unassigned": 2,
    "done_week": 5,
    "created_week": 7,
    "due_week": 6,
    "progress": 44,
    "estimate_minutes": 9600,
    "spent_minutes": 4100,
    "workload": [
      {
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "open": 6,
        "overdue": 1
      }
    ],
    "milestones": [
      {
        "id": 401,
        "title": "Soft opening",
        "due_date": "2026-12-01",
        "done": false,
        "total": 12,
        "closed": 5
      }
    ],
    "velocity": [
      {
        "week": "2026-10-27",
        "closed": 5
      }
    ],
    "burnup": [
      {
        "date": "2026-11-01",
        "scope": 40,
        "done": 15
      }
    ],
    "forecast": "2026-12-20",
    "avg_per_week": 4.5
  }
}

GETList project activity

GET /projects/{uuid}/activity

Latest project and task events (up to 60), newest first. Page back with before = at of the last event.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_activity · read-only

Path parameters

uuid uuid Required
Project UUID.

Query parameters

before date-time
Only events before this moment.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/activity?before=2026-11-03T09:00:00+05:00' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/activity?before=2026-11-03T09:00:00+05:00', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/activity",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"before":"2026-11-03T09:00:00+05:00"},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/activity', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'before' => '2026-11-03T09:00:00+05:00',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_activity",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "before": "2026-11-03T09:00:00+05:00"
        }
    }
}
Response 200
{
  "data": [
    {
      "scope": "task",
      "type": "status",
      "user": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "guest_name": null,
      "payload": {
        "from": "new",
        "to": "in_progress"
      },
      "task": {
        "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
        "key": "OPEN-12",
        "title": "Install the espresso machine"
      },
      "at": "2026-11-03T12:01:00+05:00"
    }
  ]
}

GETList project members

GET /projects/{uuid}/members
Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_members_list · read-only

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_members_list",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": [
    {
      "user": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "role": "admin"
    }
  ]
}

POSTAdd project members

POST /projects/{uuid}/members

Adds employees with one project role (default editor); existing members get the new role. Added people are notified. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

user_ids array<integer> Required
User ids. Items 1–200.
role string
Project role. Default editor.
admineditorcommenterviewer

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_ids": [
        12,
        14
    ],
    "role": "editor"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "user_ids": [
          12,
          14
      ],
      "role": "editor"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"user_ids":[12,14],"role":"editor"},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'user_ids' => [
            12,
            14,
        ],
        'role' => 'editor',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_members_add",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "user_ids": [
                12,
                14
            ],
            "role": "editor"
        }
    }
}
Response 200
{
  "data": [
    {
      "user": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "role": "editor"
    }
  ]
}

PATCHChange a member's project role

PATCH /projects/{uuid}/members/{user_id}
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_members_update

Path parameters

uuid uuid Required
Project UUID.
user_id integer Required
User id.

Request body

role string Required
admineditorcommenterviewer

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "role": "admin"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "role": "admin"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"role":"admin"},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'role' => 'admin',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_members_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "user_id": 42,
            "role": "admin"
        }
    }
}
Response 200
{
  "data": [
    {
      "user": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "role": "commenter"
    }
  ]
}

DELRemove a project member

DELETE /projects/{uuid}/members/{user_id}

Removes a member (admin role required) or leaves the project when user_id is the acting user. The owner cannot be removed.

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

Path parameters

uuid uuid Required
Project UUID.
user_id integer Required
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 DELETE 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/members/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_members_remove",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "user_id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

GETList project guests

GET /projects/{uuid}/guests

External participants with personal links (url gives access without an account — keep it secret). Requires the admin role in the project and projects.guests.

Token scoperead
Permission projects.guests
MCP toolprojects_guests_list · read-only

Path parameters

uuid uuid Required
Project UUID.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.guests
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_guests_list",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 12,
      "name": "Ivan Petrov",
      "email": "[email protected]",
      "company": "BuildCo",
      "role": "editor",
      "tasks_count": 4,
      "last_seen_at": "2026-11-02T15:30:00+05:00",
      "invited_at": "2026-10-29T10:00:00+05:00",
      "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
    }
  ]
}

POSTInvite a project guest

POST /projects/{uuid}/guests

Invites a contractor or client by e-mail: they get a personal link to the project (up to 50 guests per project). Requires the admin role in the project and projects.guests.

Token scopewrite
Permission projects.guests
MCP toolprojects_guests_invite

Path parameters

uuid uuid Required
Project UUID.

Request body

name string Required
Guest name. Length 2–120.
email string Required
Guest e-mail. Maximum length 190.
company string
Guest company. Maximum length 120.
role string
Guest role. Default editor.
editorcommenterviewer
message string
Personal message in the invitation. Maximum length 2000.
locale string
Invitation language (ru, en, kk, …), default — company language. Maximum length 5.
send boolean
Send the invitation e-mail. Default true.

Responses

StatusDescription
201Created
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.guests, 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 POST 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "email": "[email protected]",
    "company": "string",
    "role": "editor"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "email": "[email protected]",
      "company": "string",
      "role": "editor"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","email":"[email protected]","company":"string","role":"editor"},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'email' => '[email protected]',
        'company' => 'string',
        'role' => 'editor',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_guests_invite",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal",
            "email": "[email protected]",
            "company": "string",
            "role": "editor"
        }
    }
}
Response 201
{
  "data": {
    "id": 12,
    "name": "Ivan Petrov",
    "email": "[email protected]",
    "company": "BuildCo",
    "role": "editor",
    "tasks_count": 4,
    "last_seen_at": "2026-11-02T15:30:00+05:00",
    "invited_at": "2026-10-29T10:00:00+05:00",
    "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
  }
}

PATCHUpdate a project guest

PATCH /projects/{uuid}/guests/{guest_id}

Changes the role, name or company; resend re-sends the invitation, rotate issues a new link (the old one stops working).

Token scopewrite
Permission projects.guests
MCP toolprojects_guests_update

Path parameters

uuid uuid Required
Project UUID.
guest_id integer Required
Guest id.

Request body

role string
editorcommenterviewer
name string
Length 2–120.
company string | null
Maximum length 120.
resend boolean
Re-send the invitation e-mail.
rotate boolean
Issue a new personal link.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks projects.guests, 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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "role": "editor",
    "name": "Replace the broken fridge seal",
    "company": "string",
    "resend": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "role": "editor",
      "name": "Replace the broken fridge seal",
      "company": "string",
      "resend": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"role":"editor","name":"Replace the broken fridge seal","company":"string","resend":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/guests/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'role' => 'editor',
        'name' => 'Replace the broken fridge seal',
        'company' => 'string',
        'resend' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_guests_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "guest_id": 42,
            "role": "editor",
            "name": "Replace the broken fridge seal",
            "company": "string",
            "resend": true
        }
    }
}
Response 200
{
  "data": {
    "id": 12,
    "name": "Ivan Petrov",
    "email": "[email protected]",
    "company": "BuildCo",
    "role": "editor",
    "tasks_count": 4,
    "last_seen_at": "2026-11-02T15:30:00+05:00",
    "invited_at": "2026-10-29T10:00:00+05:00",
    "url": "https://app.jecheck.io/pg/Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56"
  }
}

DELRevoke a guest link

DELETE /projects/{uuid}/guests/{guest_id}
Token scopewrite
Permission projects.guests
MCP toolprojects_guests_revoke · destructive

Path parameters

uuid uuid Required
Project UUID.
guest_id integer Required
Guest id.

Responses

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

GETList project tasks (board)

GET /projects/{uuid}/tasks

Tasks of the project in board order (rank) with section, column, milestone, dates, estimate, logged time and custom field values (fields: field id → value). Closed tasks are included. Use the Tasks section for the full task card and changes.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_tasks_list · read-only

Path parameters

uuid uuid Required
Project UUID.

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.
section_id integer
Only this section.
column_id integer
Only this board column.
milestone_id integer
Only this milestone.
status array<string>
Filter by status: new, in_progress, review, approval, done, rejected.
assignee_id integer
Only tasks assigned to this 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
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks?section_id=42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks?section_id=42', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"section_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('GET', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'section_id' => 42,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_tasks_list",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "section_id": 42
        }
    }
}
Response 200
{
  "data": [
    {
      "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
      "key": "OPEN-12",
      "title": "Install the espresso machine",
      "status": "in_progress",
      "priority": "high",
      "assignees": [
        {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        }
      ],
      "section_id": 201,
      "column_id": 301,
      "milestone_id": 401,
      "start_date": "2026-11-04",
      "due_date": "2026-11-10",
      "estimate_minutes": 240,
      "spent_minutes": 90,
      "tags": [
        "Equipment"
      ],
      "fields": {
        "501": "o_k2m9qa"
      },
      "guest_ids": [
        12
      ],
      "blocked_by_open": 0,
      "rank": 3.5,
      "completed_at": null,
      "updated_at": "2026-11-03T12:01:00+05:00",
      "url": "https://app.jecheck.io/ui/tasks?task=3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "has_more": false
  }
}

POSTMove a task on the board

POST /projects/{uuid}/tasks/{task_uuid}/move

Same as drag and drop: puts the task between before_uuid and after_uuid (rank), and optionally into another column (its status changes accordingly — loop rules may keep it), section or milestone. Requires the editor role.

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

Path parameters

uuid uuid Required
Project UUID.
task_uuid uuid Required
Task UUID.

Request body

column_id integer
Target board column.
section_id integer | null
Target section (null — no section).
milestone_id integer | null
Target milestone (null — none).
before_uuid uuid | null
Task that should end up right before this one.
after_uuid uuid | null
Task that should end up right after this one.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/move' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "column_id": 42,
    "section_id": 42,
    "milestone_id": 42,
    "before_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/move', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "column_id": 42,
      "section_id": 42,
      "milestone_id": 42,
      "before_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/move",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"column_id":42,"section_id":42,"milestone_id":42,"before_uuid":"3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/move', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'column_id' => 42,
        'section_id' => 42,
        'milestone_id' => 42,
        'before_uuid' => '3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_tasks_move",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "task_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "column_id": 42,
            "section_id": 42,
            "milestone_id": 42,
            "before_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
    "status": "in_progress",
    "column_id": 301,
    "section_id": 201,
    "milestone_id": 401,
    "rank": 3.5
  }
}

GETGet the project part of a task

GET /projects/tasks/{uuid}

Project-specific data of a task: section, column, milestone, custom field values, guests, links to other tasks and time logs.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_tasks_get · read-only

Path parameters

uuid uuid Required
Task UUID (the task must belong to a project).

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/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/tasks/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/projects/tasks/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', 'projects/tasks/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": "projects_tasks_get",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": {
    "task_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
    "project": {
      "id": 58,
      "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
      "key": "OPEN",
      "name": "Opening: Abay Ave"
    },
    "role": "editor",
    "section_id": 201,
    "column_id": 301,
    "milestone_id": 401,
    "fields": {
      "501": "o_k2m9qa"
    },
    "guest_ids": [
      12
    ],
    "links": [
      {
        "id": 77,
        "type": "blocked_by",
        "task": {
          "uuid": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
          "key": "OPEN-9",
          "title": "Deliver the machine",
          "status": "done",
          "due_date": "2026-11-05"
        }
      }
    ],
    "time_logs": [
      {
        "id": 901,
        "minutes": 90,
        "date": "2026-11-03",
        "note": "Plumbing",
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "guest_name": null
      }
    ],
    "spent_minutes": 90
  }
}

PATCHUpdate the project part of a task

PATCH /projects/tasks/{uuid}

Sets section, milestone, board column, custom field values (fields: field id → value; null clears; select — option id, multiselect — array of option ids, user — user id) and assigned guests. Requires the editor role.

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

Path parameters

uuid uuid Required
Task UUID (the task must belong to a project).

Request body

section_id integer | null
milestone_id integer | null
column_id integer
Board column (changes the status as on the board).
fields object
Custom field values: {"": value}.
guest_ids array<integer>
Project guests assigned to the task (replaces the list). Maximum items 20.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "section_id": 42,
    "milestone_id": 42,
    "column_id": 42,
    "fields": []
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "section_id": 42,
      "milestone_id": 42,
      "column_id": 42,
      "fields": []
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"section_id":42,"milestone_id":42,"column_id":42,"fields":[]},
)
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', 'projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'section_id' => 42,
        'milestone_id' => 42,
        'column_id' => 42,
        'fields' => [
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_tasks_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "section_id": 42,
            "milestone_id": 42,
            "column_id": 42,
            "fields": []
        }
    }
}
Response 200
{
  "data": {
    "task_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
    "project": {
      "id": 58,
      "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
      "key": "OPEN",
      "name": "Opening: Abay Ave"
    },
    "role": "editor",
    "section_id": 201,
    "column_id": 301,
    "milestone_id": 401,
    "fields": {
      "501": "o_k2m9qa"
    },
    "guest_ids": [
      12
    ],
    "links": [
      {
        "id": 77,
        "type": "blocked_by",
        "task": {
          "uuid": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
          "key": "OPEN-9",
          "title": "Deliver the machine",
          "status": "done",
          "due_date": "2026-11-05"
        }
      }
    ],
    "time_logs": [
      {
        "id": 901,
        "minutes": 90,
        "date": "2026-11-03",
        "note": "Plumbing",
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "guest_name": null
      }
    ],
    "spent_minutes": 90
  }
}

POSTLog time on a task

POST /projects/tasks/{uuid}/time
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_tasks_time_create

Path parameters

uuid uuid Required
Task UUID (the task must belong to a project).

Request body

minutes integer Required
Minutes spent (1–1440). Value 1–1440.
date date
Day of work, default today.
note string
Note. Maximum length 500.

Responses

StatusDescription
201Created
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/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "minutes": 42,
    "date": "2026-11-01",
    "note": "Seal on fridge #2 is torn, temperature rises to +9 °C."
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "minutes": 42,
      "date": "2026-11-01",
      "note": "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/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"minutes":42,"date":"2026-11-01","note":"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', 'projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'minutes' => 42,
        'date' => '2026-11-01',
        'note' => '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": "projects_tasks_time_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "minutes": 42,
            "date": "2026-11-01",
            "note": "Seal on fridge #2 is torn, temperature rises to +9 °C."
        }
    }
}
Response 201
{
  "data": {
    "task_uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
    "project": {
      "id": 58,
      "uuid": "8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
      "key": "OPEN",
      "name": "Opening: Abay Ave"
    },
    "role": "editor",
    "section_id": 201,
    "column_id": 301,
    "milestone_id": 401,
    "fields": {
      "501": "o_k2m9qa"
    },
    "guest_ids": [
      12
    ],
    "links": [
      {
        "id": 77,
        "type": "blocked_by",
        "task": {
          "uuid": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
          "key": "OPEN-9",
          "title": "Deliver the machine",
          "status": "done",
          "due_date": "2026-11-05"
        }
      }
    ],
    "time_logs": [
      {
        "id": 901,
        "minutes": 90,
        "date": "2026-11-03",
        "note": "Plumbing",
        "user": {
          "id": 311,
          "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
          "name": "Aigerim Sadykova"
        },
        "guest_name": null
      }
    ],
    "spent_minutes": 90
  }
}

DELDelete a time log

DELETE /projects/tasks/{uuid}/time/{id}

Own time logs can be deleted by their author; any — by project admins.

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

Path parameters

uuid uuid Required
Task UUID (the task must belong to a project).
id integer Required
Time log 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/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time/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/projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time/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', 'projects/tasks/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/time/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_tasks_time_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

GETList status updates

GET /projects/{uuid}/updates
Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_updates_list · read-only

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_updates_list",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 31,
      "health": "on_track",
      "body": "Equipment delivered, staff hired.",
      "stats": {
        "total": 42,
        "done": 18,
        "open": 23,
        "overdue": 3,
        "progress": 44,
        "forecast": "2026-12-20"
      },
      "author": {
        "id": 311,
        "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
        "name": "Aigerim Sadykova"
      },
      "created_at": "2026-11-02T18:00:00+05:00"
    }
  ]
}

POSTPost a status update

POST /projects/{uuid}/updates

Posts a status report with health; the project health changes and members are notified. Requires the editor role.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

health string Required
on_trackat_riskoff_track
body string Required
Report text. Length 2–10000.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "health": "on_track",
    "body": "string"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "health": "on_track",
      "body": "string"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"health":"on_track","body":"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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'health' => 'on_track',
        'body' => 'string',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_updates_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "health": "on_track",
            "body": "string"
        }
    }
}
Response 201
{
  "data": {
    "id": 31,
    "health": "on_track",
    "body": "Equipment delivered, staff hired.",
    "stats": {
      "total": 42,
      "done": 18,
      "open": 23,
      "overdue": 3,
      "progress": 44,
      "forecast": "2026-12-20"
    },
    "author": {
      "id": 311,
      "uuid": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "name": "Aigerim Sadykova"
    },
    "created_at": "2026-11-02T18:00:00+05:00"
  }
}

DELDelete a status update

DELETE /projects/{uuid}/updates/{id}

The author or a project admin can delete an update.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Update 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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/updates/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_updates_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

GETList automation rules

GET /projects/{uuid}/rules

Project automation rules ("when … if … then …"). Requires the admin role in the project. Ids inside trigger, conditions and actions refer to columns, sections, milestones, fields and users of this project.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_rules_list · read-only

Path parameters

uuid uuid Required
Project UUID.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_list",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 14,
      "name": "Done → notify the owner",
      "enabled": true,
      "trigger": {
        "type": "column_changed",
        "column": "305"
      },
      "conditions": [
        {
          "field": "priority",
          "op": "is",
          "value": "urgent"
        }
      ],
      "actions": [
        {
          "type": "notify",
          "to": [
            "owner"
          ],
          "text": "Urgent task closed"
        }
      ],
      "runs": 12,
      "last_run_at": "2026-11-03T12:01:00+05:00"
    }
  ]
}

POSTCreate an automation rule

POST /projects/{uuid}/rules

Triggers: task_created, column_changed, status_changed, section_changed, assigned, field_changed, commented, subtasks_done, unblocked, due_soon, overdue. Conditions (up to 10) on: priority, column, section, milestone, assignee, tag, title, field with op is/not/empty/not_empty/contains. Actions (1–12): move_column, move_section, set_milestone, assign, unassign, watchers, priority, due, start, tags, field, subtasks, comment, notify, create_task. Up to 50 rules per project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

name string
Rule name. Maximum length 200.
trigger object Required
{"type": "", ...}: column for column_changed, section for section_changed, status for status_changed, field+value for field_changed, days for due_soon, guest: true for commented.
conditions array<object>
[{"field", "op", "value", "id"}]; id — custom field id when field = field. Maximum items 10.
actions array<object> Required
[{"type", ...}], e.g. {"type": "move_column", "column": 301}, {"type": "assign", "users": [311], "mode": "add"}, {"type": "comment", "text": "…"}. Items 1–12.
enabled boolean
Default true.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "trigger": [],
    "conditions": [
        []
    ],
    "actions": [
        []
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "trigger": [],
      "conditions": [
          []
      ],
      "actions": [
          []
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","trigger":[],"conditions":[[]],"actions":[[]]},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'trigger' => [
        ],
        'conditions' => [
            [
            ],
        ],
        'actions' => [
            [
            ],
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal",
            "trigger": [],
            "conditions": [
                []
            ],
            "actions": [
                []
            ]
        }
    }
}
Response 201
{
  "data": {
    "id": 14,
    "name": "Done → notify the owner",
    "enabled": true,
    "trigger": {
      "type": "column_changed",
      "column": "305"
    },
    "conditions": [
      {
        "field": "priority",
        "op": "is",
        "value": "urgent"
      }
    ],
    "actions": [
      {
        "type": "notify",
        "to": [
          "owner"
        ],
        "text": "Urgent task closed"
      }
    ],
    "runs": 12,
    "last_run_at": "2026-11-03T12:01:00+05:00"
  }
}

PUTReplace an automation rule

PUT /projects/{uuid}/rules/{id}

Replaces the whole rule definition (same fields as on creation).

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Rule id.

Request body

name string
Rule name. Maximum length 200.
trigger object Required
{"type": "", ...}: column for column_changed, section for section_changed, status for status_changed, field+value for field_changed, days for due_soon, guest: true for commented.
conditions array<object>
[{"field", "op", "value", "id"}]; id — custom field id when field = field. Maximum items 10.
actions array<object> Required
[{"type", ...}], e.g. {"type": "move_column", "column": 301}, {"type": "assign", "users": [311], "mode": "add"}, {"type": "comment", "text": "…"}. Items 1–12.
enabled boolean
Default true.

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 PUT 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "trigger": [],
    "conditions": [
        []
    ],
    "actions": [
        []
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "trigger": [],
      "conditions": [
          []
      ],
      "actions": [
          []
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","trigger":[],"conditions":[[]],"actions":[[]]},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'trigger' => [
        ],
        'conditions' => [
            [
            ],
        ],
        'actions' => [
            [
            ],
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "name": "Replace the broken fridge seal",
            "trigger": [],
            "conditions": [
                []
            ],
            "actions": [
                []
            ]
        }
    }
}
Response 200
{
  "data": {
    "id": 14,
    "name": "Done → notify the owner",
    "enabled": true,
    "trigger": {
      "type": "column_changed",
      "column": "305"
    },
    "conditions": [
      {
        "field": "priority",
        "op": "is",
        "value": "urgent"
      }
    ],
    "actions": [
      {
        "type": "notify",
        "to": [
          "owner"
        ],
        "text": "Urgent task closed"
      }
    ],
    "runs": 12,
    "last_run_at": "2026-11-03T12:01:00+05:00"
  }
}

POSTEnable or disable a rule

POST /projects/{uuid}/rules/{id}/toggle
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_rules_toggle

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Rule id.

Request body

enabled boolean Required

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/toggle' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/toggle', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "enabled": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/toggle",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"enabled":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/toggle', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'enabled' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_toggle",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "enabled": true
        }
    }
}
Response 200
{
  "data": {
    "id": 14,
    "name": "Done → notify the owner",
    "enabled": true,
    "trigger": {
      "type": "column_changed",
      "column": "305"
    },
    "conditions": [
      {
        "field": "priority",
        "op": "is",
        "value": "urgent"
      }
    ],
    "actions": [
      {
        "type": "notify",
        "to": [
          "owner"
        ],
        "text": "Urgent task closed"
      }
    ],
    "runs": 12,
    "last_run_at": "2026-11-03T12:01:00+05:00"
  }
}

DELDelete an automation rule

DELETE /projects/{uuid}/rules/{id}
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_rules_delete · destructive

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Rule 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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

GETList rule runs

GET /projects/{uuid}/rules/{id}/runs

Last 50 runs of the rule: when, on which task, success or the reason of failure.

Token scoperead
Permission Any employee; results follow the token's visibility
MCP toolprojects_rules_runs · read-only

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Rule 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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/runs' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/runs', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/runs",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/rules/42/runs', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_rules_runs",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": [
    {
      "trigger": "column_changed",
      "ok": true,
      "note": null,
      "task": {
        "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
        "key": "OPEN-12",
        "title": "Install the espresso machine"
      },
      "at": "2026-11-03T12:01:00+05:00"
    }
  ]
}

POSTCreate a section

POST /projects/{uuid}/sections

Adds a section to the project. Requires the editor role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

name string Required
Section name. Length 1–120.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections' \
  -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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections', {
  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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections",
    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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections', [
    '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": "projects_sections_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal"
        }
    }
}
Response 201
{
  "data": {
    "id": 201,
    "name": "Equipment"
  }
}

PATCHUpdate a section

PATCH /projects/{uuid}/sections/{id}

Partial update. Requires the editor role in the project.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Section id.

Request body

name string Required
Section name. Length 1–120.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42' \
  -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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42', {
  method: 'PATCH',
  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.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42",
    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('PATCH', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42', [
    '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": "projects_sections_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "name": "Replace the broken fridge seal"
        }
    }
}
Response 200
{
  "data": {
    "id": 201,
    "name": "Equipment"
  }
}

DELDelete a section

DELETE /projects/{uuid}/sections/{id}

Tasks of the section move to move_to_id or are left without a section.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Section id.

Query parameters

move_to_id integer
Where to move its tasks.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_sections_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

PUTReorder sections

PUT /projects/{uuid}/sections/order
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_sections_reorder

Path parameters

uuid uuid Required
Project UUID.

Request body

ids array<integer> Required
All ids in the new order. Minimum items 1.

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 PUT 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/order' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "ids": [
        12,
        14
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/order', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "ids": [
          12,
          14
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/order",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"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('PUT', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/sections/order', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'ids' => [
            12,
            14,
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_sections_reorder",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "ids": [
                12,
                14
            ]
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 201,
      "name": "Equipment"
    }
  ]
}

POSTCreate a column

POST /projects/{uuid}/columns

Adds a column to the project. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

name string Required
Column name. Length 1–60.
status string Required
Task status the column stands for.
newin_progressreviewdonerejected
color string | null
Hex color. Maximum length 9.
wip_limit integer | null
Work-in-progress limit. Value 1–999.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "status": "new",
    "color": "string",
    "wip_limit": 42
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "status": "new",
      "color": "string",
      "wip_limit": 42
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","status":"new","color":"string","wip_limit":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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'status' => 'new',
        'color' => 'string',
        'wip_limit' => 42,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_columns_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal",
            "status": "new",
            "color": "string",
            "wip_limit": 42
        }
    }
}
Response 201
{
  "data": {
    "id": 301,
    "name": "In progress",
    "status": "in_progress",
    "color": "#f59e0b",
    "wip_limit": 5
  }
}

PATCHUpdate a column

PATCH /projects/{uuid}/columns/{id}

Changing the column status moves its tasks to that status (normal status change with notifications).

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Board column id.

Request body

name string
Column name. Length 1–60.
status string
Task status the column stands for.
newin_progressreviewdonerejected
color string | null
Hex color. Maximum length 9.
wip_limit integer | null
Work-in-progress limit. Value 1–999.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "status": "new",
    "color": "string",
    "wip_limit": 42
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "status": "new",
      "color": "string",
      "wip_limit": 42
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","status":"new","color":"string","wip_limit":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('PATCH', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'status' => 'new',
        'color' => 'string',
        'wip_limit' => 42,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_columns_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "name": "Replace the broken fridge seal",
            "status": "new",
            "color": "string",
            "wip_limit": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 301,
    "name": "In progress",
    "status": "in_progress",
    "color": "#f59e0b",
    "wip_limit": 5
  }
}

DELDelete a column

DELETE /projects/{uuid}/columns/{id}

Tasks of the column move to move_to_id (or a column with the same status). The last column cannot be deleted.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Board column id.

Query parameters

move_to_id integer
Where to move its tasks.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_columns_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

PUTReorder columns

PUT /projects/{uuid}/columns/order
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_columns_reorder

Path parameters

uuid uuid Required
Project UUID.

Request body

ids array<integer> Required
All ids in the new order. Minimum items 1.

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 PUT 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/order' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "ids": [
        12,
        14
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/order', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "ids": [
          12,
          14
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/order",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"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('PUT', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/columns/order', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'ids' => [
            12,
            14,
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_columns_reorder",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "ids": [
                12,
                14
            ]
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 301,
      "name": "In progress",
      "status": "in_progress",
      "color": "#f59e0b",
      "wip_limit": 5
    }
  ]
}

POSTCreate a milestone

POST /projects/{uuid}/milestones

Adds a milestone to the project. Requires the editor role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

title string Required
Milestone title. Length 1–200.
description string | null
Maximum length 5000.
due_date date | null
done boolean
Mark as reached.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Replace the broken fridge seal",
    "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
    "due_date": "2026-11-01",
    "done": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "title": "Replace the broken fridge seal",
      "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
      "due_date": "2026-11-01",
      "done": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"title":"Replace the broken fridge seal","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","due_date":"2026-11-01","done":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'title' => 'Replace the broken fridge seal',
        'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
        'due_date' => '2026-11-01',
        'done' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_milestones_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "title": "Replace the broken fridge seal",
            "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
            "due_date": "2026-11-01",
            "done": true
        }
    }
}
Response 201
{
  "data": {
    "id": 401,
    "title": "Soft opening",
    "description": "",
    "due_date": "2026-12-01",
    "done": false
  }
}

PATCHUpdate a milestone

PATCH /projects/{uuid}/milestones/{id}

Partial update. Requires the editor role in the project.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Milestone id.

Request body

title string
Milestone title. Length 1–200.
description string | null
Maximum length 5000.
due_date date | null
done boolean
Mark as reached.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Replace the broken fridge seal",
    "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
    "due_date": "2026-11-01",
    "done": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "title": "Replace the broken fridge seal",
      "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
      "due_date": "2026-11-01",
      "done": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"title":"Replace the broken fridge seal","description":"Seal on fridge #2 is torn, temperature rises to +9 °C.","due_date":"2026-11-01","done":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'title' => 'Replace the broken fridge seal',
        'description' => 'Seal on fridge #2 is torn, temperature rises to +9 °C.',
        'due_date' => '2026-11-01',
        'done' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_milestones_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "title": "Replace the broken fridge seal",
            "description": "Seal on fridge #2 is torn, temperature rises to +9 °C.",
            "due_date": "2026-11-01",
            "done": true
        }
    }
}
Response 200
{
  "data": {
    "id": 401,
    "title": "Soft opening",
    "description": "",
    "due_date": "2026-12-01",
    "done": false
  }
}

DELDelete a milestone

DELETE /projects/{uuid}/milestones/{id}

Tasks of the milestone move to move_to_id or are left without a milestone.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Milestone id.

Query parameters

move_to_id integer
Where to move its tasks.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_milestones_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

PUTReorder milestones

PUT /projects/{uuid}/milestones/order
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_milestones_reorder

Path parameters

uuid uuid Required
Project UUID.

Request body

ids array<integer> Required
All ids in the new order. Minimum items 1.

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 PUT 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/order' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "ids": [
        12,
        14
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/order', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "ids": [
          12,
          14
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/order",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"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('PUT', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/milestones/order', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'ids' => [
            12,
            14,
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_milestones_reorder",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "ids": [
                12,
                14
            ]
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 401,
      "title": "Soft opening",
      "description": "",
      "due_date": "2026-12-01",
      "done": false
    }
  ]
}

POSTCreate a field

POST /projects/{uuid}/fields

Adds a field to the project. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.

Request body

name string Required
Field name. Length 1–80.
type string Required
Field type (cannot be changed later).
textnumbermoneyselectmultiselectdatecheckboxuserurl
options array<object> | null
Options for select / multiselect (replaces the list). Maximum items 50.
id string
Existing option id (keep it to preserve values).
label string Required
Maximum length 60.
color string
Maximum length 9.
on_card boolean
Show on the board card.

Responses

StatusDescription
201Created
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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "type": "text",
    "options": [
        {
            "id": "string",
            "label": "string",
            "color": "string"
        }
    ],
    "on_card": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "type": "text",
      "options": [
          {
              "id": "string",
              "label": "string",
              "color": "string"
          }
      ],
      "on_card": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","type":"text","options":[{"id":"string","label":"string","color":"string"}],"on_card":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'type' => 'text',
        'options' => [
            [
                'id' => 'string',
                'label' => 'string',
                'color' => 'string',
            ],
        ],
        'on_card' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_fields_create",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "name": "Replace the broken fridge seal",
            "type": "text",
            "options": [
                {
                    "id": "string",
                    "label": "string",
                    "color": "string"
                }
            ],
            "on_card": true
        }
    }
}
Response 201
{
  "data": {
    "id": 501,
    "name": "Supplier",
    "type": "select",
    "options": [
      {
        "id": "o_k2m9qa",
        "label": "Metro",
        "color": "#22c55e"
      }
    ],
    "on_card": true
  }
}

PATCHUpdate a field

PATCH /projects/{uuid}/fields/{id}

Partial update. Requires the admin role in the project.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Custom field id.

Request body

name string
Field name. Length 1–80.
options array<object> | null
Options for select / multiselect (replaces the list). Maximum items 50.
id string
Existing option id (keep it to preserve values).
label string Required
Maximum length 60.
color string
Maximum length 9.
on_card boolean
Show on the board card.

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 PATCH 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "options": [
        {
            "id": "string",
            "label": "string",
            "color": "string"
        }
    ],
    "on_card": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "options": [
          {
              "id": "string",
              "label": "string",
              "color": "string"
          }
      ],
      "on_card": true
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","options":[{"id":"string","label":"string","color":"string"}],"on_card":True},
)
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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'options' => [
            [
                'id' => 'string',
                'label' => 'string',
                'color' => 'string',
            ],
        ],
        'on_card' => true,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_fields_update",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42,
            "name": "Replace the broken fridge seal",
            "options": [
                {
                    "id": "string",
                    "label": "string",
                    "color": "string"
                }
            ],
            "on_card": true
        }
    }
}
Response 200
{
  "data": {
    "id": 501,
    "name": "Supplier",
    "type": "select",
    "options": [
      {
        "id": "o_k2m9qa",
        "label": "Metro",
        "color": "#22c55e"
      }
    ],
    "on_card": true
  }
}

DELDelete a field

DELETE /projects/{uuid}/fields/{id}

Deletes the field and its values in all tasks.

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

Path parameters

uuid uuid Required
Project UUID.
id integer Required
Custom field id.

Query parameters

move_to_id integer
Where to move its tasks.

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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/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/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/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', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_fields_delete",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "deleted": true
  }
}

PUTReorder fields

PUT /projects/{uuid}/fields/order
Token scopewrite
Permission Any employee; results follow the token's visibility
MCP toolprojects_fields_reorder

Path parameters

uuid uuid Required
Project UUID.

Request body

ids array<integer> Required
All ids in the new order. Minimum items 1.

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 PUT 'https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/order' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "ids": [
        12,
        14
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/order', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "ids": [
          12,
          14
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/order",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"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('PUT', 'projects/3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b/fields/order', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'ids' => [
            12,
            14,
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "projects_fields_reorder",
        "arguments": {
            "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
            "ids": [
                12,
                14
            ]
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 501,
      "name": "Supplier",
      "type": "select",
      "options": [
        {
          "id": "o_k2m9qa",
          "label": "Metro",
          "color": "#22c55e"
        }
      ],
      "on_card": true
    }
  ]
}