Skip to main content

API and integrations: reference

The reference is intended for an integration developer. A step-by-step instruction for a user is in the process “Integrations”.

Access methods​

MethodWhat it is forAuthentication
REST APIReading and changing data from scripts and servicesAn API key in the header Authorization: Bearer thor_sk_…
MCPReading data by AI assistants (read-only)An API key
WebhookReceiving events in your systemThe signature X-Assist-Signature

Addresses​

  • REST API: https://<cabinet address>/api.
  • MCP: https://<cabinet address>/api/mcp (Streamable HTTP, stateless).
  • Health check: GET /health and GET /ready without authentication.

Authentication​

  1. Create an API key on the “API keys” page. Choose a role: the key gets the permissions of exactly this role.
  2. Save the token of the form thor_sk_<identifier>.<secret>: it is shown once.
  3. Pass the token in every request: Authorization: Bearer thor_sk_….

For requests with a key, the X-Requested-With header is not needed. Managing the keys themselves with a key is impossible: the response is 403.

Common headers​

HeaderWhenValue
AuthorizationAlwaysBearer thor_sk_<id>.<secret>
Content-TypeFor POST and PATCH with a bodyapplication/json
Accept-LanguageOptionalru or en: the message language
Idempotency-KeyRecommended for POST, PUT, PATCH, DELETEA unique string up to 255 characters

Idempotency. Repeating a request with the same key and body returns the stored response. The same key with a different body: error 409 IDEMPOTENCY_MISMATCH. It does not work for file uploads (multipart/form-data).

Data format​

  • Identifiers: UUIDs in lowercase.
  • Date and time: ISO 8601 with a time zone, for example 2026-10-28T12:00:00.000Z.
  • Calendar days (start and end of tasks and releases): YYYY-MM-DD.
  • Description: a BlockNote document (JSON) or null.
  • Estimates and durations: minutes (an integer).

Pagination. Lists respond with an object { items, pagination: { limit, offset, total, hasMore } }. Parameters limit and offset. Task trees use a cursor: nextCursor.

Permissions​

Each method checks the key role's permissions and the record scope. The current key's permissions are returned by GET /api/me in the permissions field. A 403 error means insufficient permissions, not an authentication problem. A 404 error may mean the record is outside the role's scope.

Limits​

ZoneLimit
/api/auth/*40 requests per minute per address
Other /api/*180 requests per minute per address

On exceeding, the response is 429 RATE_LIMITED with the headers x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, retry-after.

Error format​

{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": {} } }
HTTPCodeWhen
400VALIDATION_ERRORAn invalid body or request parameters
401UNAUTHORIZEDNo or invalid key or session
403FORBIDDENNo permission
404NOT_FOUNDThe record is not found or outside the scope
409CONFLICT, IDEMPOTENCY_MISMATCHA data conflict, a repeat with a different body
429RATE_LIMITEDThe limit is exceeded
500INTERNALAn unhandled error

A stage transition that did not pass a gate returns an error with details.failures and the hint hint.

Main methods​

The needed permission is stated for the key's role.

Profile​

MethodPathDescription
GET/api/meThe profile, role, and permissions of the key
GET/api/me/my-workThe “My work” tasks

Projects, releases, tasks​

MethodPathDescriptionPermission
GET/api/projectsThe project list. Parameters q, kind, stageKey, limit, offsetProjects: view
POST/api/projectsCreate a projectProjects: create
GET/api/projects/:id/releasesA project's releasesReleases: view
POST/api/projects/:id/releasesCreate a releaseReleases: create
PATCH/api/releases/:idChange a releaseReleases: update
POST/api/releases/:id/move-stageMove a releaseReleases: update
GET/api/projects/:id/tasksA project's task treeTasks: view
POST/api/projects/:id/tasksCreate a taskTasks: create
POST/api/releases/:id/tasksCreate a task in a releaseTasks: create
GET/api/tasks/:idGet a taskTasks: view
PATCH/api/tasks/:idChange a taskTasks: update
POST/api/tasks/:id/move-stageMove a task: body {"stageKey":"in_progress","confirmed":true}Tasks: update
GET/api/tasks/:id/allowed-transitionsAllowed transitionsTasks: view
DELETE/api/tasks/:idDelete a taskTasks: delete
GET/api/search?q=…Global searchView permissions

Hours and comments​

MethodPathDescription
GET/api/tracksThe track list
POST/api/tracksCreate a track: taskId, workTypeId, description, durationMinutes, startedAt, endedAt, with the permission also userId
GET/api/work-typesWork types
POST/api/entity-commentsA comment: entityType (task, release, project), entityId, body

Notifications and reports​

MethodPathDescription
GET/api/notificationsThe notification feed
POST/api/notifications/:id/readMark as read
GET/api/reports/tracks/duration-matrixThe “Track hours” report (.csv and .xlsx are available)
GET/api/reports/tracks/time-allocationThe “Time allocation” report
GET/api/resources/plan-fact?yearMonth=YYYY-MMPlan–fact

Examples​

Create a task:

curl -X POST "https://<address>/api/projects/<PROJECT_ID>/tasks" \
-H "Authorization: Bearer thor_sk_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm-import-001" \
-d '{"title": "Task from CRM", "estimateMinutes": 120}'

Log time:

curl -X POST "https://<address>/api/tracks" \
-H "Authorization: Bearer thor_sk_..." \
-H "Content-Type: application/json" \
-d '{"taskId": "<TASK_ID>", "workTypeId": "<WORK_TYPE_ID>", "description": "Integration work", "durationMinutes": 60, "startedAt": "2026-10-28T09:00:00.000Z", "endedAt": "2026-10-28T10:00:00.000Z"}'

Move a task to a stage:

curl -X POST "https://<address>/api/tasks/<TASK_ID>/move-stage" \
-H "Authorization: Bearer thor_sk_..." \
-H "Content-Type: application/json" \
-d '{"stageKey": "in_progress", "confirmed": true}'

The time logging rules are the same as in the interface: “Rules and limits”.

MCP for AI assistants​

The MCP server works read-only. Authorization is by an API key only. GET and DELETE requests return 405.

ToolWhat it returns
whoamiThe key's user, role, collections with scope
list_fieldsTask and project fields
list_projects, get_projectProjects; a project card with the team and areas of responsibility (by projectId or prefix)
list_tasks, get_taskTasks across all projects with filters; a task card (by taskId or a key like RGM-30)
list_usersUsers; with projectId — the project team
list_time_tracksTime tracks and the total in minutes
list_field_tracksThe history of field values

Lists accept limit (1–100, 50 by default) and offset. Dates in responses: ISO 8601.

Webhook​

A webhook is configured by a user on the profile's “Notification channels” tab: “Your notification settings”.

  • Assist sends one HTTPS POST per event.
  • The address must be publicly available. Private and local addresses are rejected.
  • The secret is shown once on creation.
  • Signature: the X-Assist-Signature header contains sha256= and the hexadecimal HMAC-SHA256 of the exact request body, computed with the webhook secret.

An example of signature verification (Python):

import hmac, hashlib

def is_valid(body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)

Limitations​

  1. Keys are created and revoked only in the interface.
  2. Deletion of tasks, projects, releases, and tracks is soft: records are marked as deleted.
  3. Stage transitions may be blocked by a gate. Pass confirmed: true after the conditions are met.
  4. Additional fields from the constructor are passed as top-level fields of the request body and are checked against the catalog and field permissions.
  5. The full list of methods and request body schemas is maintained by the Assist development team. Ask the administrator for the “REST API (integration)” document.