curl --request GET \
--url https://api.getbreezyapp.com/v1/reports/job-profitability \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.getbreezyapp.com/v1/reports/job-profitability"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.getbreezyapp.com/v1/reports/job-profitability', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"period_start": "2026-08-01",
"period_end": "2026-09-01",
"currency": "USD",
"group": null,
"job_count": 1,
"revenue_cents": 130000,
"labor_cost_cents": 6000,
"parts_cost_cents": 24000,
"equipment_cost_cents": 0,
"misc_cost_cents": 0,
"other_cost_cents": 0,
"total_cost_cents": 30000,
"gross_profit_cents": 100000,
"gross_margin": 0.7692
}
],
"pagination": {
"next_cursor": null
},
"meta": {
"request_id": "11111111-1111-4111-8111-000000009999",
"generated_at": "2026-09-08T19:00:00Z",
"timezone": "America/Los_Angeles"
},
"report": {
"start_date": "2026-08-01",
"end_date": "2026-10-01",
"bucket": "month",
"costing_enabled": true,
"verified_only": true,
"include_excluded_job_types": false,
"group_by": null
}
}{
"error": {
"code": "INVALID_REQUEST",
"message": "end_date must be later than start_date",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "A valid API key is required",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "METHOD_NOT_ALLOWED",
"message": "This resource supports GET",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "STALE_REVISION",
"message": "The visit changed; read it again before editing",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "INVALID_REQUEST",
"message": "Request body exceeds 64 KB",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Request limit exceeded",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "Unable to complete request",
"request_id": "example-request",
"details": []
}
}Summarize recorded job profitability
Enabled costing and TRACKED jobs only; defaults to VERIFIED jobs and included owned job types. Revenue is recorded OPEN/PAID/UNCOLLECTABLE pre-discount, pre-tax invoice subtotals. Whole-job date is earliest qualifying invoice issue time, then work completion, then job creation, in company timezone. One optional business grouping plus time; null business groups retained when eligible. Rows order by period_start then group value, null first. Empty buckets omitted. Margin is calculated from summed amounts, not averaged job margins.
curl --request GET \
--url https://api.getbreezyapp.com/v1/reports/job-profitability \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.getbreezyapp.com/v1/reports/job-profitability"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.getbreezyapp.com/v1/reports/job-profitability', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"period_start": "2026-08-01",
"period_end": "2026-09-01",
"currency": "USD",
"group": null,
"job_count": 1,
"revenue_cents": 130000,
"labor_cost_cents": 6000,
"parts_cost_cents": 24000,
"equipment_cost_cents": 0,
"misc_cost_cents": 0,
"other_cost_cents": 0,
"total_cost_cents": 30000,
"gross_profit_cents": 100000,
"gross_margin": 0.7692
}
],
"pagination": {
"next_cursor": null
},
"meta": {
"request_id": "11111111-1111-4111-8111-000000009999",
"generated_at": "2026-09-08T19:00:00Z",
"timezone": "America/Los_Angeles"
},
"report": {
"start_date": "2026-08-01",
"end_date": "2026-10-01",
"bucket": "month",
"costing_enabled": true,
"verified_only": true,
"include_excluded_job_types": false,
"group_by": null
}
}{
"error": {
"code": "INVALID_REQUEST",
"message": "end_date must be later than start_date",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "A valid API key is required",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "METHOD_NOT_ALLOWED",
"message": "This resource supports GET",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "STALE_REVISION",
"message": "The visit changed; read it again before editing",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "INVALID_REQUEST",
"message": "Request body exceeds 64 KB",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Request limit exceeded",
"request_id": "example-request",
"details": []
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "Unable to complete request",
"request_id": "example-request",
"details": []
}
}Authorizations
Existing Breezy API key. Grants all published reads and scheduling writes in its associated company. No app permission scopes.
Query Parameters
Maximum parent records or report rows. Complete children are always included.
1 <= x <= 100Repeat the original filters; any valid page size may continue. Foreign-company, tampered or mismatched cursors return INVALID_CURSOR.
1Inclusive company-local date.
Exclusive company-local date; must be after start_date.
day, week, month, quarter, year SERVICE, MAINTENANCE, ESTIMATE_REPAIR, ESTIMATE_REPLACE, INSTALL, WARRANTY, CALLBACK, SALES, UNKNOWN, null business_unit, job_type, job_class, null A validated assigned member. Selects distinct jobs for job financials/profitability and only that member for the participation report.
Include excluded or unavailable job-type mappings. Disabled costing and untracked jobs remain excluded.
Response
Successful read. Clients ignore unrecognized response fields.