Profitability Report
The Profitability Report returns revenue, cost, profit and return-on-cost for a timeframe, grouped by project, client, team member or task. Results are ranked by total_profit descending.
The profitability result object
| Attribute | Type | Description |
|---|---|---|
project_id |
integer | The ID of the project. Returned in the project grouping. |
project_name |
string | The name of the project. Returned in the project grouping. Includes the project code. |
client_id |
integer | The ID of the client. Returned in the project and client groupings. |
client_name |
string | The name of the client. Returned in the project and client groupings. |
project_type |
string | The project’s type: fixed_fee, time_and_materials, or non_billable. Returned in the project grouping. |
user_id |
integer | The ID of the user. Returned in the team grouping. |
user_name |
string | The name of the user. Returned in the team grouping. |
task_id |
integer | The ID of the task. Returned in the task grouping. |
task_name |
string | The name of the task. Returned in the task grouping. |
is_active |
boolean | Whether the subject had activity in the timeframe. For a client, this is the client’s own activity or that of a contributing fixed-fee project. |
currency |
string | The company’s ISO 4217 currency code. It applies to revenue, not to cost. |
missing_rates |
boolean | Whether a billable rate, a cost rate or a fixed-fee fee is missing. |
missing_dates |
boolean | Whether a fixed-fee project lacks a start or end date. Returned in every grouping; false where it does not apply. |
total_revenue |
decimal | Billable time and expenses, plus attributable fixed-fee revenue, in currency. The task grouping omits expenses. |
total_cost |
decimal | Time, expense and fixed-fee cost. Not limited to currency. |
total_profit |
decimal | Revenue minus cost. May mix currencies. |
invoiced_revenue |
decimal | Invoiced revenue. The task grouping omits expense revenue. |
uninvoiced_revenue |
decimal | Uninvoiced revenue, including fixed-fee revenue. The task grouping omits expense revenue. |
return_on_cost |
integer | Return on cost as a whole percentage: round(total_profit / total_cost * 100). It is null when cost is zero and profit is non-zero, and 0 when both are zero. |
return_on_cost_unbounded |
string | positive or negative when return_on_cost is null; otherwise null. |
Required permissions
The profitability report must be enabled for the account. Results are limited to the projects the calling user can see, and the filters do not widen that scope.
Profitability Report
Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes
Harvest-Api-Stability: beta.
GET /v2/reports/profitability
| Parameter | Type | Description |
|---|---|---|
from |
date | Required. Inclusive first day of the timeframe. |
to |
date | Required. Inclusive last day of the timeframe. The timeframe cannot exceed 365 days. |
group_by |
string | The grouping for the results: project, client, team, or task. When absent, it defaults to team if project_id is given, to project if client_id is given, and otherwise to client. |
client_id |
integer | Only report on the given client and its projects. |
project_id |
integer | Only report on the given project. |
page |
integer | The page number to use in pagination. (Default: 1) |
per_page |
integer | The number of records to return per page. Can range between 1 and 2000. (Default: 2000) |
A query parameter the report does not support is refused rather than ignored.
Example Request:
curl "https://api.harvestapp.com/v2/reports/profitability?from=2026-09-01&to=2026-09-30&group_by=project" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "User-Agent: MyApp ([email protected])"
Example Response:
{
"group_by": "project",
"results": [
{
"project_id": 14307913,
"project_name": "[MW] Marketing Website",
"client_id": 5735774,
"client_name": "ABC Corp",
"project_type": "time_and_materials",
"is_active": true,
"currency": "USD",
"missing_rates": false,
"missing_dates": false,
"total_revenue": 1250.0,
"total_cost": 800.0,
"total_profit": 450.0,
"invoiced_revenue": 500.0,
"uninvoiced_revenue": 750.0,
"return_on_cost": 56,
"return_on_cost_unbounded": null
}
],
"per_page": 2000,
"total_pages": 1,
"total_entries": 1,
"next_page": null,
"previous_page": null,
"page": 1,
"links": {
"first": "https://api.harvestapp.com/v2/reports/profitability?from=2026-09-01&group_by=project&page=1&per_page=2000&to=2026-09-30",
"next": null,
"previous": null,
"last": "https://api.harvestapp.com/v2/reports/profitability?from=2026-09-01&group_by=project&page=1&per_page=2000&to=2026-09-30"
}
}Errors
| Status | When |
|---|---|
400 |
The User-Agent header is missing: User-Agent header required. |
400 |
A date is missing or invalid, the range is reversed or exceeds 365 days, or a grouping, ID, page bound or unsupported query parameter is invalid. Messages include Cannot complete your request. Parameter is missing or the value is empty: from, Invalid from date provided: "nope", Invalid timeframe: from must not be later than to, Invalid timeframe: must not exceed 1 year, Invalid group_by provided: "clients", Invalid client_id integer provided: "one", Invalid page parameter: must be greater than 0, Invalid per_page parameter: must be from 1 to 2000, and Invalid <param>[, <param>…] parameter: not supported by this endpoint. |
401 |
Authentication failed: Authentication failed for API request. |
403 |
The profitability report is not enabled for the account: Profitability report is not enabled for this account. |
403 |
The caller does not have permission to read the report: Not authorized!. |
403 |
The account is inactive: Account inactive. |
406 |
The Accept header disallows JSON. |
422 |
The cursor parameter is malformed. |
500 |
An unexpected failure. |