ProjectsCreate a task on a project

Create a task on a project

Adds a root task to a project's plan and returns it.

Creates a task at the next top-level position of the project's work breakdown structure, on the contract you name (default: the project's main contract), with its budget and hourly rate; for task-driven-revenue (TDR) contracts also its payment settings. Answers 200 with the new task as TaskRead. Not idempotent and not atomic. An empty or half-filled body answers 500 Code 100 instead of a 400 field list: always send ProjectID, TaskName, StartDate, EndDate, BudgetHours, BudgetAmount and HourlyRateID.

Use it to:

  • Create the task structure of a project created from an external system (ERP / CRM project sync)
  • Add a task for a new deliverable before people register time on it

Not for:

  • A task under an existing task → POST /v1/task/create-sub-task
  • A dry run → POST /v1/task/validate-new-task

Rules across fields:

  • R1: Time & material contract: BudgetHours, BudgetAmount and HourlyRateID may not ALL be non-zero (one is derived from the other two). 400 with one message per field.
  • 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 (FixedPricePayment) PaymentProductNo, PaymentName and PaymentInvoiceDate are required (400).
  • R5: EndDate must be on or after StartDate (400).

Behaviour:

  • Not idempotent.
  • Not safe to retry blindly. Every call inserts a new task; there is no external key or dedup. After a timeout or a 500, list the project's tasks (GET /v1/task) before retrying.
  • Side effect: TDR + FixedPricePayment, or a time-and-material-basic contract: if the task then has exactly one instalment, sets its name / invoice date / product number / amount (TDR: PaymentAmount; TMB: the task budget amount) and IsReadyForInvoicing, and saves the billing plan.
  • Side effect: Re-saves the project: the project row is updated, project dates may be aligned to the task plan, invoicing potential is recalculated.
  • On failure: The task, its events and the project re-save are committed before MapTDRTaskWithPayment; a failure there answers 500 while the task stays.
  • Changes are visible to the next read immediately.

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

Next: GET /v1/task/{taskID}, POST /v1/task/create-sub-task

See also: POST /v1/task/validate-new-task

curl -X POST "https://app3.timelog.com/your-account/api/v1/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"
}'
{
  "Properties": {
    "TaskID": 123,
    "ID": "123e4567-e89b-12d3-a456-426614174000",
    "Name": "John Doe",
    "No": "example_string",
    "IsFixedPrice": true,
    "IsDefaultBillable": true,
    "AdditionalTextIsRequired": true,
    "ParentFullName": "John Doe",
    "ProjectID": 123,
    "Project": {
      "ProjectID": 123,
      "ID": "123e4567-e89b-12d3-a456-426614174000",
      "Name": "John Doe",
      "No": "example_string",
      "ExpenseIsBillable": "null",
      "CustomerID": 123,
      "Customer": {
        "CustomerID": 123,
        "ID": "123e4567-e89b-12d3-a456-426614174000",
        "Name": "John Doe",
        "No": "example_string",
        "DefaultMileageDistance": 25,
        "CustomerStatusID": 123,
        "VATNo": "example_string",
        "OrganizationNo": "example_string"
      },
      "MainContractId": 123
    },
    "ParentTaskID": "null",
    "IsTravelTimeTask": true,
    "IsFavourite": "null"
  },
  "Links": [
    {
      "Href": "example_string",
      "Rel": "example_string"
    }
  ],
  "Actions": [
    {}
  ]
}
POST
/v1/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.

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.
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.

Min length: 1
TaskNostringnull

The task number shown next to the name (searchable by the time-tracking searches). Copied as sent when the account's task number series is off. When the task number series is on, the number you send is overwritten with the next number from the series (except on template projects).

Descriptionstringnull

Free-text description of the task.

StartDatestring
Required

Planned start of the task. - Omitted (0001-01-01) — 400 'StartDate is not a valid date.'

Format: date-time
EndDatestring
Required

Planned end of the task. - 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.

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.').

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.

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).

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. - Feature LockPaymentDateToFPTTaskDate on — On later task saves the instalment's invoice date is re-synced to the task's EndDate.

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.

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.

TaskNostring,null

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

Copied as sent when the account's task number series is off. When the task number series is on, the number you send is overwritten with the next number from the series (except on template projects).

Descriptionstring,null

Free-text description of the task.

StartDatestring
Required

Planned start of the task.

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

Planned end of the task.

  • 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.

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.').

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.

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).
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.

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

Responses

Propertiesobject

A short task representation for time-tracking pickers: the task's IDs, name and number, its parent, its project, and three flags that change how a registration on it behaves (fixed price, default billable, additional text required). It is not the full task (no dates, budget, status or contract). The TAF self link points to GET /v1/task/{TaskID}; entities also carry TAF actions (add-registration, start-time-tracker and, depending on the operation, create-task / create-sub-task / validate-new-task) describing other POST operations.

Linksarray
Actionsobject[]