Validate a new contact person
Runs the contact create validations on a body without saving anything.
Runs model validation (FirstName, LastName, CountryID > 0), the adapter's customer lookup and the country rule of POST /v1/contact/create, then returns 200 with the body null.
Use it to:
- Validate a contact form before submitting, to show TimeLog's errors early
Behaviour:
- Idempotent.
- Safe to retry.
- Changes are visible to the next read immediately.
Call first: GET /v1/country/get-all
Next: POST /v1/contact/create
Not yet documented: examples (success).
curl -X POST "https://app3.timelog.com/your-account/api/v1/contact/validate-new-contact" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"FirstName": "John Doe",
"LastName": "John Doe",
"CountryID": 123,
"CustomerID": 123,
"OwnerID": 123,
"Phone": "+1-555-0123",
"PrivatePhone": "+1-555-0123",
"Mobile": "example_string",
"Fax": "example_string",
"Email": "user@example.com",
"Department": "example_string",
"JobTitle": "example_string",
"Address": "123 Main St",
"Address2": "123 Main St",
"Address3": "123 Main St",
"ZipCode": "example_string",
"City": "New York",
"State": "example_string",
"Salutation": "example_string",
"Initials": "example_string",
"ProfessionalTitle1": "example_string",
"ProfessionalTitle2": "example_string",
"Comment": "example_string",
"Birthday": "null"
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/contact/validate-new-contact"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"FirstName": "John Doe",
"LastName": "John Doe",
"CountryID": 123,
"CustomerID": 123,
"OwnerID": 123,
"Phone": "+1-555-0123",
"PrivatePhone": "+1-555-0123",
"Mobile": "example_string",
"Fax": "example_string",
"Email": "user@example.com",
"Department": "example_string",
"JobTitle": "example_string",
"Address": "123 Main St",
"Address2": "123 Main St",
"Address3": "123 Main St",
"ZipCode": "example_string",
"City": "New York",
"State": "example_string",
"Salutation": "example_string",
"Initials": "example_string",
"ProfessionalTitle1": "example_string",
"ProfessionalTitle2": "example_string",
"Comment": "example_string",
"Birthday": "null"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/contact/validate-new-contact", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"FirstName": "John Doe",
"LastName": "John Doe",
"CountryID": 123,
"CustomerID": 123,
"OwnerID": 123,
"Phone": "+1-555-0123",
"PrivatePhone": "+1-555-0123",
"Mobile": "example_string",
"Fax": "example_string",
"Email": "user@example.com",
"Department": "example_string",
"JobTitle": "example_string",
"Address": "123 Main St",
"Address2": "123 Main St",
"Address3": "123 Main St",
"ZipCode": "example_string",
"City": "New York",
"State": "example_string",
"Salutation": "example_string",
"Initials": "example_string",
"ProfessionalTitle1": "example_string",
"ProfessionalTitle2": "example_string",
"Comment": "example_string",
"Birthday": "null"
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"FirstName": "John Doe",
"LastName": "John Doe",
"CountryID": 123,
"CustomerID": 123,
"OwnerID": 123,
"Phone": "+1-555-0123",
"PrivatePhone": "+1-555-0123",
"Mobile": "example_string",
"Fax": "example_string",
"Email": "user@example.com",
"Department": "example_string",
"JobTitle": "example_string",
"Address": "123 Main St",
"Address2": "123 Main St",
"Address3": "123 Main St",
"ZipCode": "example_string",
"City": "New York",
"State": "example_string",
"Salutation": "example_string",
"Initials": "example_string",
"ProfessionalTitle1": "example_string",
"ProfessionalTitle2": "example_string",
"Comment": "example_string",
"Birthday": "null"
}`)
req, err := http.NewRequest("POST", "https://app3.timelog.com/your-account/api/v1/contact/validate-new-contact", 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/contact/validate-new-contact')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"FirstName": "John Doe",
"LastName": "John Doe",
"CountryID": 123,
"CustomerID": 123,
"OwnerID": 123,
"Phone": "+1-555-0123",
"PrivatePhone": "+1-555-0123",
"Mobile": "example_string",
"Fax": "example_string",
"Email": "user@example.com",
"Department": "example_string",
"JobTitle": "example_string",
"Address": "123 Main St",
"Address2": "123 Main St",
"Address3": "123 Main St",
"ZipCode": "example_string",
"City": "New York",
"State": "example_string",
"Salutation": "example_string",
"Initials": "example_string",
"ProfessionalTitle1": "example_string",
"ProfessionalTitle2": "example_string",
"Comment": "example_string",
"Birthday": "null"
}'
response = http.request(request)
puts response.body
"null"
{
"Code": 200,
"Details": [
"'First Name' must not be empty.",
"'Last Name' must not be empty.",
"'Country ID' must be greater than 0."
],
"Message": "Invalid model state error.",
"Parameters": "contact: {...}",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/contact/validate-new-contact"
}
{
"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/contact/validate-new-contact
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.The media type of the request body
First name of the contact. Can be set on create only. Contains personal data. - null, empty or whitespace — 400 "'First Name' must not be empty."
Last name of the contact. Can be set on create only. Contains personal data. - null, empty or whitespace — 400 "'Last Name' must not be empty."
Country of the contact's address.
Can be set on create only.
Refers to CountryRead.CountryID. Look up valid values with GET /v1/country/get-all.
- 0, negative or omitted — 400 "'Country ID' must be greater than 0."
- positive but unknown — 500 Code 102, ErrorCode 30017 (rest.crm.country-unknown).
Valid values come from GET /v1/country/get-all.
The customer the contact belongs to.
Can be set on create only.
Refers to CustomerRead.CustomerID. Look up valid values with GET /v1/customer.
- 0 or omitted — The contact is created WITHOUT a customer (KundeId 0); CustomerID 0 in the response.
- The business rule CustomerExist never runs — it is gated on a change flag that is never set for CustomerID.
Valid values come from GET /v1/customer.
UserID of the TimeLog user who owns the contact. It also decides access for callers whose customer privilege is "customers where I am account manager": such a caller may create a contact only when they name themselves as owner.
Refers to UserRead.UserID. Look up valid values with GET /v1/user.
- 0 or omitted — No owner.
- unknown UserID — The lookup exception is swallowed and the contact is created without an owner — no error.
Valid values come from GET /v1/user.
Work phone. Can be set on create only. Contains personal data.
Private phone. Can be set on create only. Contains personal data.
Mobile phone. Can be set on create only. Contains personal data.
Fax number. Can be set on create only.
E-mail address. No format validation. Can be set on create only. Contains personal data.
Free-text department of the contact at the customer. Can be set on create only.
Job title (stored as Stillingsbetegnelse). Can be set on create only.
Address line 1. Can be set on create only. Contains personal data.
Address line 2. Can be set on create only. Contains personal data.
Accepted and discarded — contacts have no third address line. Can be set on create only.
Postal code. Can be set on create only. Contains personal data.
City. Can be set on create only. Contains personal data.
State / region. Can be set on create only.
Salutation / prefix (e.g. a courtesy title). Can be set on create only.
Initials. Longer values are silently truncated to 10. Can be set on create only. Contains personal data.
First professional title. Longer values are silently truncated to 20. Can be set on create only.
Second professional title. Longer values are silently truncated to 20. Can be set on create only.
Free-text comment on the contact.
Birthday of the contact. Time zone: not yet documented. Contains personal data. > Not yet documented: constraints → timezone.
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.
Body
First name of the contact.
Can be set on create only.
Contains personal data.
- null, empty or whitespace — 400 "'First Name' must not be empty."
Last name of the contact.
Can be set on create only.
Contains personal data.
- null, empty or whitespace — 400 "'Last Name' must not be empty."
Country of the contact's address.
Can be set on create only.
Refers to CountryRead.CountryID. Look up valid values with GET /v1/country/get-all.
-
0, negative or omitted — 400 "'Country ID' must be greater than 0."
-
positive but unknown — 500 Code 102, ErrorCode 30017 (rest.crm.country-unknown).
Valid values come from GET /v1/country/get-all.
The customer the contact belongs to.
Can be set on create only.
Refers to CustomerRead.CustomerID. Look up valid values with GET /v1/customer.
-
0 or omitted — The contact is created WITHOUT a customer (KundeId 0); CustomerID 0 in the response.
-
The business rule CustomerExist never runs — it is gated on a change flag that is never set for CustomerID.
Valid values come from GET /v1/customer.
UserID of the TimeLog user who owns the contact. It also decides access for callers whose customer privilege is "customers where I am account manager": such a caller may create a contact only when they name themselves as owner.
Refers to UserRead.UserID. Look up valid values with GET /v1/user.
-
0 or omitted — No owner.
-
unknown UserID — The lookup exception is swallowed and the contact is created without an owner — no error.
Valid values come from GET /v1/user.
Work phone.
Can be set on create only.
Contains personal data.
Private phone.
Can be set on create only.
Contains personal data.
Mobile phone.
Can be set on create only.
Contains personal data.
Fax number.
Can be set on create only.
E-mail address. No format validation.
Can be set on create only.
Contains personal data.
Free-text department of the contact at the customer.
Can be set on create only.
Job title (stored as Stillingsbetegnelse).
Can be set on create only.
Address line 1.
Can be set on create only.
Contains personal data.
Address line 2.
Can be set on create only.
Contains personal data.
Accepted and discarded — contacts have no third address line.
Can be set on create only.
Postal code.
Can be set on create only.
Contains personal data.
City.
Can be set on create only.
Contains personal data.
State / region.
Can be set on create only.
Salutation / prefix (e.g. a courtesy title).
Can be set on create only.
Initials. Longer values are silently truncated to 10.
Can be set on create only.
Contains personal data.
First professional title. Longer values are silently truncated to 20.
Can be set on create only.
Second professional title. Longer values are silently truncated to 20.
Can be set on create only.
Free-text comment on the contact.
Birthday of the contact.
Time zone: not yet documented.
Contains personal data.
Not yet documented: constraints → timezone.
Responses
Success without content: HTTP 200 with the literal JSON body null. Literal JSON null — the body is valid.