Notifications
In-app notifications of the acting user (the bell in the web app and the Notifications screen in the mobile app): list, unread count, mark as read, and personal notification settings. A company key sees the notifications of its service user.
GET List notifications
GET /notifications
Notifications of the acting user, newest first. meta.unread — the number of unread notifications.
Token scope read
Permission
Any employee; results follow the token's visibility
MCP tool notifications_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.
unread
boolean
Only unread notifications.
since
date-time
Only notifications created after this moment.
Responses
Status Description
200 OK — a page of results with meta
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Plan without API access
422 validation_failed — Invalid parameters — see error.fields
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/notifications?unread=true' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/notifications?unread=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/notifications",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
params={"unread":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', 'notifications', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'query' => [
'unread' => true,
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "notifications_list",
"arguments": {
"unread": true
}
}
}
{
"data": [
{
"id": 88123,
"title": "New task: Replace the broken fridge seal",
"body": "Abay Ave · due Nov 10",
"url": "https://app.jecheck.io/ui/tasks?task=3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
"data": {
"type": "task",
"task_id": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b"
},
"is_read": false,
"read_at": null,
"created_at": "2026-11-03T10:24:00+05:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"has_more": false
}
}
GET Count unread notifications
GET /notifications/unread-count
Token scope read
Permission
Any employee; results follow the token's visibility
MCP tool notifications_unread_count · read-only
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Plan without API access
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/notifications/unread-count' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/notifications/unread-count', {
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/notifications/unread-count",
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', 'notifications/unread-count', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "notifications_unread_count",
"arguments": {}
}
}
{
"data": {
"unread": 3
}
}
POST Mark notifications as read
POST /notifications/read
Pass ids to mark specific notifications, or all: true to mark everything as read. Returns the remaining unread count.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool notifications_read
Request body
ids
array<integer>
Notification ids.
Maximum items 200.
all
boolean
Mark all notifications as read.
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Read-only token
422 validation_failed — Invalid parameters — see error.fields
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X POST 'https://app.jecheck.io/api/ext/v1/notifications/read' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ids": [
12,
14
],
"all": true
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/notifications/read', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ids": [
12,
14
],
"all": true
}),
});
const { data } = await res.json();
import os, requests
res = requests.post(
"https://app.jecheck.io/api/ext/v1/notifications/read",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"ids":[12,14],"all":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', 'notifications/read', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'ids' => [
12,
14,
],
'all' => true,
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "notifications_read",
"arguments": {
"ids": [
12,
14
],
"all": true
}
}
}
{
"data": {
"marked": 2,
"unread": 1
}
}
GET Get notification settings
GET /notifications/preferences
Personal settings by channel (push, email) and event group: assigned — a task is assigned, comments, updates — status and due-date changes, reminders — due and overdue reminders, digest — daily email digest, brief — morning AI-control brief, urgent — urgent signals during the day. The in-app history is always kept.
Token scope read
Permission
Any employee; results follow the token's visibility
MCP tool notifications_preferences_get · read-only
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Plan without API access
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl 'https://app.jecheck.io/api/ext/v1/notifications/preferences' \
-H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/notifications/preferences', {
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/notifications/preferences",
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', 'notifications/preferences', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "notifications_preferences_get",
"arguments": {}
}
}
{
"data": {
"push": {
"assigned": true,
"comments": true,
"updates": true,
"reminders": true,
"brief": true,
"urgent": true
},
"email": {
"assigned": true,
"digest": false,
"brief": true
}
}
}
PATCH Update notification settings
PATCH /notifications/preferences
Partial update: pass only the switches to change, e.g. {"email": {"digest": false}}. Unknown keys are ignored.
Token scope write
Permission
Any employee; results follow the token's visibility
MCP tool notifications_preferences_update
Request body
push
object
Push notifications to the mobile app.
email
object
Emails (only for users with web-cabinet access).
Responses
Status Description
200 OK
401 unauthorized — Missing, invalid, revoked or expired token
403 forbidden · insufficient_scope · plan_required — Read-only token
422 validation_failed — Invalid parameters — see error.fields
429 rate_limited — Too many requests — retry after Retry-After seconds
Request
cURL
Node.js
Python
PHP
MCP
Copy
curl -X PATCH 'https://app.jecheck.io/api/ext/v1/notifications/preferences' \
-H 'Authorization: Bearer $JECHECK_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"push": {
"assigned": true,
"comments": true,
"updates": true
},
"email": {
"assigned": true,
"digest": true,
"brief": true
}
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/notifications/preferences', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"push": {
"assigned": true,
"comments": true,
"updates": true
},
"email": {
"assigned": true,
"digest": true,
"brief": true
}
}),
});
const { data } = await res.json();
import os, requests
res = requests.patch(
"https://app.jecheck.io/api/ext/v1/notifications/preferences",
headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
json={"push":{"assigned":True,"comments":True,"updates":True},"email":{"assigned":True,"digest":True,"brief":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', 'notifications/preferences', [
'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
'json' => [
'push' => [
'assigned' => true,
'comments' => true,
'updates' => true,
],
'email' => [
'assigned' => true,
'digest' => true,
'brief' => true,
],
],
]);
$data = json_decode($res->getBody(), true)['data'];
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "notifications_preferences_update",
"arguments": {
"push": {
"assigned": true,
"comments": true,
"updates": true
},
"email": {
"assigned": true,
"digest": true,
"brief": true
}
}
}
}
{
"data": {
"push": {
"assigned": true,
"comments": true,
"updates": true,
"reminders": true,
"brief": true,
"urgent": true
},
"email": {
"assigned": true,
"digest": false,
"brief": true
}
}
}