Validate a new payment
Runs the create-payment checks on a body without saving anything.
Unlike create it does not unlink the task's other instalments, so it rejects (37511) a second fixed-price instalment for a task that create would accept.
Use it to:
- Validate an imported payment plan line before creating it
Rules across fields:
- R1: As
POST /v1/paymentR1–R3.
Behaviour:
- Idempotent.
- Safe to retry.
- Changes are visible to the next read immediately.
Next: POST /v1/payment
curl -X POST "https://app3.timelog.com/your-account/api/v1/payment/validate-new-payment" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"Name": "John Doe",
"Comment": "example_string",
"Amount": 3.14,
"InvoiceDate": "2024-12-25T10:00:00Z",
"IsReadyForInvoicing": true,
"ProjectID": 123,
"TaskID": 123,
"ProductNumber": "example_string",
"DiscountPercentage": 3.14,
"ProjectSubContractID": 123,
"Quantity": 3.14,
"IsFixedPricePayment": true,
"UnitType": 42
}'
import requests
import json
url = "https://app3.timelog.com/your-account/api/v1/payment/validate-new-payment"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"Name": "John Doe",
"Comment": "example_string",
"Amount": 3.14,
"InvoiceDate": "2024-12-25T10:00:00Z",
"IsReadyForInvoicing": true,
"ProjectID": 123,
"TaskID": 123,
"ProductNumber": "example_string",
"DiscountPercentage": 3.14,
"ProjectSubContractID": 123,
"Quantity": 3.14,
"IsFixedPricePayment": true,
"UnitType": 42
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://app3.timelog.com/your-account/api/v1/payment/validate-new-payment", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"Name": "John Doe",
"Comment": "example_string",
"Amount": 3.14,
"InvoiceDate": "2024-12-25T10:00:00Z",
"IsReadyForInvoicing": true,
"ProjectID": 123,
"TaskID": 123,
"ProductNumber": "example_string",
"DiscountPercentage": 3.14,
"ProjectSubContractID": 123,
"Quantity": 3.14,
"IsFixedPricePayment": true,
"UnitType": 42
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"Name": "John Doe",
"Comment": "example_string",
"Amount": 3.14,
"InvoiceDate": "2024-12-25T10:00:00Z",
"IsReadyForInvoicing": true,
"ProjectID": 123,
"TaskID": 123,
"ProductNumber": "example_string",
"DiscountPercentage": 3.14,
"ProjectSubContractID": 123,
"Quantity": 3.14,
"IsFixedPricePayment": true,
"UnitType": 42
}`)
req, err := http.NewRequest("POST", "https://app3.timelog.com/your-account/api/v1/payment/validate-new-payment", 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/payment/validate-new-payment')
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 = '{
"Name": "John Doe",
"Comment": "example_string",
"Amount": 3.14,
"InvoiceDate": "2024-12-25T10:00:00Z",
"IsReadyForInvoicing": true,
"ProjectID": 123,
"TaskID": 123,
"ProductNumber": "example_string",
"DiscountPercentage": 3.14,
"ProjectSubContractID": 123,
"Quantity": 3.14,
"IsFixedPricePayment": true,
"UnitType": 42
}'
response = http.request(request)
puts response.body
"null"
{
"Code": 200,
"Message": "Invalid model state error.",
"Details": [
"…"
],
"Parameters": "…",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/payment/validate-new-payment"
}
{
"Message": "Authorization has been denied for this request."
}
{
"Code": 103,
"Message": "…",
"Details": [],
"Parameters": "…",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/payment/validate-new-payment"
}
{
"Code": 100,
"Message": "Unknown error occur in system, please contact system administrator.",
"Details": [],
"Parameters": "…",
"Url": "https://app{server-number}.timelog.com/{account}/api/v1/payment/validate-new-payment"
}
/v1/payment/validate-new-payment
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.
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.The media type of the request body
Instalment name.
Free-text comment.
Instalment amount, in the project currency. Unit: project currency
Date the instalment is due for invoicing.
Release the instalment for invoicing immediately.
The project. Must exist (37014) and be accessible to the caller (403).
Refers to ProjectRead.ProjectID. Look up valid values with GET /v1/project/get-all.
Valid values come from GET /v1/project/get-all.
Task to link the instalment to; only allowed (non-zero) on a task-driven-revenue contract, and the task must be on that contract (37949). 0 = none.
Conditional. Must be 0 unless the contract is TaskDrivenRevenue (400 "TaskID can only be added when importing on a Task Driven Revenue Contract.").
Refers to TaskRead.TaskID.
Product number TEXT (not an ID). Only used when the InvoiceSetting_ProductNoActive feature is on: a supplied value must exist in the project's legal entity (37939); empty = the default product number for payments (fixed-price contracts: the project's fixed-price product number).
Refers to ProductNumberRead.ProductNumber.
- Feature InvoiceSetting_ProductNoActive is off — Stored as empty.
- Empty and feature on — defaulted
Discount in percent. Unit: percent
The contract. Must belong to ProjectID (37042, raised inside model validation) and be FixedPriceBasic, TimeMaterialAccountEndBalancing, PrepaidServices or TaskDrivenRevenue (400 "The selected contract does not support import of payment.").
Refers to ContractRead.ProjectSubContractID.
Quantity in UnitType units. Unit: UnitType
Make this the fixed-price instalment of TaskID. Only allowed on a task-driven-revenue contract (400 otherwise). Conditional. Must be false unless the contract is TaskDrivenRevenue.
Unit of Quantity.
- Value not in the enum (e.g. 5) — 400.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
| 0 | Undefined | No unit. |
| 1 | Hours | Hours. |
| 2 | Minutes | Minutes. |
| 3 | Days | Days. |
| 4 | Km | Kilometres. |
| 6 | Pieces | Pieces. |
| 7 | Liters | Litres. |
| 8 | Meters | Metres. |
| 9 | Kilograms | Kilograms. |
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.
Body
Instalment name.
Free-text comment.
Instalment amount, in the project currency.
Unit: project currency
Date the instalment is due for invoicing.
Release the instalment for invoicing immediately.
The project. Must exist (37014) and be accessible to the caller (403).
Refers to ProjectRead.ProjectID. Look up valid values with GET /v1/project/get-all.
Valid values come from GET /v1/project/get-all.
Task to link the instalment to; only allowed (non-zero) on a task-driven-revenue contract, and the task must be on that contract (37949). 0 = none.
Conditional. Must be 0 unless the contract is TaskDrivenRevenue (400 "TaskID can only be added when importing on a Task Driven Revenue Contract.").
Refers to TaskRead.TaskID.
Product number TEXT (not an ID). Only used when the InvoiceSetting_ProductNoActive feature is on: a supplied value must exist in the project's legal entity (37939); empty = the default product number for payments (fixed-price contracts: the project's fixed-price product number).
Refers to ProductNumberRead.ProductNumber.
-
Feature InvoiceSetting_ProductNoActive is off — Stored as empty.
-
Empty and feature on — defaulted
Discount in percent.
Unit: percent
The contract. Must belong to ProjectID (37042, raised inside model validation) and be FixedPriceBasic, TimeMaterialAccountEndBalancing, PrepaidServices or TaskDrivenRevenue (400 "The selected contract does not support import of payment.").
Refers to ContractRead.ProjectSubContractID.
Quantity in UnitType units.
Unit: UnitType
Make this the fixed-price instalment of TaskID. Only allowed on a task-driven-revenue contract (400 otherwise).
Conditional. Must be false unless the contract is TaskDrivenRevenue.
Unit of Quantity.
- Value not in the enum (e.g. 5) — 400.
Allowed values:
| Value | Name | Meaning |
|---|---|---|
0 | Undefined | No unit. |
1 | Hours | Hours. |
2 | Minutes | Minutes. |
3 | Days | Days. |
4 | Km | Kilometres. |
6 | Pieces | Pieces. |
7 | Liters | Litres. |
8 | Meters | Metres. |
9 | Kilograms | Kilograms. |
012346789Responses
Success without content: HTTP 200 with the literal JSON body null. Literal JSON null.