Skip to main content

Project Profitability & Time Estimation

When creating or updating a project, the Profitability section controls how time and income are estimated. These settings are sent as part of POST /projects and PUT /projects/{project_id}.
These fields are unrelated to the Project Estimates endpoints (/projects/{project_id}/project_estimate), which manage budget line items with a title, cost, and optional fee association.

Time estimation modes

Projects support three mutually exclusive time estimation modes. Only one should be active at a time.

1. Total hours (default)

Send a single estimated_time value (in hours). Do not set estimated_by_position or estimation_by_categories.
{
  "name": "Website Redesign",
  "client_id": 10,
  "estimated_time": 120,
  "income_type": "fee",
  "fee_id": 5
}

2. Estimation by positions

Set estimated_by_position: true and provide a users_positions array where each entry contains a unified position id and its estimated_time in hours.
{
  "name": "Mobile App",
  "client_id": 10,
  "estimated_by_position": true,
  "users_positions": [
    { "id": 1, "estimated_time": 80 },
    { "id": 2, "estimated_time": 40 }
  ]
}
When estimated_by_position is false, you may still send users_positions with only the id field to associate positions to the project without per-position hour estimates.
On update (PUT), positions that exist in the project but are absent from the users_positions array will have their estimated_hours set to 0. If no hours have been logged against them, they are soft-deleted.

3. Estimation by categories

Set estimation_by_categories: 1 (or true) and provide a categories array with id and estimated_time.
{
  "name": "Brand Campaign",
  "client_id": 10,
  "estimation_by_categories": 1,
  "categories": [
    { "id": 7, "estimated_time": 60 },
    { "id": 8, "estimated_time": 30 }
  ]
}

Income types and ratecards

The income_type field determines how the project revenue is modeled:
income_typeDescription
feeRevenue tied to a fee (fee_id required)
one_timeFixed one-time revenue (estimated monetary value)
hourly_rateRevenue calculated from hourly rates via a ratecard
contractRevenue tied to a contract (contract_id required)
When using hourly_rate, set estimated_by_hourly_rates: true and assign a ratecard:
{
  "income_type": "hourly_rate",
  "estimated_by_hourly_rates": true,
  "ratecard_id": 3
}
The ratecard_id field is an alias for user_positions_header_id — either name is accepted, but ratecard_id takes precedence if both are sent. Use GET /ratecards to list available ratecards for your company.

Reading profitability data

When you fetch a single project with GET /projects/{project_id}, the response includes:
FieldTypeDescription
estimated_timenumberTotal estimated hours
estimated_by_positionbooleanWhether estimation is split per position
estimation_by_categoriesboolean/integerWhether estimation is split per category
estimated_by_hourly_ratesbooleanWhether hourly-rate income mode is active
user_positions_header_idintegerAssigned ratecard ID
usersPositionsProjectarrayPositions with estimated_hours, hours_charged, total_cost
categoriesProjectarrayCategories with estimated_hours, hours_charged, total_cost
ratecardobjectRatecard details (name, percent, currency_id, etc.)

Field reference

Request fieldTypeUsed inDescription
estimated_timenumberPOST, PUTTotal estimated hours (used when neither by-position nor by-category is active)
estimated_by_positionbooleanPOST, PUTEnable per-position time estimation
estimation_by_categoriesboolean/integerPOST, PUTEnable per-category time estimation (1 or true)
estimated_by_hourly_ratesbooleanPOST, PUTEnable hourly-rate income calculation
ratecard_idintegerPOST, PUTRatecard to assign (alias for user_positions_header_id)
users_positionsarrayPOST, PUTPositions with optional estimated_time per item
categoriesarrayPOST, PUTCategories with optional estimated_time per item
income_typestringPOST, PUTfee, one_time, hourly_rate, or contract
exchangenumberPOST, PUTExchange rate when project currency differs from base
currency_change_amountnumberPOST, PUTOriginal amount in selected currency before conversion