Skip to content

Update a time entry

PUT
/api/time-entries/{id}
curl --request PUT \
--url https://invoicing-api.eddish.app/api/time-entries/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "workTaskId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "spentDate": "2026-04-15", "hours": 1, "notes": "example", "billable": true, "startedTime": "example", "endedTime": "example" }'

Updates a time entry. Give both times or neither: with both, they must be on quarter hours and the hours are worked out from them; with neither, an entry that has times keeps its start and its end moves to match the hours (rounded up to a quarter). Fails with 409 if it has been invoiced, its week is locked by approval, the times overlap another entry that day, or a timer is running and times are given. The hours of a running entry can’t be changed.

id
required
string format: uuid
Media typeapplication/json

The new details of a time entry.

object
projectId
required
string format: uuid
workTaskId
required
string format: uuid
spentDate
required

The day the time was worked, as yyyy-MM-dd.

string format: date
hours
required

Hours worked, as a decimal: 1.5 is an hour and a half.

number | string format: double
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/
notes
required
null | string
billable
required
boolean
startedTime

The time of day the work started, as HH:mm:ss. Give both times or neither; with both, they must be on quarter hours and the hours are worked out from them. With neither, a timed entry keeps its start and moves its end to match the hours, rounded up to a quarter.

null | string format: time
endedTime

The time of day the work ended, as HH:mm:ss. Must be after the start time.

null | string format: time

Example generated

{
"projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"workTaskId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"spentDate": "2026-04-15",
"hours": 1,
"notes": "example",
"billable": true,
"startedTime": "example",
"endedTime": "example"
}

OK

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data
One of:
null
error
One of:
null

Example generated

{
"success": true,
"data": {
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"projectName": "example",
"clientId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"clientName": "example",
"workTaskId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"workTaskName": "example",
"userId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"userName": "example",
"spentDate": "2026-04-15",
"hours": 1,
"notes": "example",
"startedTime": "example",
"endedTime": "example",
"timerStartedAtUtc": "2026-04-15T12:00:00Z",
"isRunning": true,
"isLocked": true,
"billable": true,
"billableRate": 1,
"isBilled": true,
"invoiceId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"createdAtUtc": "2026-04-15T12:00:00Z"
},
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

Not signed in, or the credential isn’t recognised, has expired or was revoked: auth.missing_credential, auth.invalid_credential, auth.expired_credential, auth.revoked_credential.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

Not allowed. error.code says why: auth.role_not_permitted (your role doesn’t allow it), auth.read_only_token (the token can only read), app.no_seat (no seat in this App), auth.api_access_not_in_plan (the plan doesn’t include API access), auth.not_a_member (no longer a member of the Account), auth.insufficient_scope (an Account API key without the scope).

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

The Account is over its plan’s limits, so changes are refused until an Owner or Admin sorts that out: plan.read_only.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}

Too many requests: rate_limit.exceeded. Wait the number of seconds in the Retry-After header.

Media typeapplication/json

Shorthand for the overwhelmingly common ServiceResponse&lt;TData, ErrorResponse&gt;. C# cannot alias an open generic, so this is expressed as a subclass rather than a using alias.

object
success

True when the call succeeded and TData? ServiceResponse<TData, TError>.Data is populated.

boolean
data

Payload on success; default on failure.

error

The Framework’s default error shape, used as the TError of ServiceResponse<TData, TError> unless an App genuinely needs its own.

object
code

Stable, machine-readable error identifier (for example account.not_found). Clients branch on this, never on string ErrorResponse.Message.

string
message

Human-readable description of what went wrong. Safe to surface to a User.

string
fieldErrors

Optional per-field validation failures, keyed by field name. Null (and omitted from JSON) for errors that are not validation failures.

null | object
details

Optional machine-readable facts about the failure that a client renders rather than parses out of string ErrorResponse.Message — e.g. plan.limit_reached’s limit, count and planName. Null (and omitted from JSON) for errors that carry none.

null | object

Example generated

{
"success": true,
"data": "example",
"error": {
"code": "example",
"message": "example",
"fieldErrors": "example",
"details": "example"
}
}
Retry-After
integer

Seconds to wait before trying again.