Work Times - in Codenica API
Before sending the first request for Work Times, create an API key in your installation settings. If the key does not exist yet, open the page Codenica API - Introduction in a new tab. It explains the shared rules for key creation, authentication, API address selection and secret storage.
A Work Time records the time spent handling a particular ticket, change, problem or release. This is deliberately a narrow object: it has no own files, pin or unrestricted relationship catalogue. It can have exactly one primary parent, an optional Work Task and an optional Agent.
In the technical contract, the collection is named worktimes and a single record has itemType set to worktime.
Work Times - API address and installation choice
All Work Time routes start with:
{BASE_URL}/api/v1/worktimesBASE_URL contains the protocol and application host but not the final /api/v1.
Codenica Cloud: use the real domain or subdomain assigned to the company.
export BASE_URL="https://{company-domain}"Codenica On-Premise: Codenica Discovery registers the default local address http://codenica.local:5150.
If the administrator exposes the installation through a company domain, HTTPS, reverse proxy or another port, use the exact address supplied for that installation. Do not assume that an On-Premise user should use localhost. That name identifies the computer running the HTTP client, not necessarily the Codenica server.
export BASE_URL="http://codenica.local:5150"If a reverse proxy or administrator gives another address, use that exact address.
The address http://localhost:5050 is only for local development where the API runs on the same computer. It is not the standard Cloud address or the default On-Premise address.
Work Times - API key and licence limits
Create the key in Settings -> API -> API Keys. A separate key for each application and environment makes rotation, auditing and access removal easier.
StarterPlusEnterpriseThe secret is displayed only while the key is created or rotated. Store the Client ID and Client Secret in a secure secret store. Deleting the key removes its record and frees its place in the licence limit.
Work Times - request authentication
Authenticate every Codenica API request with two headers:
X-Codenica-Client-Id: {CLIENT_ID}
X-Codenica-Client-Secret: {CLIENT_SECRET}
Accept: application/jsonAn external integration does not need a panel session or the user's Bearer JWT. Keep the secret on the server side or in a secret manager.
export CLIENT_ID="cna_your_client_id"
export CLIENT_SECRET="cns_your_client_secret"
curl --fail-with-body --silent --show-error \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/context"The secret must not be placed in browser code, a repository, a URL, command history or logs.
Work Times - check the connection context
Read the context before downloading a list or recording time. This confirms that the address points to the intended database and that the key has the required scopes and limits.
curl --fail-with-body --silent --show-error \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/context" | jqCheck data.tenant.id, data.tenant.name, data.tenant.resolvedDomain, data.caller.clientId and data.caller.scopes. data.caller.authentication should be api_key. Also check data.capabilities.supportsETag, supportsIdempotency and supportsRelationships.
{
"data": {
"apiVersion": "v1",
"caller": {
"authentication": "api_key",
"clientId": "{CLIENT_ID}",
"scopes": [
"worktimes:read",
"worktimes:write"
]
},
"capabilities": {
"supportsETag": true,
"supportsIdempotency": true,
"supportsRelationships": true
}
},
"meta": {
"requestId": "{REQUEST_ID}"
}
}If the context identifies another company or lacks a required scope, correct the address or issue a key with the right permissions. Do not try to select a database by placing another identifier in the request body.
Work Times - schema and supported fields
The schema is the source of truth for the current Work Times contract. It returns field types, writability, restrictions, technical fields and permitted relationship targets.
curl --fail-with-body --silent --show-error \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes/schema" | jq{
"data": {
"itemType": "worktime",
"fields": [
{ "name": "date", "type": "dateTime", "writable": true },
{ "name": "time", "type": "integer", "writable": true },
{ "name": "isBillable", "type": "boolean", "writable": true },
{ "name": "dateCreated", "type": "dateTime", "writable": false, "system": true }
],
"relationshipTargets": [
{ "targetDataSet": "tickets", "targetItemType": "ticket" },
{ "targetDataSet": "changes", "targetItemType": "change" },
{ "targetDataSet": "problems", "targetItemType": "problem" },
{ "targetDataSet": "releases", "targetItemType": "release" },
{ "targetDataSet": "worktasks", "targetItemType": "worktask" }
],
"userRelationshipTypes": ["agent"]
}
}Before mapping fields, inspect readable, writable, required, technical and maxLength. Do not build an integration solely from an example response.
Work Times - primary parent and visibility
Every Work Time must have exactly one primary operational parent. The parent can be a ticket, change, problem or release.
ticketsticketparentchangeschangeparentproblemsproblemparentreleasesreleaseparentA record cannot be created without this relationship, and the last parent of an existing record cannot be removed. Visibility follows access to the primary parent. Access to a Work Task alone is not enough for the Work Time to appear in the list.
Send the parent relationship in the relationships array. Do not write ticketId, changeId, problemId or releaseId inside attributes.
Work Times - writable and system fields
The following fields carry business data in attributes. If the schema of the current database specifies different limits, the schema takes precedence.
customIddatelocationdepartmenttimetitlecategoryisBillable{
"date": "2026-09-06T09:00:00Z",
"time": 5400,
"title": "Service Desk ticket handling",
"category": "Service Desk",
"isBillable": true
}For a 90-minute entry:
isAuto, agentId, workTaskId, ticketId, changeId, problemId, releaseId, creator, updater, dateCreated, dateUpdated, importId, importSource and dateImported are technical or system fields. Do not write them in attributes; manage Agent and Work Task through their dedicated relationship endpoints.
Work Times - main endpoints
The Work Times collection provides the following routes:
GET /api/v1/worktimes
POST /api/v1/worktimes
POST /api/v1/worktimes:batch
GET /api/v1/worktimes/schema
GET /api/v1/worktimes/stats
GET /api/v1/worktimes/values
GET /api/v1/worktimes/{WORKTIME_ID}
PATCH /api/v1/worktimes/{WORKTIME_ID}
DELETE /api/v1/worktimes/{WORKTIME_ID}
GET /api/v1/worktimes/{WORKTIME_ID}/relationships
POST /api/v1/worktimes/{WORKTIME_ID}/relationships
POST /api/v1/worktimes/{WORKTIME_ID}/relationships:batch
DELETE /api/v1/worktimes/{WORKTIME_ID}/relationships/{DATASET}/{TARGET_ID}
GET /api/v1/worktimes/{WORKTIME_ID}/user-relationships
POST /api/v1/worktimes/{WORKTIME_ID}/user-relationships
POST /api/v1/worktimes/{WORKTIME_ID}/user-relationships:batch
DELETE /api/v1/worktimes/{WORKTIME_ID}/user-relationships/{TARGET_ID}Every read requires the relevant group's read scope. Every mutation also requires a unique Idempotency-Key. The current ETag is required for editing, relationship changes and deletion.
Work Times - listing and pagination
Read the list page by page. Set sorting explicitly so that subsequent reads use a predictable order:
curl --fail-with-body --silent --show-error -G \
--data-urlencode "itemType=worktime" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=25" \
--data-urlencode "sort=date" \
--data-urlencode "direction=desc" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes"The response contains data.items and page information.
{
"data": {
"items": [
{
"id": "{WORKTIME_ID}",
"itemType": "worktime",
"attributes": {
"customId": "ERP-WORKTIME-2026-0042",
"date": "2026-09-06T09:00:00Z",
"time": 5400,
"title": "Service Desk ticket handling",
"isBillable": true
},
"meta": { "etag": "\"{ETAG}\"" }
}
],
"page": 1,
"pageSize": 25,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false
},
"meta": { "requestId": "{REQUEST_ID}" }
}Read the next page only when hasNextPage is true. Read the maximum pageSize from the limits returned in context.
Work Times - search and filters
Use search for simple text search. For synchronization, a stable customId, UUID or primary-parent filter is more reliable:
curl --fail-with-body --silent --show-error -G \
--data-urlencode "search=Service Desk" \
--data-urlencode "category=Service Desk" \
--data-urlencode "isBillable=true" \
--data-urlencode "parentDataSet=tickets" \
--data-urlencode "parentId=$TICKET_ID" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=50" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes"Available parameters include customId, date, dateAfter, dateBefore, location, department, time, title, category, isBillable, agentId, createdAfter, createdBefore, updatedAfter, updatedBefore, sort and direction. A parentDataSet filter also requires parentId.
time:gte:3600
time:lt:28800
category:eq:Service Desk
title:contains:ticket
customId:startswith:ERP-WORKTIME-
location:notempty:Structural filters use the format field:operator:value:
Supported operators are eq, ne, gt, gte, lt, lte, contains, startswith, endswith and notempty. URL-encode values containing spaces, colons or special characters.
Work Times - field selection and included data
Use fields when the response should contain only data needed for synchronization. Include object and user relationships through include:
curl --fail-with-body --silent --show-error -G \
--data-urlencode "fields=id,itemType,customId,date,time,title,category,isBillable" \
--data-urlencode "include=relationships,users" \
--data-urlencode "ids=$WORKTIME_ID" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes"For Work Times, supported include values are relationships and users. Work Times does not support include=files. Technical fields require the relevant technical scope, and fields=* does not bypass permissions or expose system fields from the response envelope.
Work Times - statistics and field values
Statistics provide a quick view of the data distribution without downloading the whole collection. The following example groups entries by category:
curl --fail-with-body --silent --show-error -G \
--data-urlencode "field=category" \
--data-urlencode "limit=20" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes/stats"{
"data": {
"total": 11,
"field": "category",
"values": [
{ "value": "Service Desk", "count": 7 },
{ "value": "Public API", "count": 4 }
]
},
"meta": { "requestId": "{REQUEST_ID}" }
}To obtain values matching a search term, use values:
curl --fail-with-body --silent --show-error -G \
--data-urlencode "field=category" \
--data-urlencode "search=Public" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes/values"Statistics and values are read-only operations. They do not modify Work Time records.
Work Times - minimal creation
A minimal create request needs itemType, fields in attributes and exactly one parent relationship. Every POST request must have a new Idempotency-Key:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: erp-worktime-create-0001" \
--data '{
"itemType": "worktime",
"attributes": {
"customId": "ERP-WORKTIME-2026-0042",
"date": "2026-09-06T09:00:00Z",
"time": 5400,
"title": "Service Desk ticket handling",
"category": "Service Desk",
"isBillable": true
},
"relationships": [
{
"targetId": "{TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "parent"
}
]
}' \
"$BASE_URL/api/v1/worktimes"The expected response is normally HTTP 201 Created. Store data.id and the ETag from both the HTTP header and data.meta.etag.
Work Times - creation with location and Agent
Additional business fields such as location and department can be sent in the same request. An Agent is a user relationship and belongs in the separate userRelationships array:
{
"itemType": "worktime",
"attributes": {
"customId": "ERP-WORKTIME-2026-0043",
"date": "2026-09-06T10:30:00Z",
"location": "Krakow",
"department": "IT",
"time": 1800,
"title": "Problem analysis and user contact",
"category": "Operations",
"isBillable": false
},
"relationships": [
{
"targetId": "{PROBLEM_ID}",
"targetDataSet": "problems",
"targetItemType": "problem",
"relationshipType": "parent"
}
],
"userRelationships": [
{
"targetId": "{APP_USER_ID}",
"targetDataSet": "users",
"relationshipType": "agent"
}
]
}targetId for an Agent is the identifier of an active application user. Do not use a client identifier from the clients collection. One Work Time can have at most one Agent.
Work Times - optional Work Task
A Work Task may be added as an additional object relationship. It does not replace the primary parent:
"relationships": [
{
"targetId": "{TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "parent"
},
{
"targetId": "{WORKTASK_ID}",
"targetDataSet": "worktasks",
"targetItemType": "worktask",
"relationshipType": "worktask"
}
]One Work Task can be assigned to only one Work Time. If it is already occupied, the API returns HTTP 400 with validation_failed and the message The WorkTask is already assigned to another WorkTime.. Select a free Work Task or omit this relationship. Do not change the technical workTaskId field in attributes.
Work Times - Idempotency-Key and safe retries
Idempotency prevents a duplicate write when the client does not receive a response in time. When retrying, send the identical body with the same key:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: erp-worktime-create-0001" \
--data-binary @worktime-create.json \
"$BASE_URL/api/v1/worktimes"The same key and body should return the same resource instead of creating another record. Reusing the key with a different body produces 409 idempotency_conflict. Generate a new key for a new operation.
Work Times - read one record
After creation, read the record by UUID. The primary parent, Work Task and Agent can be requested with the include parameters:
curl --fail-with-body --silent --show-error \
--request GET \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID?itemType=worktime&include=relationships,users" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"The normal result is HTTP 200 OK. Check data.attributes.time, date, title, category and isBillable, together with data.relationships, data.userRelationships and data.meta.etag.
Work Times - update with ETag and If-Match
Read a fresh ETag before changing a record. Update only the fields that should change and send that ETag in If-Match:
curl --fail-with-body --silent --show-error \
--request PATCH \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-update-0001" \
--data '{
"attributes": {
"time": 7200,
"title": "Service Desk ticket handling - second session",
"isBillable": false
}
}'After HTTP 200 OK, store the new ETag. Do not reuse the previous value for the next change.
Work Times - stale or missing ETag
Version control prevents one integration from overwriting a change made earlier by another person or system. Omitting If-Match returns HTTP 428 Precondition Required with if_match_required. An old ETag returns HTTP 412 Precondition Failed with if_match_failed:
HTTP/1.1 412 Precondition Failed
code: if_match_failed
HTTP/1.1 428 Precondition Required
code: if_match_requiredAfter a 412, read the record again, compare the current data with the planned change and then decide whether to send another PATCH. Do not run a blind retry loop. A rejected change must not alter the time, parent or relationships.
Work Times - object relationships with Work Task
Use /relationships routes for object relationships. Work Times accept only tickets, changes, problems, releases and worktasks targets.
curl --fail-with-body --silent --show-error \
--request POST \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID/relationships" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-worktask-add-0001" \
--data '{
"targetId": "{WORKTASK_ID}",
"targetDataSet": "worktasks",
"targetItemType": "worktask",
"relationshipType": "worktask"
}'Read the collection through GET /api/v1/worktimes/{WORKTIME_ID}/relationships. Removing a relationship requires the current ETag:
curl --fail-with-body --silent --show-error \
--request DELETE \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID/relationships/worktasks/$WORKTASK_ID?relationshipType=worktask" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-worktask-remove-0001"Refresh the ETag after every relationship change. Removing a Work Task does not remove the Work Time.
Work Times - change the primary parent
To move time from a ticket to a change, use one PATCH that removes the old parent and adds the new one. Exactly one parent must remain after the operation:
{
"relationshipsToRemove": [
{
"targetId": "{OLD_TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "parent"
}
],
"relationshipsToAdd": [
{
"targetId": "{NEW_CHANGE_ID}",
"targetDataSet": "changes",
"targetItemType": "change",
"relationshipType": "parent"
}
]
}Send the operation to /api/v1/worktimes/{WORKTIME_ID} with the current If-Match and a new Idempotency-Key. Do not remove the old parent in a separate request, because the record would temporarily have no required parent.
Work Times - Agent relationship
An Agent is a user assigned to the Work Time. Use /user-relationships, not ordinary /relationships:
curl --fail-with-body --silent --show-error \
--request POST \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID/user-relationships" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-agent-add-0001" \
--data '{
"targetId": "{APP_USER_ID}",
"targetDataSet": "users",
"relationshipType": "agent"
}'Read the list with GET /api/v1/worktimes/{WORKTIME_ID}/user-relationships?relationshipType=agent. To replace an Agent, remove the current relationship and add the new one, using a fresh ETag each time. One Work Time can have at most one Agent.
targetId must identify an active and visible application user. It is not Clients.Id and it is not a company identifier.
Work Times - relationship batch
Use relationships:batch when one operation should add or remove several relationships. Agent relationships have the corresponding user-relationships:batch route:
curl --fail-with-body --silent --show-error \
--request POST \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID/relationships:batch" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-relationships-batch-0001" \
--data '{
"add": [
{
"targetId": "{WORKTASK_ID}",
"targetDataSet": "worktasks",
"targetItemType": "worktask",
"relationshipType": "worktask"
}
],
"remove": []
}'The response contains added, removed and skipped counters. Keep exactly one parent relationship; never send a batch that removes the only parent.
{
"data": {
"added": 1,
"removed": 0,
"skipped": 0
},
"meta": { "requestId": "{REQUEST_ID}" }
}Check the response counters before treating the operation as complete.
Work Times - batch operations for records
For several Work Times, use POST /api/v1/worktimes:batch. Each item specifies create, update or delete:
{
"items": [
{
"operation": "create",
"create": {
"itemType": "worktime",
"attributes": {
"customId": "ERP-WORKTIME-BATCH-0001",
"date": "2026-09-06T10:00:00Z",
"time": 1800,
"title": "Time imported from ERP",
"category": "Public API",
"isBillable": true
},
"relationships": [
{
"targetId": "{TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "parent"
}
]
}
}
]
}An update or delete item needs its own id and ifMatch. Send ifMatch as a string containing the current ETag:
{
"items": [
{
"operation": "update",
"id": "{WORKTIME_ID}",
"ifMatch": "\"{CURRENT_ETAG}\"",
"update": {
"attributes": {
"time": 2700
}
}
},
{
"operation": "delete",
"id": "{OTHER_WORKTIME_ID}",
"ifMatch": "\"{OTHER_CURRENT_ETAG}\""
}
]
}Inspect every item by index, operation and status. A partial result may use HTTP 207 Multi-Status; one failed item does not confirm that the remaining items succeeded.
Work Times - delete a record
Deletion is irreversible from the point of view of Public API. Before deleting, read a fresh ETag and confirm that the UUID and customId identify the intended record:
curl --fail-with-body --silent --show-error \
--request DELETE \
--url "$BASE_URL/api/v1/worktimes/$WORKTIME_ID" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $WORKTIME_ETAG" \
--header "Idempotency-Key: erp-worktime-delete-0001"A successful result is HTTP 200 OK with data=true. Then read the UUID again:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/worktimes/$WORKTIME_ID"The follow-up read should return HTTP 404 Not Found with workTime_not_found. Also check a list filtered by customId so the record is not returned again.
Work Times - no files and no pin
Work Times do not have their own file module or pin action. Do not use these routes:
/api/v1/worktimes/{WORKTIME_ID}/files
/api/v1/worktimes/{WORKTIME_ID}/pinTreating a Work Time as an object with files or a pin is outside the supported contract. If a time entry needs a document or attachment, store the file on an object that supports files, such as a ticket or document, and keep the connection in the integrating system.
Work Times - errors and limits
validation_failedauthentication_requiredpublic_api_scope_deniedworkTime_parent_access_deniedworkTime_not_foundidempotency_conflictif_match_failedif_match_requiredidempotency_key_requiredrate_limit_exceededtenant_context_unavailableFor an error, record the HTTP status, code and meta.requestId, but never the key secret. For HTTP 400, also inspect errors because it identifies the exact field or array item.
Read request and batch limits from data.capabilities.limits. The X-RateLimit-Limit and X-RateLimit-Remaining headers help adjust synchronization speed.
Work Times - synchronization and n8n
For synchronization with an ERP, helpdesk or n8n, use a customId assigned by the external system, such as ERP-WORKTIME-{external-id}. Do not use the title as the deduplication key because two sessions may have the same description.
In n8n, an HTTP Request node is sufficient. Store X-Codenica-Client-Id, X-Codenica-Client-Secret and Accept: application/json in the header credential. Add a unique Idempotency-Key to POST requests.
{
"itemType": "worktime",
"attributes": {
"customId": "N8N-WORKTIME-{{$execution.id}}",
"date": "2026-09-06T09:00:00Z",
"time": 1800,
"title": "Time synchronized by n8n",
"category": "Public API",
"isBillable": true
},
"relationships": [
{
"targetId": "{{$json.ticketId}}",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "parent"
}
]
}For an update, the workflow should read the record first, keep data.meta.etag and then send PATCH with that ETag. On HTTP 412, read again and resolve the conflict. On HTTP 429, use a bounded backoff. Never put the secret in a Code node, workflow input or execution history.
Work Times - recommended operation order
A safe integration sequence looks like this:
1. Set BASE_URL for Cloud or On-Premise.
2. Create a key in Settings -> API and save the secret.
3. Read GET /api/v1/context and check the database, scopes and limits.
4. Read GET /api/v1/worktimes/schema.
5. Select one available Ticket, Change, Problem or Release.
6. Optionally select a free Work Task and active Agent.
7. Create the record with one parent and a new Idempotency-Key.
8. Keep the UUID and ETag from the response.
9. Read the record with include=relationships,users.
10. Use a fresh If-Match and new Idempotency-Key for changes.
11. Change relationships through the correct endpoint, not technical fields.
12. For bulk imports, inspect every batch item.
13. Read a fresh ETag before DELETE.
14. Confirm HTTP 404 and absence of the customId after DELETE.The essential rules are simple: one Work Time has one primary parent, time is stored in seconds, Work Task is optional and occupies one place, Agent is a user relationship, and files and pin are not supported. Idempotency protects the write and ETag protects the specific record version.
