jeCheckDevelopers
Get an API key

GETList POS connections

GET /pos/connections
Token scoperead
Permission pos.manage
Plan featurepos
MCP toolpos_connections_list · read-only

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, or the plan has no pos
429rate_limited — Too many requests — retry after Retry-After seconds
Request
curl 'https://app.jecheck.io/api/ext/v1/pos/connections' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections', {
  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/pos/connections",
    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', 'pos/connections', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_connections_list",
        "arguments": {}
    }
}
Response 200
{
  "data": [
    {
      "id": 3,
      "provider": "iiko",
      "name": "iiko",
      "status": "active",
      "last_sync_at": "2026-11-13T10:05:00+05:00"
    }
  ]
}

GETGet a POS connection

GET /pos/connections/{id}

Connection status, sync rules, iiko reference data (venues, terminal groups, positions, attendance and schedule types), linked locations and counters. The API key itself is never returned.

Token scoperead
Permission pos.manage
Plan featurepos
MCP toolpos_connections_get · read-only

Path parameters

id integer Required
Connection id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, or the plan has no pos
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/pos/connections/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
  },
});
const { data } = await res.json();
import os, requests

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

$res = $client->request('GET', 'pos/connections/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_connections_get",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "id": 3,
    "uuid": "7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "provider": "iiko",
    "name": "iiko",
    "status": "active",
    "base_url": null,
    "default_url": "https://api-ru.iiko.services",
    "key_kind": "login",
    "key_hint": "••••9f2a",
    "settings": {
      "attendance_out": "closed",
      "attendance_in": true,
      "webhook": true,
      "priority": "jecheck",
      "merge_minutes": 30,
      "delete_out": true,
      "attendance_type_id": null,
      "role_default": null,
      "role_map": [],
      "schedule_out": false,
      "schedule_type_id": null,
      "schedule_in": false,
      "auto_match": true,
      "since": null
    },
    "catalog": {
      "organizations": [
        {
          "id": "a3f1…",
          "name": "Abay Ave"
        }
      ],
      "terminal_groups": [
        {
          "id": "tg-1…",
          "org_id": "a3f1…",
          "name": "Main hall"
        }
      ],
      "roles": [
        {
          "id": "r-1…",
          "name": "Cook",
          "code": "CK"
        }
      ],
      "attendance_types": [],
      "schedule_types": [
        {
          "id": "s-1…",
          "name": "Day",
          "code": "D"
        }
      ]
    },
    "catalog_at": "2026-11-13T10:00:00+05:00",
    "last_sync_at": "2026-11-13T10:05:00+05:00",
    "last_webhook_at": null,
    "last_error": null,
    "last_error_at": null,
    "webhook_url": "https://app.jecheck.io/hooks/pos/iiko/7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "sites": [
      {
        "department_id": 4637,
        "external_id": "a3f1…",
        "external_name": "Abay Ave",
        "terminal_group_id": "tg-1…"
      }
    ],
    "stats": {
      "people": 42,
      "matched": 40,
      "unmatched": 2,
      "pending": 0,
      "errors": 0,
      "in_day": 18,
      "out_day": 21,
      "linked": 512
    },
    "created_at": "2026-11-01T09:00:00+05:00"
  }
}

POSTConnect iiko

POST /pos/connections

Checks the key, loads iiko reference data, links locations with identical names. Sync starts from today; use since in the settings to change it.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_connections_create

Request body

provider string
Default iiko.
iiko
name string
Maximum length 120.
api_login string
iikoWeb API key (apiLogin). Either this or app_id + client_secret + api_key.
app_id string
iiko developer portal application id.
client_secret string
iiko developer portal client secret.
api_key string
iikoWeb API key for the developer application.
base_url string | null
iikoCloud server, e.g. https://api-eu.syrve.live for Syrve. Default https://api-ru.iiko.services.

Responses

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

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/pos/connections",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"provider":"iiko","name":"Replace the broken fridge seal","api_login":"string","app_id":"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', 'pos/connections', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'provider' => 'iiko',
        'name' => 'Replace the broken fridge seal',
        'api_login' => 'string',
        'app_id' => 'string',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_connections_create",
        "arguments": {
            "provider": "iiko",
            "name": "Replace the broken fridge seal",
            "api_login": "string",
            "app_id": "string"
        }
    }
}
Response 201
{
  "data": {
    "id": 3,
    "uuid": "7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "provider": "iiko",
    "name": "iiko",
    "status": "active",
    "base_url": null,
    "default_url": "https://api-ru.iiko.services",
    "key_kind": "login",
    "key_hint": "••••9f2a",
    "settings": {
      "attendance_out": "closed",
      "attendance_in": true,
      "webhook": true,
      "priority": "jecheck",
      "merge_minutes": 30,
      "delete_out": true,
      "attendance_type_id": null,
      "role_default": null,
      "role_map": [],
      "schedule_out": false,
      "schedule_type_id": null,
      "schedule_in": false,
      "auto_match": true,
      "since": null
    },
    "catalog": {
      "organizations": [
        {
          "id": "a3f1…",
          "name": "Abay Ave"
        }
      ],
      "terminal_groups": [
        {
          "id": "tg-1…",
          "org_id": "a3f1…",
          "name": "Main hall"
        }
      ],
      "roles": [
        {
          "id": "r-1…",
          "name": "Cook",
          "code": "CK"
        }
      ],
      "attendance_types": [],
      "schedule_types": [
        {
          "id": "s-1…",
          "name": "Day",
          "code": "D"
        }
      ]
    },
    "catalog_at": "2026-11-13T10:00:00+05:00",
    "last_sync_at": "2026-11-13T10:05:00+05:00",
    "last_webhook_at": null,
    "last_error": null,
    "last_error_at": null,
    "webhook_url": "https://app.jecheck.io/hooks/pos/iiko/7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "sites": [
      {
        "department_id": 4637,
        "external_id": "a3f1…",
        "external_name": "Abay Ave",
        "terminal_group_id": "tg-1…"
      }
    ],
    "stats": {
      "people": 42,
      "matched": 40,
      "unmatched": 2,
      "pending": 0,
      "errors": 0,
      "in_day": 18,
      "out_day": 21,
      "linked": 512
    },
    "created_at": "2026-11-01T09:00:00+05:00"
  }
}

PATCHUpdate a POS connection

PATCH /pos/connections/{id}

Rename, pause (status: paused) or resume, or replace the API key (the new key is checked first).

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_connections_update

Path parameters

id integer Required
Connection id.

Request body

name string
Maximum length 120.
status string
activepaused
api_login string
iikoWeb API key (apiLogin). Either this or app_id + client_secret + api_key.
app_id string
iiko developer portal application id.
client_secret string
iiko developer portal client secret.
api_key string
iikoWeb API key for the developer application.
base_url string | null
iikoCloud server, e.g. https://api-eu.syrve.live for Syrve. Default https://api-ru.iiko.services.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Replace the broken fridge seal",
    "status": "active",
    "api_login": "string",
    "app_id": "string"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "name": "Replace the broken fridge seal",
      "status": "active",
      "api_login": "string",
      "app_id": "string"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"name":"Replace the broken fridge seal","status":"active","api_login":"string","app_id":"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', 'pos/connections/42', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'name' => 'Replace the broken fridge seal',
        'status' => 'active',
        'api_login' => 'string',
        'app_id' => 'string',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_connections_update",
        "arguments": {
            "id": 42,
            "name": "Replace the broken fridge seal",
            "status": "active",
            "api_login": "string",
            "app_id": "string"
        }
    }
}
Response 200
{
  "data": {
    "id": 3,
    "uuid": "7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "provider": "iiko",
    "name": "iiko",
    "status": "active",
    "base_url": null,
    "default_url": "https://api-ru.iiko.services",
    "key_kind": "login",
    "key_hint": "••••9f2a",
    "settings": {
      "attendance_out": "closed",
      "attendance_in": true,
      "webhook": true,
      "priority": "jecheck",
      "merge_minutes": 30,
      "delete_out": true,
      "attendance_type_id": null,
      "role_default": null,
      "role_map": [],
      "schedule_out": false,
      "schedule_type_id": null,
      "schedule_in": false,
      "auto_match": true,
      "since": null
    },
    "catalog": {
      "organizations": [
        {
          "id": "a3f1…",
          "name": "Abay Ave"
        }
      ],
      "terminal_groups": [
        {
          "id": "tg-1…",
          "org_id": "a3f1…",
          "name": "Main hall"
        }
      ],
      "roles": [
        {
          "id": "r-1…",
          "name": "Cook",
          "code": "CK"
        }
      ],
      "attendance_types": [],
      "schedule_types": [
        {
          "id": "s-1…",
          "name": "Day",
          "code": "D"
        }
      ]
    },
    "catalog_at": "2026-11-13T10:00:00+05:00",
    "last_sync_at": "2026-11-13T10:05:00+05:00",
    "last_webhook_at": null,
    "last_error": null,
    "last_error_at": null,
    "webhook_url": "https://app.jecheck.io/hooks/pos/iiko/7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "sites": [
      {
        "department_id": 4637,
        "external_id": "a3f1…",
        "external_name": "Abay Ave",
        "terminal_group_id": "tg-1…"
      }
    ],
    "stats": {
      "people": 42,
      "matched": 40,
      "unmatched": 2,
      "pending": 0,
      "errors": 0,
      "in_day": 18,
      "out_day": 21,
      "linked": 512
    },
    "created_at": "2026-11-01T09:00:00+05:00"
  }
}

DELDisconnect iiko

DELETE /pos/connections/{id}

Deletes the connection, its links, rules and log. Clock records and shifts stay in both systems.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_connections_delete · destructive

Path parameters

id integer Required
Connection id.

Responses

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

POSTTest the connection and refresh reference data

POST /pos/connections/{id}/test
Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_connections_test

Path parameters

id integer Required
Connection id.

Responses

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

PUTLink locations to iiko venues

PUT /pos/connections/{id}/sites

Pass rows for the locations to change. Empty external_id unlinks a location. terminal_group_id is needed for instant (live) clock-ins; with a single terminal group it is chosen automatically.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_sites_set

Path parameters

id integer Required
Connection id.

Request body

sites array<object> Required
Maximum items 2000.
department_id integer Required
jeCheck location id.
external_id string | null
iiko venue (organization) id.
terminal_group_id string | null
iiko terminal group id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/sites' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "sites": [
        {
            "department_id": 42,
            "external_id": "string",
            "terminal_group_id": "string"
        }
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/sites', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "sites": [
          {
              "department_id": 42,
              "external_id": "string",
              "terminal_group_id": "string"
          }
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.put(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42/sites",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"sites":[{"department_id":42,"external_id":"string","terminal_group_id":"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('PUT', 'pos/connections/42/sites', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'sites' => [
            [
                'department_id' => 42,
                'external_id' => 'string',
                'terminal_group_id' => 'string',
            ],
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_sites_set",
        "arguments": {
            "id": 42,
            "sites": [
                {
                    "department_id": 42,
                    "external_id": "string",
                    "terminal_group_id": "string"
                }
            ]
        }
    }
}
Response 200
{
  "data": {
    "id": 3,
    "uuid": "7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "provider": "iiko",
    "name": "iiko",
    "status": "active",
    "base_url": null,
    "default_url": "https://api-ru.iiko.services",
    "key_kind": "login",
    "key_hint": "••••9f2a",
    "settings": {
      "attendance_out": "closed",
      "attendance_in": true,
      "webhook": true,
      "priority": "jecheck",
      "merge_minutes": 30,
      "delete_out": true,
      "attendance_type_id": null,
      "role_default": null,
      "role_map": [],
      "schedule_out": false,
      "schedule_type_id": null,
      "schedule_in": false,
      "auto_match": true,
      "since": null
    },
    "catalog": {
      "organizations": [
        {
          "id": "a3f1…",
          "name": "Abay Ave"
        }
      ],
      "terminal_groups": [
        {
          "id": "tg-1…",
          "org_id": "a3f1…",
          "name": "Main hall"
        }
      ],
      "roles": [
        {
          "id": "r-1…",
          "name": "Cook",
          "code": "CK"
        }
      ],
      "attendance_types": [],
      "schedule_types": [
        {
          "id": "s-1…",
          "name": "Day",
          "code": "D"
        }
      ]
    },
    "catalog_at": "2026-11-13T10:00:00+05:00",
    "last_sync_at": "2026-11-13T10:05:00+05:00",
    "last_webhook_at": null,
    "last_error": null,
    "last_error_at": null,
    "webhook_url": "https://app.jecheck.io/hooks/pos/iiko/7d1c2f4e-6a8b-4c3d-9e1f-2a3b4c5d6e7f",
    "sites": [
      {
        "department_id": 4637,
        "external_id": "a3f1…",
        "external_name": "Abay Ave",
        "terminal_group_id": "tg-1…"
      }
    ],
    "stats": {
      "people": 42,
      "matched": 40,
      "unmatched": 2,
      "pending": 0,
      "errors": 0,
      "in_day": 18,
      "out_day": 21,
      "linked": 512
    },
    "created_at": "2026-11-01T09:00:00+05:00"
  }
}

PATCHUpdate sync rules

PATCH /pos/connections/{id}/settings

Partial update — pass only the rules to change.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_settings_update

Path parameters

id integer Required
Connection id.

Request body

attendance_out string
jeCheck clock records → iiko: closed — a closed attendance after clock-out; live — open/close the personal shift on the till instantly; off.
offclosedlive
attendance_in boolean
Receive iiko attendance (card at the terminal) as jeCheck clock records.
webhook boolean
Receive iiko personal-shift events instantly (otherwise polling every 5 minutes).
priority string
Whose times win when the same shift is recorded in both systems.
jecheckpos
merge_minutes integer
Records of one employee whose start differs by no more than this are the same shift. Value 5–240.
delete_out boolean
Deleting a clock record in jeCheck deletes the attendance jeCheck created in iiko.
attendance_type_id string | null
iiko attendance type for created attendance.
role_default string | null
Default iiko position (role) id.
role_map object
jeCheck position id → iiko role id.
schedule_out boolean
Send the published shift schedule to iiko.
schedule_type_id string | null
iiko schedule type for sent shifts (required with schedule_out).
schedule_in boolean
Allow importing the iiko schedule as draft shifts.
auto_match boolean
Match new iiko employees automatically by phone, email, employee number or name.
since date | null
Do not send or receive records before this date.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/settings' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "attendance_out": "off",
    "attendance_in": true,
    "webhook": true,
    "priority": "jecheck"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/settings', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "attendance_out": "off",
      "attendance_in": true,
      "webhook": true,
      "priority": "jecheck"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.patch(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42/settings",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"attendance_out":"off","attendance_in":True,"webhook":True,"priority":"jecheck"},
)
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', 'pos/connections/42/settings', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'attendance_out' => 'off',
        'attendance_in' => true,
        'webhook' => true,
        'priority' => 'jecheck',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_settings_update",
        "arguments": {
            "id": 42,
            "attendance_out": "off",
            "attendance_in": true,
            "webhook": true,
            "priority": "jecheck"
        }
    }
}
Response 200
{
  "data": {
    "attendance_out": "closed",
    "attendance_in": true,
    "webhook": true,
    "priority": "jecheck",
    "merge_minutes": 30,
    "delete_out": true,
    "attendance_type_id": null,
    "role_default": null,
    "role_map": [],
    "schedule_out": false,
    "schedule_type_id": null,
    "schedule_in": false,
    "auto_match": true,
    "since": null
  }
}

GETList iiko employees and their jeCheck matches

GET /pos/connections/{id}/people
Token scoperead
Permission pos.manage
Plan featurepos
MCP toolpos_people_list · read-only

Path parameters

id integer Required
Connection id.

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.
state string
Only matched or unmatched employees.
matchedunmatched
q string
Search by name, code or phone.

Responses

StatusDescription
200OK — a page of results with meta
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, or the plan has no pos
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/pos/connections/42/people?state=matched' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/people?state=matched', {
  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/pos/connections/42/people",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"state":"matched"},
)
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', 'pos/connections/42/people', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'state' => 'matched',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_people_list",
        "arguments": {
            "id": 42,
            "state": "matched"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 81,
      "external_id": "e1…",
      "name": "Aliya Sarsenova",
      "code": "101",
      "card_tail": "4321",
      "phone": "+77011112233",
      "email": null,
      "role": "Cook",
      "fired": false,
      "matched_by": "phone",
      "user": {
        "id": 2291,
        "uuid": "3f2b8c1e-7a4d-4e2f-9b1a-6c5d4e3f2a1b",
        "name": "Aliya Sarsenova"
      }
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "has_more": false
  }
}

POSTLoad employees from iiko

POST /pos/connections/{id}/people/refresh

Updates the iiko employee list and matches new employees automatically (if auto_match is on).

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_people_refresh

Path parameters

id integer Required
Connection id.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/people/refresh' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/people/refresh', {
  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/pos/connections/42/people/refresh",
    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', 'pos/connections/42/people/refresh', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_people_refresh",
        "arguments": {
            "id": 42
        }
    }
}
Response 200
{
  "data": {
    "total": 42,
    "matched": 3,
    "unmatched": 2
  }
}

POSTCreate jeCheck employees in iiko

POST /pos/connections/{id}/people/export

For users without an iiko match: the iiko code is the employee number (or JC + user id), the venue is the home location, the position is role_default.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_people_export

Path parameters

id integer Required
Connection id.

Request body

user_ids array<integer> Required
Items 1–100.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/people/export' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "user_ids": [
        12,
        14
    ]
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/people/export', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "user_ids": [
          12,
          14
      ]
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42/people/export",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"user_ids":[12,14]},
)
res.raise_for_status()
data = res.json()["data"]
$client = new GuzzleHttp\Client(['base_uri' => 'https://app.jecheck.io/api/ext/v1/']);

$res = $client->request('POST', 'pos/connections/42/people/export', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'user_ids' => [
            12,
            14,
        ],
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_people_export",
        "arguments": {
            "id": 42,
            "user_ids": [
                12,
                14
            ]
        }
    }
}
Response 200
{
  "data": {
    "created": 2,
    "errors": []
  }
}

POSTSync a period now

POST /pos/connections/{id}/sync

attendance — fetch iiko attendance (default: the last 2 days) and send what is queued; resend — queue and send closed clock records of the period; schedule_in — import the iiko schedule as draft shifts. Up to two months; no duplicates are created.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_sync

Path parameters

id integer Required
Connection id.

Request body

what string Required
attendanceresendschedule_in
from date
to date

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/sync' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "what": "attendance",
    "from": "2026-11-01",
    "to": "2026-11-30"
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/sync', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "what": "attendance",
      "from": "2026-11-01",
      "to": "2026-11-30"
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42/sync",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"what":"attendance","from":"2026-11-01","to":"2026-11-30"},
)
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', 'pos/connections/42/sync', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'what' => 'attendance',
        'from' => '2026-11-01',
        'to' => '2026-11-30',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_sync",
        "arguments": {
            "id": 42,
            "what": "attendance",
            "from": "2026-11-01",
            "to": "2026-11-30"
        }
    }
}
Response 200
{
  "data": {
    "created": 3,
    "updated": 1,
    "linked": 12,
    "closed": 0,
    "skipped": 0,
    "sent": 2
  }
}

POSTSubscribe to iiko personal-shift events

POST /pos/connections/{id}/webhook

Sets the jeCheck webhook for every linked venue. If the key already has another webhook address, the venue is reported as busy unless force is true (iiko keeps one address per key — prefer a separate key for jeCheck).

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_webhook_install

Path parameters

id integer Required
Connection id.

Request body

force boolean
Default false.

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/webhook' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "force": false
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/webhook', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "force": false
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://app.jecheck.io/api/ext/v1/pos/connections/42/webhook",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    json={"force":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', 'pos/connections/42/webhook', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'force' => false,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_webhook_install",
        "arguments": {
            "id": 42,
            "force": false
        }
    }
}
Response 200
{
  "data": [
    {
      "org_id": "a3f1…",
      "status": "ok"
    }
  ]
}

GETSync log

GET /pos/connections/{id}/events

Every record sent to or received from iiko, newest first. status: ok, error, pending (queued or waiting for a retry), skipped.

Token scoperead
Permission pos.manage
Plan featurepos
MCP toolpos_events_list · read-only

Path parameters

id integer Required
Connection id.

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 string
okerrorpendingskipped
direction string
inoutsys
entity string
attendanceshiftemployeecatalogwebhookconnection

Responses

StatusDescription
200OK — a page of results with meta
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, or the plan has no pos
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/pos/connections/42/events?status=ok' \
  -H 'Authorization: Bearer $JECHECK_TOKEN'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/events?status=ok', {
  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/pos/connections/42/events",
    headers={"Authorization": f"Bearer {os.environ['JECHECK_TOKEN']}"},
    params={"status":"ok"},
)
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', 'pos/connections/42/events', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'query' => [
        'status' => 'ok',
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_events_list",
        "arguments": {
            "id": 42,
            "status": "ok"
        }
    }
}
Response 200
{
  "data": [
    {
      "id": 9012,
      "direction": "out",
      "entity": "attendance",
      "action": "sync",
      "status": "ok",
      "message": "Attendance created",
      "local_id": 55123,
      "external_id": "b7e2…",
      "attempts": 1,
      "user": "Aliya Sarsenova",
      "department": "Abay Ave",
      "next_try_at": null,
      "created_at": "2026-11-13T18:02:11+05:00"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "has_more": false
  }
}

POSTRetry failed sends

POST /pos/connections/{id}/events/retry

Retries one event (event_id) or all failed and pending outgoing events.

Token scopewrite
Permission pos.manage
Plan featurepos
MCP toolpos_events_retry

Path parameters

id integer Required
Connection id.

Request body

event_id integer

Responses

StatusDescription
200OK
401unauthorized — Missing, invalid, revoked or expired token
403forbidden · insufficient_scope · plan_required — Token lacks pos.manage, is read-only, or the plan has no pos
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/pos/connections/42/events/retry' \
  -H 'Authorization: Bearer $JECHECK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "event_id": 42
}'
const res = await fetch('https://app.jecheck.io/api/ext/v1/pos/connections/42/events/retry', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.JECHECK_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "event_id": 42
  }),
});
const { data } = await res.json();
import os, requests

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

$res = $client->request('POST', 'pos/connections/42/events/retry', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('JECHECK_TOKEN')],
    'json' => [
        'event_id' => 42,
    ],
]);
$data = json_decode($res->getBody(), true)['data'];
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "pos_events_retry",
        "arguments": {
            "id": 42,
            "event_id": 42
        }
    }
}
Response 200
{
  "data": {
    "retried": 2
  }
}