Correct a worklog
PATCHhttps://
Partially updates a worklog: absent keys are untouched, an empty body is rejected.
Access
- Token scope
- api:
write: times Without it:
403 insufficient-token-scope. - Permission
- None. The record's own rules still apply.
- Rate cost
- 1 unit, write bucket. A write costs the same whatever
viewyou ask for. - Also
- Accepts
If-Match. Never cached:private, no-store. Unknown body keys are refused, never dropped.
Both are checked, scope first. A token never does more than its user. How access is checked
Changing another user's entry additionally requires times::update_others; without it, other people's entries are invisible to you. An entry awaiting review answers 409 with conflict.reason locked_by_review to anyone but its author or a reviewer, and an invoiced entry answers 409 locked_by_invoice: an invoiced entry can never be changed again. exceeded_budget is read-only here: it is what puts an entry in the reviewer's queue, and clearing it would withdraw the entry from that queue silently. reason stays writable until a reviewer has settled the entry; rewriting it afterwards answers 409 reason_reviewed. Sending task_id re-infers is_not_billable from the task, and sending is_not_billable with a value that differs from the inferred or current one requires billable_change_reason (422 on /billable_change_reason without it) and puts the entry back in the reviewer's queue, reopening one that was already settled. A new project_id must be one the entry's owner holds a task on, and a new task_id must be the owner's own task in the entry's project, so a manager holding times::update_others may move a colleague's hours onto that colleague's deadline in another project. Only the caller's times::write_on_others_tasks widens either rule, never the owner's; a refusal answers 403 forbidden-by-policy, and a task outside the project a 422 on /task_id. Moving the entry with project_id detaches a task or work item that cannot follow it and nulls budget_id with the task. Reassigning a worklog to another employee is not possible: that is a DELETE plus a POST. work_item_id is checked for existence, visibility and the same project, and moving the entry onto a different work item additionally requires that the entry's owner may log time on it, the same rule plnnrly and the create operation apply; otherwise it answers 403 forbidden-by-policy. Send If-Match with the ETag from your last read to detect a concurrent edit, which answers 412. Treat it as best-effort only: this resource carries no concurrency token, and updated_at is second-precision.
Path parameters
Query parameters
Unknown parameters are refused with 400, naming the parameter.
Request headers
A correlation id of your own. It is recorded in our logs next to the server's request id but never returned: the response header always carries the server's id. A value that does not match the pattern is discarded silently, never rejected.
Request body
Unknown keys are refused with 422, naming the key.
Project the hours are booked against; null once that project is deleted.
Task the hours are booked on; null when the entry is not attached to one, or once that task is deleted.
Work item the hours are attached to; null when the entry is not attached to one, or once that work item is deleted.
Whether the hours count as overtime. Sending it without the times::write_overtime permission leaves it false and adds an input_ignored warning rather than failing the write.
Whether these hours are excluded from invoicing. Inferred from the task's is_billable flag (false without a task) on create and again whenever task_id is sent. Sending a value that differs from the inferred or current one requires billable_change_reason and puts the entry in a reviewer's queue; without it the write is a 422 on /billable_change_reason.
Why the inferred billability was overridden. Required whenever is_not_billable is sent with a value that differs from the inferred or current one, on create and on PATCH alike; the override puts the entry in a reviewer's queue, reopening one a reviewer had already settled.
Response 200
Returns a Time in the detail view.
Headers
ETag- A strong validator of exactly this representation.
RateLimit- The IETF
httpapi-ratelimit-headersform of your remaining allowance on the tightest bucket this request touched. RateLimit-Policy- The ceiling and window of that bucket, as
<limit>;w=<seconds>. X-Request-Id- The server-generated ULID correlating this response with our logs.
Every response also carries Cache-Control, Vary, X-Content-Type-Options, X-Plnnrly-Api-Version, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Headers and versioning
The project the hours are booked against, always expanded. Its customer_id is the customer to fetch with GET /api/v2/customers/{customer}; the customer itself is not nested.
Budget the hours are invoiced against. Derived from the task, never accepted on a write; null when no task is set or the budget is deleted.
The budget the hours are invoiced against. Expanding it with ?include=budget additionally requires the budgets::read permission and a token scope covering the budgets prefix.
Task the hours are booked on; null when the entry is not attached to one, or once that task is deleted.
The task the hours are booked on. Expanding it with ?include=task additionally requires the kanban::manage_self permission and a token scope covering the kanban prefix, and is limited to the tasks you can see on the tasks collection.
Work item the hours are attached to; null when the entry is not attached to one, or once that work item is deleted.
The work item the hours are attached to, always expanded.
Employee the hours belong to. Assigned on create (from the authenticated user, or from on_behalf_of_user_id) and never writable afterwards; reassigning a worklog is a DELETE plus a POST.
The employee the hours belong to. Expanding it with ?include=user additionally requires the users::read permission and a token scope covering the users prefix.
Whether these hours are excluded from invoicing. Inferred from the task's is_billable flag (false without a task) on create and again whenever task_id is sent. Sending a value that differs from the inferred or current one requires billable_change_reason and puts the entry in a reviewer's queue; without it the write is a 422 on /billable_change_reason.
Whether the hours count as overtime. Sending it without the times::write_overtime permission leaves it false and adds an input_ignored warning rather than failing the write.
Whether the entry was booked knowing it exceeds its budget. Set on create only, and true whenever a reason is sent; setting it puts the entry in a reviewer's queue.
Why the budget overrun was accepted. Sending it on create marks the entry as exceeding its budget. Once a reviewer has settled the entry it can no longer be changed: a PATCH that does answers 409 reason_reviewed.
Why the inferred billability was overridden. Required whenever is_not_billable is sent with a value that differs from the inferred or current one, on create and on PATCH alike; the override puts the entry in a reviewer's queue, reopening one a reviewer had already settled.
The reviewer who settled the entry, once one has. Set by the review queue in plnnrly; this API exposes no way to write it.
The invoice these hours were billed on, once they have been. While it is set, the entry is locked: a write answers 409 with conflict.reason locked_by_invoice.
The sales-invoice line these hours were billed on, once they have been. Set by the invoicing flow.
Errors
403 Forbidden.
forbidden-by-policyinsufficient-permissioninsufficient-token-scope
forbidden-by-policy: You point the entry at something its owner may not log time on: a project_id where the owner holds no task, a task_id that is not one of the owner's own tasks, or a work_item_id the owner may not log time on. Holding times::write_on_others_tasks lifts the first two rules, never the third. You also get this answer on a colleague's entry when you hold times::delete_others but not times::update_others: either permission lets you see it, only times::update_others lets you change it.
409 Conflict.
412 Precondition failed.
415 Unsupported media type.
422 Unprocessable content.
7 errors every operation can return: 400, 401, 404, 406, 429, 500, 503
400 Bad request.
idempotency-key-requiredinvalid-cursorinvalid-query-parametermalformed-requestunsupported-parameter
401 Unauthenticated.
404 Not found.
406 Not acceptable.
429 Too many requests.
500 Server error.
503 Service unavailable.
This path allows GET, PATCH, DELETE. Anything else answers 405.
Something wrong or missing on this page? Tell us