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
Not yet documented: examples.
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"
{
"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
}
{
"error": "Forbidden",
"message": "You don't have permission to access this resource",
"code": 403
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred on the server",
"code": 500,
"requestId": "req_1234567890"
}
/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.
> 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
Instalment name.
Free-text comment.
Instalment amount, in the project currency. Unit: project currency > Not yet documented: description.
Date the instalment is due for invoicing. Time zone: not yet documented. > Not yet documented: constraints → timezone.
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.
Not yet documented: how to obtain a token.
Not yet documented: token lifetime.
Body
Instalment name.
Free-text comment.
Instalment amount, in the project currency.
Unit: project currency
Not yet documented: description.
Date the instalment is due for invoicing.
Time zone: not yet documented.
Not yet documented: constraints → timezone.
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.