Skip to content
TruTecDevelopers
Get an API key

Owner reports

Run the reports from TruTec's Reports page (money owed, cash forecast, KPIs, win / loss, bid vs actual and more), read labor hours by person, day and job, and a month's revenue and direct cost per job.

View as Markdown

These are the reports an owner reads on TruTec's Reports page, built by the same code as the page, its CSV and Excel exports and the scheduled report emails. Use them to answer questions like "who owes us money and how late is it?", "what did we win this month?" or "which jobs are over budget?".

All of them are read-only and need Read jobs. They run as the user who created the API key, so they show what that person sees: their job visibility applies, and management reports need a user who may view them (owners always; members when an owner turned on Can view management reports for them in Settings › Members). Otherwise GET /v1/reports/{key} returns 403 Reports not available.

List reports#

GET /v1/reports

Permission: Read jobs

The reports this key can run, with key, title, section, description and date_basis (which date the range filters on: bid, decided, created, or all when each figure uses its own date).

Key Report
weekly-summary Every week of the year: new leads, dollars quoted, work won, invoiced and collected, with past years side by side.
week-glance One week: new leads, estimates sent, work won, change orders, invoices and payments.
receivables Money owed to you: open invoices by customer and age (current, 1–30, 31–60, 61–90, over 90 days), plus billed and collected in the range.
cash-forecast Cash likely to come in over the next weeks.
top-customers Customers ranked by work won, with bids, hit rate, billed, collected and owed.
zip-code Bids, wins and dollars by zip code and city.
bid-vs-actual Jobs with costs logged: bid cost against actual and forecast, flagged when outside tolerance.
material-usage Materials on won work, estimated against used.
completed-work Pay items marked Completed on the estimate, counted on the day they were finished: revenue (their price on the estimate), estimated cost and profit, plus what is still to do on won jobs. view groups by job (blank), worktype, division or salesperson. Needs no invoices.
bid-schedule, win-loss, win-loss-graph, work-type, market-analysis Sales.
data-dump, estimate-totals, item-history, material-history, resource-utilization Estimating.
sub-utilization, vendor-utilization, minority Subcontractors and vendors.
weekly-sales, kpi Weekly and monthly sales KPIs against the previous period, last year and goals.
lead-pipeline, brochure-scans Listed only for workspaces that use them.
labor-hours Listed when the workspace runs crews and the user has Approve payroll. See below.
month-end-job-cost Listed when the workspace runs crews and the user may see job costs (Estimating Pro and pricing access). See below.

Run a report#

GET /v1/reports/{key}

Permission: Read jobs (and the management reports permission above)

Name Type Description
start, end date The range (YYYY-MM-DD). Default 1 January this year to today. kpi, weekly-sales and week-glance cover the whole week or month containing end.
date_basis string bid, decided or created, for reports with a "Dates are" picker.
salesperson_ids, estimator_ids, customer_ids, division_ids string Comma-separated ids.
statuses, work_types, outcomes string Comma-separated pipeline stage keys, job types, and won / lost / open / excluded.
group_by string Up to 3, comma-separated: work_type, salesperson, estimator, customer, division, status, outcome, month, quarter, year, customer_type, property_type, source, zip, city.
period string week or month (KPI report).
weeks integer Cash forecast: 4, 8, 12 or 26.
net_days integer Receivables: an invoice with no due date is due this many days after it's sent (0, 15, 30, 45, 60 or 90; default 30).
q, view, columns string The page's search box, view and column picker, where the report has them.
rows_limit integer Rows per table. Default 200, maximum 2,000. rows_total says how many there were.
curl "https://trutec.ai/api/v1/reports/receivables" \
  -H "X-API-Key: sk_your_api_key_here"
{
  "data": {
    "key": "receivables",
    "title": "Money owed to you",
    "section": "Owner dashboard",
    "description": "Every open invoice, how late it is and who owes the most — plus what you billed and collected.",
    "start": "2026-01-01",
    "end": "2026-10-14",
    "date_basis": "all",
    "summary": [
      {"label": "Owed to you now", "value": "$62,410"},
      {"label": "Overdue", "value": "$18,200"}
    ],
    "tables": [
      {
        "key": "aging",
        "title": "Who owes you",
        "columns": [
          {"key": "customer", "label": "Customer", "kind": "text"},
          {"key": "count", "label": "Invoices", "kind": "int"},
          {"key": "current", "label": "Current", "kind": "money"},
          {"key": "d1_30", "label": "1-30 days", "kind": "money"},
          {"key": "total", "label": "Total owed", "kind": "money"},
          {"key": "oldest", "label": "Oldest invoice", "kind": "date"}
        ],
        "rows": [
          {"customer": "Northgate Properties", "count": 2, "current": 12125.0, "d1_30": 6075.0, "total": 18200.0, "oldest": "2026-08-29"}
        ],
        "rows_total": 1,
        "total": {"customer": "Total", "count": 2, "total": 18200.0},
        "note": null
      }
    ],
    "truncated": false
  }
}

summary values are display text ("$62,410"), as on the page. Table rows hold raw values: money and numbers as numbers, pct columns as fractions (0.25 = 25%), dates as YYYY-MM-DD. Rows about one job also carry job_id; a customer's division rows carry is_division_row: true under the customer's row. truncated is true when more than 20,000 jobs matched (narrow the range).

Labor hours#

GET /v1/reports/labor-hours

Permission: Read jobs; the workspace runs crews and the key's user has the Approve payroll permission

Payroll hours from crew clock-ins, per person, per day and job: regular, overtime and double-time, with overtime worked out per worker-week (the crew accounting Time entry report). Approved time only unless approved_only=false. start and end cover up to 93 days; with neither, this week. pay (dollars per line) is included only when the key's user may see actual pay (includes_pay).

{
  "data": {
    "start": "2026-10-05",
    "end": "2026-10-11",
    "approved_only": true,
    "includes_pay": false,
    "people": [
      {
        "user_id": 412,
        "name": "Luis Ortega",
        "total_hours": 46.5,
        "lines": [
          {"date": "2026-10-06", "job_id": 70412, "cost_code": "01-SEAL", "regular_hours": 9.5,
           "overtime_hours": 0.0, "doubletime_hours": 0.0, "total_hours": 9.5}
        ]
      }
    ],
    "totals": {"regular_hours": 40.0, "overtime_hours": 6.5, "doubletime_hours": 0.0, "total_hours": 46.5}
  }
}

job_id is null for shop or yard time. For the raw clock-ins, see Timesheets; for one job's costs and labor, see Job costing.

Month-end job cost#

GET /v1/reports/month-end-job-cost

Permission: Read jobs; the workspace runs crews and the key's user may see job costs (Estimating Pro and pricing access), as for Job Cost Out in the app

The crew accounting Month-end report: every job with revenue or direct cost in one month, with what was invoiced, the direct cost by type, gross profit and GP %, and the same job to date, plus a totals row. Use it to close the month or to reconcile against your accounting system job by job.

Name Type Description
month string YYYY-MM. Default last month.
  • Revenue is the job's invoices dated in the month (by the day each was created, in your workspace's time zone). Draft, void, uncollectible and cancelled invoices are left out; a credit is a negative invoice and nets out.
  • Direct cost is the job's Job Cost Out for the month: the same cost entries and not-yet-posted clock labor. direct_cost equals that report's period cost and cost_to_date its cost to date through the last day of the month.
  • direct_costs splits it by type: labor (labor & burden), material, trucking (truck rental), equipment, dump, subcontract (subs) and other. A cost lands by its category; an other cost on a cost code named for dumping (for example "Dump Fees") goes to dump.
  • gross_profit is revenue minus direct cost; gross_profit_pct is that over revenue as a fraction (0.2823 = 28.23%), null with no revenue.
  • contract is the revised contract (the job's value when it has no estimate). job_number is the accounting job number when one is set.
  • Up to 200 jobs, by job number; truncated is true when there were more.
curl "https://trutec.ai/api/v1/reports/month-end-job-cost?month=2026-09" \
  -H "X-API-Key: sk_your_api_key_here"
{
  "data": {
    "month": "2026-09",
    "start": "2026-09-01",
    "end": "2026-09-30",
    "cost_types": [{"key": "labor", "label": "Labor & burden"}, {"key": "material", "label": "Material"}],
    "jobs": [
      {
        "job_id": 70412, "job_number": "25995", "job_name": "Mission Plaza",
        "customer": "Northgate Properties", "customer_number": "1140", "contract": 47350.0,
        "revenue": 47350.0,
        "direct_costs": {"labor": 14743.87, "material": 15566.96, "trucking": 0.0, "equipment": 3673.0,
                         "dump": 0.0, "subcontract": 0.0, "other": 0.0},
        "direct_cost": 33983.83, "gross_profit": 13366.17, "gross_profit_pct": 0.282284,
        "revenue_to_date": 47350.0, "cost_to_date": 33983.83,
        "gross_profit_to_date": 13366.17, "gross_profit_pct_to_date": 0.282284
      }
    ],
    "totals": {"jobs": 1, "contract": 47350.0, "revenue": 47350.0, "direct_cost": 33983.83,
               "gross_profit": 13366.17, "gross_profit_pct": 0.282284},
    "truncated": false
  }
}

totals carries every money field of a job row (summed), with GP % worked out from the sums. To look at one job's cost codes for the month, export its Job Cost Out: POST /v1/exports with kind: "job_cost_out", job_id, from and to. The same report as a spreadsheet is the month_end_job_cost export.