Change the status of several projects
Moves every listed project to one status (Quote … Cancelled), one project after another.
For each ID in projectsIds, in the order given: loads the project, changes its status with TimeLog's status processing and saves it. InProgress opens the project for time registration; OnHold / Completed / Archived / Cancelled close it; Quote / Approved keep the project's current flag. Completed, Archived and Cancelled also mark every open milestone completed and move every open contract to Completed (Cancelled for Cancelled) — reopening later does NOT reopen contracts. Answers 200 with an empty TAF list whose Properties.UpdatedProjectsCount is the number of IDs processed. The first failing project aborts the call with 500 and the earlier projects KEEP their new status; there is no per-project result. Always send Status: {} moves every listed project to Quote.
Use it to:
- Close a batch of finished projects (Completed / Archived) from a portfolio tool
Not for:
- Opening a Quote / Approved project for time registration — this route keeps the current flag; use
PUT /v1/project/{projectID}/status(AllowTimeTracking)
Rules across fields:
- R1: When the projectsIds string is exactly one character long (a single project 1–9), Date is replaced by today.
Behaviour:
- Idempotent.
- Same status again re-applies it: status date reset, ProjectStatusChanged raised again, project re-saved.
- Safe to retry only under a condition. After a 500 re-send the whole list: projects already moved are re-applied harmlessly; closing statuses never reopen contracts, so a retry cannot undo the cascade.
- Side effect: Per project: status units / status date written and the status stored, OpenForTimeRegistration set by status.
- Side effect: Completed / Archived / Cancelled: open milestones completed, every open contract moved to Completed / Cancelled.
- On failure: Projects before the failing one keep their new status; within the failing project the status may already be written before the save fails.
- Changes are visible to the next read immediately.
- Batch: Sequential, no transaction, no per-item result: the first failure aborts the rest with 500 and gives no indication which projects were already changed.
Call first: GET /v2/projects, GET /v2/projects/actions
See also: PUT /v1/project/{projectID}/status
Not yet documented: errors; examples.
curl -X PUT "https://app3.timelog.com/your-account/api/v2/projects/status?projectsIds=example_string" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"Status": 42,
"Date": "null"
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v2/projects/status?projectsIds=example_string"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"Status": 42,
"Date": "null"
}
response = requests.put(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v2/projects/status?projectsIds=example_string", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"Status": 42,
"Date": "null"
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"Status": 42,
"Date": "null"
}`)
req, err := http.NewRequest("PUT", "https://app3.timelog.com/your-account/api/v2/projects/status?projectsIds=example_string", bytes.NewBuffer(data))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://app3.timelog.com/your-account/api/v2/projects/status?projectsIds=example_string')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"Status": 42,
"Date": "null"
}'
response = http.request(request)
puts response.body
{
"Properties": {
"UpdatedProjectsCount": "example_string"
},
"Links": [
{
"Href": "example_string",
"Rel": "example_string"
}
],
"Actions": [
{}
]
}
{
"error": "Bad Request",
"message": "The request contains invalid parameters or malformed data",
"code": 400,
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"code": "UnsupportedApiVersion",
"error": "No route providing a controller name with API version '2' was found to match HTTP method 'PUT' and request URI 'https://app{server-number}.timelog.com/{account}/api/v2/projects/status'.",
"traceId": "…",
"type": "https://docs.api-versioning.org/problems#unsupported",
"title": "Unsupported API version",
"status": 405,
"detail": "The requested resource with API version '2' does not support HTTP method 'PUT'."
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/v2/projects/status
Target server for requests. Edit to use your own host.
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.
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.Comma-separated project IDs, processed in order; duplicates are processed (and counted) twice. Omitted → 405 (captured). A non-integer entry → 500 after the entries before it were applied.
Several values: one string, separated by ,.
The media type of the request body
The new status, as the OrderStatus integer. Non-nullable: when omitted it arrives as 0 and is APPLIED — {} moves every listed project to Quote.
- Not one of 0–6 — 400 "Status must be 0 = Quote or 1 = Approved or 2 = InProgress or 3 = OnHold or 4 = Completed or 5 = Archived or 6 = Cancelled."
- Omitted — 0 = Quote is applied.
- Quote or Approved — OpenForTimeRegistration is left as the project had it (the controller passes the project's own flag).
Allowed values:
| Value | Name | Meaning |
|---|---|---|
| 0 | Quote | Quote. Time registration keeps the project's current open/closed flag. |
| 1 | Approved | Approved. Time registration keeps the project's current open/closed flag. |
| 2 | InProgress | In progress. Opens the project for time registration. |
| 3 | OnHold | On hold. Closes the project for time registration. |
| 4 | Completed | Completed. Closes time registration, completes open milestones, moves every open contract to Completed. Refused (37969) when a multi-customer contract uses the system customer. |
| 5 | Archived | Archived. Closes time registration, completes open milestones, moves every open contract to Completed. |
| 6 | Cancelled | Cancelled. Closes time registration, completes open milestones, moves every open contract to Cancelled. |
Status date to record (date part only). When omitted: the date already stored for that status, or today (ProjectStatusUnitRule). Date only — no time component. Default: the status's existing date, else today - projectsIds has exactly one character — Replaced by today's date. - Time part sent — statusDate.Value.Date keeps the date only.
Request Preview
Response
Response will appear here after sending the request
Authentication
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.
Query Parameters
Comma-separated project IDs, processed in order; duplicates are processed (and counted) twice. Omitted → 405 (captured). A non-integer entry → 500 after the entries before it were applied.
Several values: one string, separated by ,.
Body
The new status, as the OrderStatus integer. Non-nullable: when omitted it arrives as 0 and is APPLIED — {} moves every listed project to Quote.
-
Not one of 0–6 — 400 "Status must be 0 = Quote or 1 = Approved or 2 = InProgress or 3 = OnHold or 4 = Completed or 5 = Archived or 6 = Cancelled."
-
Omitted — 0 = Quote is applied.
-
Quote or Approved — OpenForTimeRegistration is left as the project had it (the controller passes the project's own flag).
Allowed values:
| Value | Name | Meaning |
|---|---|---|
0 | Quote | Quote. Time registration keeps the project's current open/closed flag. |
1 | Approved | Approved. Time registration keeps the project's current open/closed flag. |
2 | InProgress | In progress. Opens the project for time registration. |
3 | OnHold | On hold. Closes the project for time registration. |
4 | Completed | Completed. Closes time registration, completes open milestones, moves every open contract to Completed. Refused (37969) when a multi-customer contract uses the system customer. |
5 | Archived | Archived. Closes time registration, completes open milestones, moves every open contract to Completed. |
6 | Cancelled | Cancelled. Closes time registration, completes open milestones, moves every open contract to Cancelled. |
0123456Status date to record (date part only). When omitted: the date already stored for that status, or today (ProjectStatusUnitRule).
Date only — no time component.
Default: the status's existing date, else today
-
projectsIds has exactly one character — Replaced by today's date.
-
Time part sent — statusDate.Value.Date keeps the date only.
Responses
How many projects a /v2/projects bulk write processed or changed.