ProjectsUpdate an allocation

Update an allocation

Changes the planned hours, hourly rate and/or period of an existing allocation and returns it.

Partial update (AllocationUpdate): only AllocatedHours, HourlyRateID, StartDate and EndDate can change, and at least one must be sent. Dates need the account feature 'Enable start and end date on allocations' and are refused on allocations of recurring tasks. A changed HourlyRateID must be an active rate of the task's contract; an unchanged one is not re-checked. Runs the same follow-up as the project-plan save: the task's dates may follow the allocation span, the project is re-saved, subscribed project managers are e-mailed. Answers 200 with the allocation as stored (AllocationRead). Requires project privileges on the task's project. Not atomic.

Use it to:

  • Re-plan hours of a staffed user from a resource-planning or PSA tool
  • Move an allocation's period (AllocationDates feature)
  • Resolve a 409 from POST /v1/task/{taskID}/allocation by updating the existing allocation

Not for:

  • Allocating a new user → POST /v1/task/{taskID}/allocation
  • Completing / re-opening an allocation — the status cannot be changed here

Rules across fields:

  • R1: At least one of AllocatedHours, HourlyRateID, StartDate, EndDate must be sent (400).
  • R2: Both dates sent: EndDate >= StartDate (400 Code 200). One date sent: the effective period (other date from the stored allocation) must not end before it starts (400).

Behaviour:

  • Idempotent.
  • Sending the same values again stores the same state; it still runs a full save (audit / e-mail event, project save).
  • Safe to retry only under a condition. Safe after a 2xx or a timeout. After a 400 from the project save (allocation-save-violation) or a 500, the allocation may already be updated — re-read it first.
  • Side effect: Updates the allocation row with an audit-log + e-mail event (EventAction BothAuditLogAndEmail, like the project-plan UI save), so subscribed project managers are mailed.
  • Side effect: With AutomaticallyCloseTaskWhenLastAllocationIsClosed on: if the task is In progress and has no active (not completed) allocation, the task is set to Completed, the project saved and close notifications sent — called on every update, whatever changed.
  • Side effect: Re-saves the project.
  • Side effect: Dates changed, no task date sync, AllocationDates on: sends the 'allocation exceeds task dates' notification when the period goes beyond the task.
  • Changes are visible to the next read immediately.

Call first: GET /v1/allocation/{allocationID}, GET /v1/task/{taskID}/allocation

Next: GET /v1/allocation/{allocationID}

See also: POST /v1/task/{taskID}/allocation, DELETE /v1/allocation/{allocationID}

Not yet documented: behaviour → consistency; behaviour → side effects; examples.

curl -X PUT "https://app3.timelog.com/your-account/api/v1/allocation/123" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "AllocatedHours": "null",
  "HourlyRateID": "null",
  "StartDate": "null",
  "EndDate": "null"
}'
{
  "Properties": {
    "AllocationID": 123,
    "TaskID": 123,
    "UserID": 123,
    "AllocatedHours": 3.14,
    "RegisteredHours": 3.14,
    "HourlyRateID": 123,
    "HourlyRateName": "null",
    "HourlyRateAmount": 3.14,
    "HourlyRateCurrencyAbb": "example_string",
    "StartDate": "null",
    "EndDate": "null",
    "IsRecurring": true,
    "IsCompleted": true
  },
  "Links": [
    {
      "Href": "example_string",
      "Rel": "example_string"
    }
  ],
  "Actions": [
    {}
  ]
}
PUT
/v1/allocation/{allocationID}
PUT
Base URLstring

Target server for requests. Edit to use your own host.

Bearer Token
Bearer Tokenstring
Required

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.
path
allocationIDinteger
Required

The allocation to change. Route constraint :int.

Format: int32
Content-Typestring
Required

The media type of the request body

Options: application/json
AllocatedHoursnumbernull

New planned hours of the user on the task. Null: null / omitted = unchanged. Unit: hours - Negative — 400 Code 200 (FluentValidation GreaterThanOrEqualTo(0)).

Format: double
HourlyRateIDintegernull

New contract hourly rate of the allocation (a rate of the task's contract). Refers to ContractHourlyRateRead.ContractHourlyRateID. Look up valid values with GET /v1/contract-hourly-rate. Null: null / omitted = unchanged. 0 is rejected by the body validator; there is no way to clear the rate. - 0 or negative — 400 Code 200 (GreaterThan(0)). - Different from the current rate and not a rate of the task's contract, or an inactive rate — 400 (rest.projectmanagement.allocation-update-rate-invalid). - Equal to the current rate — Not re-validated, so GET-modify-PUT keeps working on a rate that was deactivated since. Valid values come from GET /v1/contract-hourly-rate.

Format: int32
StartDatestringnull

New first day of the allocation period. Conditional. Accepted only when the account feature AllocationDates ('Enable start and end date on allocations') is on, and never for an allocation on a recurring task (it has no period). Null: null / omitted = unchanged. Time zone: none — the time part is dropped (stored as whole days) - AllocationDates feature off — 400 Code 200 'StartDate cannot be set because the feature ...' - Allocation on a recurring task — 400 (rest.projectmanagement.allocation-update-period-invalid). - Effective EndDate (sent or stored) before it — 400 (allocation-update-period-invalid); both sent → 400 Code 200. - Any time of day — Truncated to the date (.Date).

Format: date-time
EndDatestringnull

New last day of the allocation period. Conditional. Same as StartDate: AllocationDates feature on, and not a recurring-task allocation. Null: null / omitted = unchanged. Time zone: none — the time part is dropped (stored as whole days) - AllocationDates feature off — 400 Code 200 'EndDate cannot be set because the feature ...' - Both dates sent and EndDate < StartDate — 400 Code 200 (GreaterThanOrEqualTo). - Any time of day — Truncated to the date (.Date).

Format: date-time
Request Preview
Response

Response will appear here after sending the request

Authentication

header
Authorizationstring
Required

Bearer token. OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).

The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.

Not yet documented: how to obtain a token.

Not yet documented: token lifetime.

Path Parameters

allocationIDinteger
Required

The allocation to change. Route constraint :int.

Body

application/json
AllocatedHoursnumber,null

New planned hours of the user on the task.

Null: null / omitted = unchanged.

Unit: hours

  • Negative — 400 Code 200 (FluentValidation GreaterThanOrEqualTo(0)).
HourlyRateIDinteger,null

New contract hourly rate of the allocation (a rate of the task's contract).

Refers to ContractHourlyRateRead.ContractHourlyRateID. Look up valid values with GET /v1/contract-hourly-rate.

Null: null / omitted = unchanged. 0 is rejected by the body validator; there is no way to clear the rate.

  • 0 or negative — 400 Code 200 (GreaterThan(0)).

  • Different from the current rate and not a rate of the task's contract, or an inactive rate — 400 (rest.projectmanagement.allocation-update-rate-invalid).

  • Equal to the current rate — Not re-validated, so GET-modify-PUT keeps working on a rate that was deactivated since.

Valid values come from GET /v1/contract-hourly-rate.

StartDatestring,null

New first day of the allocation period.

Conditional. Accepted only when the account feature AllocationDates ('Enable start and end date on allocations') is on, and never for an allocation on a recurring task (it has no period).

Null: null / omitted = unchanged.

Time zone: none — the time part is dropped (stored as whole days)

  • AllocationDates feature off — 400 Code 200 'StartDate cannot be set because the feature ...'

  • Allocation on a recurring task — 400 (rest.projectmanagement.allocation-update-period-invalid).

  • Effective EndDate (sent or stored) before it — 400 (allocation-update-period-invalid); both sent → 400 Code 200.

  • Any time of day — Truncated to the date (.Date).

EndDatestring,null

New last day of the allocation period.

Conditional. Same as StartDate: AllocationDates feature on, and not a recurring-task allocation.

Null: null / omitted = unchanged.

Time zone: none — the time part is dropped (stored as whole days)

  • AllocationDates feature off — 400 Code 200 'EndDate cannot be set because the feature ...'

  • Both dates sent and EndDate < StartDate — 400 Code 200 (GreaterThanOrEqualTo).

  • Any time of day — Truncated to the date (.Date).

Responses

Propertiesobject

One user's allocation on a task: planned (allocated) hours, hours already registered, the contract hourly rate with its name, amount and currency, the allocation period, and whether it is recurring or completed.

Linksarray
Actionsobject[]