Complete or reopen a milestone
Marks a milestone (or one occurrence of a recurring milestone) as completed or not completed.
Send the MilestoneId and IsRecurring of a GET /v2/milestones/incomplete entity unchanged. isRecurring=true treats id as a recurring-milestone INSTANCE ID and flips only that occurrence's IsCompleted (no event); isRecurring=false treats id as a milestone ID, sets its completion, refreshes the parent task's status, saves it with the caller as modifier and raises MilestoneChangeStatus. Setting the status it already has does nothing. Answers 200 with body null. The flag is trusted: a wrong isRecurring addresses a different milestone that shares the number.
Use it to:
- Tick off a milestone from a reminder list
Behaviour:
- Idempotent.
- Safe to retry.
- Side effect: Recurring instance: IsCompleted, LastModifiedBy, LastModified updated (no event).
- Changes are visible to the next read immediately.
Call first: GET /v2/milestones/incomplete
Not yet documented: behaviour → side effects; examples.
curl -X PUT "https://app3.timelog.com/your-account/api/v2/milestones/123/status?isCompleted=true&isRecurring=true" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN"
import requests
import json
url = "https://app3.timelog.com/your-account/api/v2/milestones/123/status?isCompleted=true&isRecurring=true"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
response = requests.put(url, headers=headers)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v2/milestones/123/status?isCompleted=true&isRecurring=true", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
)
func main() {
req, err := http.NewRequest("PUT", "https://app3.timelog.com/your-account/api/v2/milestones/123/status?isCompleted=true&isRecurring=true", nil)
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/milestones/123/status?isCompleted=true&isRecurring=true')
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'
response = http.request(request)
puts response.body
"null"
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Not Found",
"message": "The requested resource was not found",
"code": 404
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/v2/milestones/{id}/statusTarget 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.MilestoneId from the list: a recurring-instance ID when isRecurring is true, otherwise a milestone ID. Unknown → 500.
true = completed, false = reopen. Omitted → 404 (captured).
Which ID space id belongs to — pass MilestoneRead.IsRecurring unchanged. Omitted → 404 (captured).
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.
Path Parameters
MilestoneId from the list: a recurring-instance ID when isRecurring is true, otherwise a milestone ID. Unknown → 500.
Query Parameters
true = completed, false = reopen. Omitted → 404 (captured).
Which ID space id belongs to — pass MilestoneRead.IsRecurring unchanged. Omitted → 404 (captured).
Responses
*Success without content: HTTP 200 with the literal JSON body null. Body is the JSON literal null (TafSuccessResult), also when nothing changed.
Empty result: Not applicable.*