ProjectsValidate a new task (dry run)

Validate a new task (dry run)

Checks whether a root task with this body could be created on the project, without creating it.

Same body as POST /v1/task. Runs the body rules, the project / contract / hourly-rate / TDR product-number checks and the task save rules (contract valid for the project, hourly rate on the contract, parent may take sub-tasks), then answers 200 with null. It writes nothing.

Use it to:

  • Pre-check a task import row before calling POST /v1/task

Not for:

  • Validating a sub-task placement — not supported

Rules across fields:

  • R1: Time & material contract: BudgetHours, BudgetAmount and HourlyRateID may not ALL be non-zero (400).
  • R2: TDR contract: BudgetHours, BudgetAmount and TaskHourlyRate may not ALL be non-zero (400).
  • R3: TDR contract: TaskHourlyRate must be 0 when HourlyRateID is not 0 (400).
  • R4: TDR contract: PaymentRecognitionModel must be 1 or 2; with 2, PaymentProductNo, PaymentName and PaymentInvoiceDate are required (400).
  • R5: EndDate must be on or after StartDate (400).

Behaviour:

  • Idempotent.
  • Safe to retry.
  • Changes are visible to the next read immediately.

Call first: GET /v1/project/get-all, GET /v1/contract

Next: POST /v1/task

See also: POST /v1/task/create-sub-task

Not yet documented: examples.

curl -X POST "https://app3.timelog.com/your-account/api/v1/task/validate-new-task" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "ProjectID": 123,
  "ParentTaskID": "null",
  "TaskName": "John Doe",
  "TaskNo": "null",
  "Description": "null",
  "StartDate": "2024-12-25T10:00:00Z",
  "EndDate": "2024-12-25T10:00:00Z",
  "AdditionalTextIsRequired": true,
  "IsBillable": true,
  "IsReadyForInvoicing": true,
  "ProjectSubContractID": "null",
  "HourlyRateID": 123,
  "BudgetHours": 3.14,
  "BudgetAmount": 3.14,
  "TaskTypeID": "null",
  "PaymentRecognitionModel": 42,
  "PaymentAmount": 3.14,
  "TaskHourlyRate": 3.14,
  "PaymentProductNo": "null",
  "PaymentName": "null",
  "PaymentInvoiceDate": "null"
}'
"null"
POST
/v1/task/validate-new-task
POST
Base URLstring

Target server for requests. Edit to use your own host.

Bearer Token
Bearer Tokenstring
Required

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.

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.
Content-Typestring
Required

The media type of the request body

Options: application/json
ProjectIDinteger
Required

The project the task is created on. Can be set on create only. Refers to ProjectRead.ProjectID. Look up valid values with GET /v1/project/get-all. - 0 or omitted — Should be 400 'Project ID must be greater than 0', but the validator's contract rules crash first: 500 Code 100. - Unknown ID — 500 Code 102 / 37014 (rest.projectmanagement.project-not-found) — or 500 Code 100 when the validator's contract lookup runs first. Valid values come from GET /v1/project/get-all.

Format: int32
ParentTaskIDintegernull

The existing task the new task is placed under (create-sub-task only). Can be set on create only. Refers to TaskRead.TaskID. Look up valid values with GET /v1/task. - Sent as 0 or negative — 400 (must be > 0 when present). - create-sub-task: the task is on ANOTHER project — The parent is re-resolved by its WBS number inside ProjectID: the sub-task lands under the task of ProjectID that has the same WBS number, or the call fails with 500. - create-sub-task: null — Treated as task 0: 500 rest.projectmanagement.task-not-found (37001). Valid values come from GET /v1/task.

Format: int32
TaskNamestring
Required

Display name of the task. > Not yet documented: constraints → max length.

Min length: 1
TaskNostringnull

The task number shown next to the name (searchable by the time-tracking searches). Copied as sent. > Not yet documented: notes.

Descriptionstringnull

Free-text description of the task.

StartDatestring
Required

Planned start of the task. Time zone: not yet documented. - Omitted (0001-01-01) — 400 'StartDate is not a valid date.' > Not yet documented: constraints → timezone.

Format: date-time
EndDatestring
Required

Planned end of the task. Time zone: not yet documented. - Omitted (0001-01-01) — 400 with the message 'StartDate is not a valid date.'. - Before StartDate — 400 'EndDate must be equal to or greater than StartDate.' - Time-and-material basic contract — Becomes the invoice date of the task's instalment. > Not yet documented: constraints → timezone.

Format: date-time
AdditionalTextIsRequiredboolean

When true, time registrations on this task must carry an additional comment.

IsBillableboolean

Default billable flag of time registered on the task. Omitted = false (non-billable task). Read back as TaskRead.IsDefaultBillable.

IsReadyForInvoicingboolean

Marks the task (and, for TDR fixed-price-payment / time-and-material-basic tasks, its instalment) ready for invoicing.

ProjectSubContractIDintegernull

The contract of the project the task is invoiced on. Refers to ContractRead.ContractID. Look up valid values with GET /v1/contract. - Omitted / null on POST /v1/task and validate-new-task — The project's main contract. - Omitted / null on create-sub-task — The parent task's contract. - 0 or negative — 400 (must be > 0 when present). - Not a contract of ProjectID — 500 Code 102 / 37042 (rest.projectmanagement.task-contract-not-on-project). Valid values come from GET /v1/contract.

Format: int32
HourlyRateIDinteger
Required

The contract hourly rate used for the task; 0 = the employee's default hourly rate. Refers to ContractHourlyRateID. - Null / omitted — Required (NotNull) — but an empty body fails earlier with 500 Code 100. - > 0 and not a rate of the contract — 500 Code 102 / 37944 or 37043 (rest.projectmanagement.task-hourly-rate-not-on-contract). - > 0, fixed-price contract on a project with hourly-rate model Calculated — Set to 0; the task's hourly rate is derived instead (TDR: TaskHourlyRate; other fixed price: the contract's target hourly rate). - TDR contract and HourlyRateID != 0 — TaskHourlyRate must then be 0 (400 'Hourly rate must be 0 when HourlyRateID is selected.'). > Not yet documented: values → lookup op.

Format: int32
BudgetHoursnumber
Required

Budgeted hours of the task. Unit: hours - Null / omitted — Required (NotNull, >= 0) — an empty body fails earlier with 500 Code 100. - Time & material contract, BudgetAmount and HourlyRateID also non-zero — 400: only two of BudgetHours, BudgetAmount, HourlyRateID may be non-zero. - HourlyRateID > 0 and BudgetHours = 0 — Derived: BudgetAmount / the rate's amount, rounded to InvoiceSetting_NumberOfDecimals. - TDR on a Calculated-rate project and BudgetHours = 0 — Derived: BudgetAmount / TaskHourlyRate (1 when the rate is 0).

Format: double
BudgetAmountnumber
Required

Budgeted revenue of the task. Unit: project currency - Null / omitted — Required (NotNull, >= 0) — an empty body fails earlier with 500 Code 100. - HourlyRateID > 0 and BudgetAmount = 0 — Derived: BudgetHours x the rate's amount. - TDR contract — Stored as the budget; the task's allocated revenue is PaymentAmount instead. - Otherwise — Also becomes the task's allocated revenue amount.

Format: double
TaskTypeIDintegernull

The task type (classification) of the task. Refers to TaskTypeRead.TaskTypeID. - 0 or negative — 400 (must be > 0 when present). - Unknown ID (create only) — 500 Code 102 / 37010 (rest.projectmanagement.task-type-not-found). validate-new-task does not check it. - Null — Stored as 0 (no task type). The account's 'task type required' setting is deliberately not enforced by the save rules. > Not yet documented: values → lookup op.

Format: int32
PaymentRecognitionModelinteger

How a task-driven-revenue (TDR) task recognises revenue. Conditional. Required (1 or 2) when the task's contract is TDR; ignored and reset to 0 otherwise. Allowed values: | Value | Name | Meaning | |---|---|---| | 0 | Undefined | Not a TDR task. Rejected (400) on a TDR contract. | | 1 | OverallPaymentPlan | Revenue follows the contract's overall payment plan; no instalment of its own. | | 2 | FixedPricePayment | The task has its own fixed-price instalment: PaymentAmount, PaymentProductNo, PaymentName and PaymentInvoiceDate become required and are written to it. |

Format: int32 • Options: 0, 1, 2
PaymentAmountnumber

TDR only — the task's allocated revenue, and with FixedPricePayment the amount of its instalment. Conditional. TDR contract: >= 0 (0 when omitted). Ignored otherwise. Can be set on create only. Unit: project currency - TDR contract — Becomes the task's allocated revenue amount (replaces BudgetAmount for that). - TDR + FixedPricePayment and the task has exactly one instalment after the save — Written as that instalment's Rate and Amount.

Format: double
TaskHourlyRatenumber

TDR only — the task's own hourly rate on a project whose hourly-rate model is Calculated. Conditional. TDR + FixedPricePayment: >= 0. Must be 0 when HourlyRateID != 0, and not all three of BudgetHours, BudgetAmount, TaskHourlyRate may be non-zero. Ignored on other contracts. Can be set on create only. Unit: project currency per hour - TDR, Calculated hourly-rate model, TaskHourlyRate = 0 — Derived: BudgetAmount / BudgetHours (1 when hours are 0). - TDR, Calculated hourly-rate model, TaskHourlyRate > 0 — Stored as the task's hourly rate; used to derive BudgetHours or BudgetAmount when one of them is 0.

Format: double
PaymentProductNostringnull

TDR fixed-price-payment only — product number of the task's instalment. Conditional. Required (non-empty) when the contract is TDR and PaymentRecognitionModel = 2; must exist in the project's legal entity whenever sent on a TDR contract. Can be set on create only. Refers to ProductNumber. - TDR contract, unknown number — 500 Code 102 / 37939 (rest.projectmanagement.task-payment-product-number-not-found). > Not yet documented: values → lookup op.

PaymentNamestringnull

TDR fixed-price-payment only — name (invoice text) of the task's instalment. Conditional. Required (non-empty) when the contract is TDR and PaymentRecognitionModel = 2. Ignored otherwise. Can be set on create only.

PaymentInvoiceDatestringnull

TDR fixed-price-payment only — invoice date of the task's instalment. Conditional. Required when the contract is TDR and PaymentRecognitionModel = 2. Ignored otherwise. Can be set on create only. Time zone: not yet documented. - Feature LockPaymentDateToFPTTaskDate on — On later task saves the instalment's invoice date is re-synced to the task's EndDate. > Not yet documented: constraints → timezone.

Format: date-time
Request Preview
Response

Response will appear here after sending the request

Authentication

header
Authorizationstring
Required

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

application/json
ProjectIDinteger
Required

The project the task is created on.

Can be set on create only.

Refers to ProjectRead.ProjectID. Look up valid values with GET /v1/project/get-all.

  • 0 or omitted — Should be 400 'Project ID must be greater than 0', but the validator's contract rules crash first: 500 Code 100.

  • Unknown ID — 500 Code 102 / 37014 (rest.projectmanagement.project-not-found) — or 500 Code 100 when the validator's contract lookup runs first.

Valid values come from GET /v1/project/get-all.

ParentTaskIDinteger,null

The existing task the new task is placed under (create-sub-task only).

Can be set on create only.

Refers to TaskRead.TaskID. Look up valid values with GET /v1/task.

  • Sent as 0 or negative — 400 (must be > 0 when present).

  • create-sub-task: the task is on ANOTHER project — The parent is re-resolved by its WBS number inside ProjectID: the sub-task lands under the task of ProjectID that has the same WBS number, or the call fails with 500.

  • create-sub-task: null — Treated as task 0: 500 rest.projectmanagement.task-not-found (37001).

Valid values come from GET /v1/task.

TaskNamestring
Required

Display name of the task.

Not yet documented: constraints → max length.

TaskNostring,null

The task number shown next to the name (searchable by the time-tracking searches).

Copied as sent.

Not yet documented: notes.

Descriptionstring,null

Free-text description of the task.

StartDatestring
Required

Planned start of the task.

Time zone: not yet documented.

  • Omitted (0001-01-01) — 400 'StartDate is not a valid date.'

Not yet documented: constraints → timezone.

EndDatestring
Required

Planned end of the task.

Time zone: not yet documented.

  • Omitted (0001-01-01) — 400 with the message 'StartDate is not a valid date.'.

  • Before StartDate — 400 'EndDate must be equal to or greater than StartDate.'

  • Time-and-material basic contract — Becomes the invoice date of the task's instalment.

Not yet documented: constraints → timezone.

AdditionalTextIsRequiredboolean

When true, time registrations on this task must carry an additional comment.

IsBillableboolean

Default billable flag of time registered on the task.

Omitted = false (non-billable task). Read back as TaskRead.IsDefaultBillable.

IsReadyForInvoicingboolean

Marks the task (and, for TDR fixed-price-payment / time-and-material-basic tasks, its instalment) ready for invoicing.

ProjectSubContractIDinteger,null

The contract of the project the task is invoiced on.

Refers to ContractRead.ContractID. Look up valid values with GET /v1/contract.

  • Omitted / null on POST /v1/task and validate-new-task — The project's main contract.

  • Omitted / null on create-sub-task — The parent task's contract.

  • 0 or negative — 400 (must be > 0 when present).

  • Not a contract of ProjectID — 500 Code 102 / 37042 (rest.projectmanagement.task-contract-not-on-project).

Valid values come from GET /v1/contract.

HourlyRateIDinteger
Required

The contract hourly rate used for the task; 0 = the employee's default hourly rate.

Refers to ContractHourlyRateID.

  • Null / omitted — Required (NotNull) — but an empty body fails earlier with 500 Code 100.

  • 0 and not a rate of the contract — 500 Code 102 / 37944 or 37043 (rest.projectmanagement.task-hourly-rate-not-on-contract).

  • 0, fixed-price contract on a project with hourly-rate model Calculated — Set to 0; the task's hourly rate is derived instead (TDR: TaskHourlyRate; other fixed price: the contract's target hourly rate).

  • TDR contract and HourlyRateID != 0 — TaskHourlyRate must then be 0 (400 'Hourly rate must be 0 when HourlyRateID is selected.').

Not yet documented: values → lookup op.

BudgetHoursnumber
Required

Budgeted hours of the task.

Unit: hours

  • Null / omitted — Required (NotNull, >= 0) — an empty body fails earlier with 500 Code 100.

  • Time & material contract, BudgetAmount and HourlyRateID also non-zero — 400: only two of BudgetHours, BudgetAmount, HourlyRateID may be non-zero.

  • HourlyRateID > 0 and BudgetHours = 0 — Derived: BudgetAmount / the rate's amount, rounded to InvoiceSetting_NumberOfDecimals.

  • TDR on a Calculated-rate project and BudgetHours = 0 — Derived: BudgetAmount / TaskHourlyRate (1 when the rate is 0).

BudgetAmountnumber
Required

Budgeted revenue of the task.

Unit: project currency

  • Null / omitted — Required (NotNull, >= 0) — an empty body fails earlier with 500 Code 100.

  • HourlyRateID > 0 and BudgetAmount = 0 — Derived: BudgetHours x the rate's amount.

  • TDR contract — Stored as the budget; the task's allocated revenue is PaymentAmount instead.

  • Otherwise — Also becomes the task's allocated revenue amount.

TaskTypeIDinteger,null

The task type (classification) of the task.

Refers to TaskTypeRead.TaskTypeID.

  • 0 or negative — 400 (must be > 0 when present).

  • Unknown ID (create only) — 500 Code 102 / 37010 (rest.projectmanagement.task-type-not-found). validate-new-task does not check it.

  • Null — Stored as 0 (no task type). The account's 'task type required' setting is deliberately not enforced by the save rules.

Not yet documented: values → lookup op.

PaymentRecognitionModelinteger

How a task-driven-revenue (TDR) task recognises revenue.

Conditional. Required (1 or 2) when the task's contract is TDR; ignored and reset to 0 otherwise.

Allowed values:

ValueNameMeaning
0UndefinedNot a TDR task. Rejected (400) on a TDR contract.
1OverallPaymentPlanRevenue follows the contract's overall payment plan; no instalment of its own.
2FixedPricePaymentThe task has its own fixed-price instalment: PaymentAmount, PaymentProductNo, PaymentName and PaymentInvoiceDate become required and are written to it.
Allowed values:012
PaymentAmountnumber

TDR only — the task's allocated revenue, and with FixedPricePayment the amount of its instalment.

Conditional. TDR contract: >= 0 (0 when omitted). Ignored otherwise.

Can be set on create only.

Unit: project currency

  • TDR contract — Becomes the task's allocated revenue amount (replaces BudgetAmount for that).

  • TDR + FixedPricePayment and the task has exactly one instalment after the save — Written as that instalment's Rate and Amount.

TaskHourlyRatenumber

TDR only — the task's own hourly rate on a project whose hourly-rate model is Calculated.

Conditional. TDR + FixedPricePayment: >= 0. Must be 0 when HourlyRateID != 0, and not all three of BudgetHours, BudgetAmount, TaskHourlyRate may be non-zero. Ignored on other contracts.

Can be set on create only.

Unit: project currency per hour

  • TDR, Calculated hourly-rate model, TaskHourlyRate = 0 — Derived: BudgetAmount / BudgetHours (1 when hours are 0).

  • TDR, Calculated hourly-rate model, TaskHourlyRate > 0 — Stored as the task's hourly rate; used to derive BudgetHours or BudgetAmount when one of them is 0.

PaymentProductNostring,null

TDR fixed-price-payment only — product number of the task's instalment.

Conditional. Required (non-empty) when the contract is TDR and PaymentRecognitionModel = 2; must exist in the project's legal entity whenever sent on a TDR contract.

Can be set on create only.

Refers to ProductNumber.

  • TDR contract, unknown number — 500 Code 102 / 37939 (rest.projectmanagement.task-payment-product-number-not-found).

Not yet documented: values → lookup op.

PaymentNamestring,null

TDR fixed-price-payment only — name (invoice text) of the task's instalment.

Conditional. Required (non-empty) when the contract is TDR and PaymentRecognitionModel = 2. Ignored otherwise.

Can be set on create only.

PaymentInvoiceDatestring,null

TDR fixed-price-payment only — invoice date of the task's instalment.

Conditional. Required when the contract is TDR and PaymentRecognitionModel = 2. Ignored otherwise.

Can be set on create only.

Time zone: not yet documented.

  • Feature LockPaymentDateToFPTTaskDate on — On later task saves the instalment's invoice date is re-synced to the task's EndDate.

Not yet documented: constraints → timezone.

Responses

Success without content: HTTP 200 with the literal JSON body null. The literal null (TafSuccessResult): the task could be built and passed the save rules.