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
| Service | Read (OData) | Write (REST) |
|---|---|---|
Task / Tasks | one task · task list · reference objects | Create, Update, Delete |
Project / Projects | project list · reference objects | Create, Update, Deactivate, Restore |
User / Users | user list · profiles · settings · reference objects | Create, UpdateProfile, UpdateSettings, Activate, Deactivate |
WorkLog / WorkLogs | time log list · reference objects | Create, 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,$topare 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 / statusCode | statusText | When it occurs |
|---|---|---|
200 | — | Success |
399 | MessageCode (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/5xx | ready-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
| Parameter | Purpose | Example |
|---|---|---|
$select | Comma-separated list of returned fields. Significantly reduces payload and speeds up the response. | $select=TaskID,TaskKey,TaskText,StatusID |
$filter | Filter 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' |
$orderby | Sorting. Directions asc / desc. Sorting by multiple fields, comma-separated, is supported. | $orderby=PriorityID asc, DueDateTime desc |
$top | How many records to return (page size). | $top=50 |
$skip | How many records to skip (offset). Used together with $top for pagination. | $skip=100&$top=50 |
$format | Response format. For JSON, specify json. | $format=json |
$inlinecount | Request 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:
| Entity | Field name | Allowed values |
|---|---|---|
| Task | TaskKeyField | TaskID, TaskKey, IntegrationID |
| Project | ProjectKeyField | ProjectID, ProjectCode, IntegrationID |
| User | UserKeyField | UserID, EmployeeID, Email, IntegrationID |
| WorkLog | WorkLogKeyField | WorkLogID, IntegrationID |
Encodings and data types
| Data type | JSON representation | Comment |
|---|---|---|
string (NVARCHAR(n)) | string | UTF-8 |
integer (INTEGER, INT, SMALLINT) | number | whole number |
long integer (BIGINT) | number / string | large values may be returned as a string |
decimal (DECIMAL(p,s)) | string | OData serializes decimal values as strings |
date/time (SECONDDATE, TIMESTAMP) | string | OData 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
nulland may overwrite existing values. The behavior depends on the specific operation — see the description of the relevant operation.