Overview

API v01

Public API. Version v01. All requests over HTTPS.


https://<host>/api/v01/<Service>/...


This section covers the general API rules: transport, request and response formats, OData query parameters, data types. Per-service details live in their own sections.

Services and operations

ServiceRead (OData)Write (REST)
Task / Tasksone task · task list · reference objectsCreate, Update, Delete
Project / Projectsproject list · reference objectsCreate, Update, Deactivate, Restore
User / Usersuser list · profiles · settings · reference objectsCreate, UpdateProfile, UpdateSettings, Activate, Deactivate
WorkLog / WorkLogstime log list · reference objectsCreate, Update, Delete

Service naming convention

Each entity is represented by a pair of endpoints:

  • Singular service (/api/v01/Task, /api/v01/Project, /api/v01/User, /api/v01/WorkLog) — operations on a single record: REST write operations (Create, Update, Delete, etc.) and, where applicable, OData read of a single record by key.
  • Plural service (/api/v01/Tasks, /api/v01/Projects, /api/v01/Users, /api/v01/WorkLogs) — collection queries and related reference objects (Statuses, Types, Priorities, etc.).

Transport

Two transports are used:

  • OData v2 — for reading data. Standard operators $select, $filter, $orderby, $skip, $top are supported, along with the response format $format=json. By default OData returns XML — in practice you almost always need to request JSON explicitly.
  • REST — for write operations. Method POST, body — JSON, response — JSON.

REST response envelope

All REST operations respond with a unified JSON document.

Success:

{
  "status": "Success",
  "statusCode": 200,
  "details": { /* keys of the created/updated entity */ }
}


Error:

{
  "status": "Error",
  "statusCode": 500,
  "statusText": "Wrong parameters"
}


A special case is a business error from database logic: statusCode = 399, with MessageCode in statusText (a string code that the client must localize on its own). In all other cases statusText contains a ready-to-display localized text.


HTTP / statusCodestatusTextWhen it occurs
200—Success
399MessageCode (e.g., JBTASKS.TASK_PROJECT_NOT_FOUND)Business error; the client must localize the code
500"Wrong parameters"Required XxxData envelope or keys are missing
other 4xx/5xxready-to-display text (MessageText)Other database-layer errors

REST request envelope

All REST operations accept a JSON body in the following general form:

{
  "<Entity>Data": { /* entity fields */ },
  "<Entity>KeyField": "TaskID",
  "Parent<Entity>KeyField": "TaskKey"
}


The <Entity>Data field is the main container. The <Entity>KeyField and Parent<Entity>KeyField fields (where applicable) specify which of the provided keys is the leading one: TaskID, TaskKey, IntegrationID, Email, EmployeeID, etc. If <Entity>KeyField is omitted, the service determines the leading key based on which fields are populated — the priority is <Entity>ID → business code → IntegrationID.

OData: reading data

Reads are always performed via the plural services or via a singular service with parameters.

Basic collection query

GET /api/v01/Tasks/odata/Tasks?$format=json
GET /api/v01/Projects/odata/Projects?$format=json
GET /api/v01/Users/odata/Users?$format=json
GET /api/v01/WorkLogs/odata/WorkLogs?$format=json


Supported query parameters

ParameterPurposeExample
$selectComma-separated list of returned fields. Significantly reduces payload and speeds up the response.$select=TaskID,TaskKey,TaskText,StatusID
$filterFilter condition. Operators: eq, ne, gt, ge, lt, le, logical and, or, not. Strings are enclosed in single quotes.$filter=ProjectCode eq 'PROJ' and StatusCategoryID ne '3'
$orderbySorting. Directions asc / desc. Sorting by multiple fields, comma-separated, is supported.$orderby=PriorityID asc, DueDateTime desc
$topHow many records to return (page size).$top=50
$skipHow many records to skip (offset). Used together with $top for pagination.$skip=100&$top=50
$formatResponse format. For JSON, specify json.$format=json
$inlinecountRequest the total number of records in the collection (regardless of $top / $skip).$inlinecount=allpages

Combined example

Get the second page of 50 open tasks for project PROJ, sorted by priority, with only the needed fields and a total count:

GET /api/v01/Tasks/odata/Tasks
  ?$select=TaskID,TaskKey,TaskText,StatusID,PriorityID,AssigneeFullName,DueDateTime
  &$filter=ProjectCode eq 'PROJ' and StatusCategoryID ne '3'
  &$orderby=PriorityID asc, DueDateTime asc
  &$skip=50&$top=50
  &$inlinecount=allpages
  &$format=json


Response (abridged):

{
  "d": {
    "__count": "327",
    "results": [
      {
        "TaskID": "0000004242",
        "TaskKey": "PROJ-42",
        "TaskText": "Fix login",
        "StatusID": "10",
        "PriorityID": "HIGH",
        "AssigneeFullName": "John Smith",
        "DueDateTime": "/Date(1735603200000)/"
      }
    ]
  }
}


Reading a single record

If a service exposes an OData single-record endpoint, it accepts key values through path parameters:

GET /api/v01/Task/odata/Task(ID='PROJ-42',TaskKeyField='TaskKey')/Results?$format=json


Allowed values for …KeyField:

EntityField nameAllowed values
TaskTaskKeyFieldTaskID, TaskKey, IntegrationID
ProjectProjectKeyFieldProjectID, ProjectCode, IntegrationID
UserUserKeyFieldUserID, EmployeeID, Email, IntegrationID
WorkLogWorkLogKeyFieldWorkLogID, IntegrationID

Encodings and data types

Data typeJSON representationComment
string (NVARCHAR(n))stringUTF-8
integer (INTEGER, INT, SMALLINT)numberwhole number
long integer (BIGINT)number / stringlarge values may be returned as a string
decimal (DECIMAL(p,s))stringOData serializes decimal values as strings
date/time (SECONDDATE, TIMESTAMP)stringOData format: "/Date(epochMs)/"; REST input accepts ISO YYYY-MM-DDTHH:MM:SS

In REST operations, date-time values in YYYY-MM-DDTHH:MM:SS format are normalized by the server to YYYYMMDDHHMMSS (14 characters).

Client tips

  • Always specify $format=json — otherwise OData returns XML.
  • Don't request "all fields" — use $select, the payload is large.
  • For pagination use $top + $skip + $inlinecount=allpages.
  • In $filter, strings are enclosed in single quotes.
  • When writing, pass only the fields you are changing — missing/empty fields are interpreted as null and may overwrite existing values. The behavior depends on the specific operation — see the description of the relevant operation.