Set an external key on a project
Creates or replaces the key a project has in one external system.
Upsert keyed on (project, external system): if the project already has a key for that system it is overwritten. TimeLog does not enforce uniqueness of the key value: the same ExternalID can be stored on several projects of the same system, and DELETE then removes it from all of them.
Use it to:
- Store the ID of the source record after syncing a project from an ERP / CRM
Behaviour:
- Idempotent.
- Safe to retry.
- Duplicates: The same ExternalID can be stored on several projects of one external system without error (no unique constraint on the value).
- Changes are visible to the next read immediately.
Call first: GET /v1/project/get-all
Next: GET /v1/project/{projectID}/external-keys
See also: PUT /v1/time-registration/{timeRegistrationID}/external-keys
Not yet documented: examples.
curl -X PUT "https://app3.timelog.com/your-account/api/v1/project/123/external-keys" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/project/123/external-keys"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
}
response = requests.put(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/project/123/external-keys", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
}`)
req, err := http.NewRequest("PUT", "https://app3.timelog.com/your-account/api/v1/project/123/external-keys", 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/v1/project/123/external-keys')
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 = '{
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
}'
response = http.request(request)
puts response.body
{
"Properties": {
"ExternalID": "example_string",
"ExternalSystemID": 123,
"ExternalSystemName": "John Doe",
"DomainType": 42,
"DomainID": 123,
"DomainGuid": "123e4567-e89b-12d3-a456-426614174000",
"IsIgnored": true
},
"Links": [
{
"Href": "example_string",
"Rel": "example_string"
}
],
"Actions": [
{}
]
}
{
"Code": 200,
"Details": [
"'External ID' must not be empty.",
"'External System ID' must not be empty.",
"'External System ID' must be greater than '0'."
],
"Message": "Invalid model state error.",
"Parameters": "externalKeysUpdateModel: {"ExternalID":null,"ExternalSystemID":0}",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/project/1/external-keys"
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/v1/project/{projectID}/external-keysTarget 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.Route constraint :int.
The media type of the request body
The object's identifier in the external system. Key from your own system. Uniqueness is not enforced. NOT unique: two time registrations (or two projects, or two tasks) can carry the same ExternalID in the same external system. TimeLog does not deduplicate by external key — integrators must. Values over 250 characters are not rejected by validation (server outcome unknown).
The external system the key belongs to.
Refers to ExternalSystemRead.ExternalSystemID. Look up valid values with GET /v1/external-systems.
Unknown ID fails with business rule 37045.
The object type: 147 (TimeRegistration) on /v1/time-registration/…, 51 (Project) on /v1/project/…, 98 (Task) on /v1/task/….
The TimeRegistrationID (or, on the project / task endpoints, the ProjectID / TaskID).
Refers to TimeRegistrationRead.TimeRegistrationID.
The TimeRegistrationGUID (or the project / task GUID on those endpoints).
Never set by these endpoints.
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
Route constraint :int.
Body
The object's identifier in the external system.
Key from your own system. Uniqueness is not enforced.
NOT unique: two time registrations (or two projects, or two tasks) can carry the same ExternalID in the same external system. TimeLog does not deduplicate by external key — integrators must. Values over 250 characters are not rejected by validation (server outcome unknown).
The external system the key belongs to.
Refers to ExternalSystemRead.ExternalSystemID. Look up valid values with GET /v1/external-systems.
Unknown ID fails with business rule 37045.
The object type: 147 (TimeRegistration) on /v1/time-registration/…, 51 (Project) on /v1/project/…, 98 (Task) on /v1/task/….
The TimeRegistrationID (or, on the project / task endpoints, the ProjectID / TaskID).
Refers to TimeRegistrationRead.TimeRegistrationID.
The TimeRegistrationGUID (or the project / task GUID on those endpoints).
Never set by these endpoints.
Responses
Links a TimeLog object to its identifier in an external system (ERP, payroll, CRM …). One key per (object, external system).