Appearance
Reports
GET /v3/company/{realmId}/reports/{reportName} serves five QuickBooks Online–compatible reports straight out of QuickBooks Desktop's own report engine. One call is one qbXML round trip; the response is QBO's Header / Columns / Rows shape, so existing QBO report code keeps working.
Report names match case-insensitively, and the response echoes QBO's exact casing back in Header.ReportName.
Supported reports
| Report | qbXML request | Desktop report type |
|---|---|---|
ProfitAndLoss | GeneralSummaryReportQueryRq | ProfitAndLossStandard |
BalanceSheet | GeneralSummaryReportQueryRq | BalanceSheetStandard |
TrialBalance | GeneralSummaryReportQueryRq | TrialBalance |
AgedReceivables | AgingReportQueryRq | ARAgingSummary |
AgedPayables | AgingReportQueryRq | APAgingSummary |
Any other QBO report name — CashFlow, the detail variants, the aging-detail variants — returns REPORT_UNKNOWN with the five supported names in the fault detail.
Parameters
| Parameter | Reports | Notes |
|---|---|---|
start_date, end_date | ProfitAndLoss, BalanceSheet, TrialBalance | ISO YYYY-MM-DD. Must be sent together. |
report_date | AgedReceivables, AgedPayables | Single as-of date — aging reports are not a range. |
date_macro | all five | QBO date macros (This Fiscal Year-to-date, Last Month, …). Fiscal-relative on both sides, so they map 1:1. |
accounting_method | ProfitAndLoss, BalanceSheet, TrialBalance | Cash or Accrual → Desktop's ReportBasis. |
summarize_column_by | all five | Only Total is accepted in v1. |
minorversion | all five | Accepted and ignored, as everywhere else in TenkeyBridge. |
If you send no dates at all you get fiscal year-to-date — the same window QuickBooks Online returns for a dateless call. This is deliberate: Desktop's own bare default is month-to-date, so TenkeyBridge always sends an explicit period rather than let the two platforms silently disagree about what "no dates" means. An undated aging report defaults to today, again matching QBO.
Example
bash
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.tenkeybridge.com/v3/company/$REALM/reports/ProfitAndLoss?start_date=2026-01-01&end_date=2026-12-31"json
{
"Header": {
"Time": "2026-07-30T12:00:00-07:00",
"ReportName": "ProfitAndLoss",
"ReportBasis": "Accrual",
"StartPeriod": "2026-01-01",
"EndPeriod": "2026-12-31",
"SummarizeColumnsBy": "Total",
"Currency": "USD",
"Option": [{ "Name": "NoReportData", "Value": "false" }]
},
"Columns": {
"Column": [
{ "ColTitle": "", "ColType": "Account" },
{ "ColTitle": "Jan - Dec 26", "ColType": "Money" }
]
},
"Rows": {
"Row": [
{
"Header": { "ColData": [{ "value": "Income" }, { "value": "" }] },
"Rows": {
"Row": [
{
"Header": { "ColData": [{ "value": "40100 · Construction Income" }, { "value": "" }] },
"Rows": {
"Row": [
{ "ColData": [{ "value": "40110 · Design Income" }, { "value": "36669.25" }], "type": "Data" }
]
},
"Summary": { "ColData": [{ "value": "Total 40100 · Construction Income" }, { "value": "418731.65" }] },
"type": "Section"
}
]
},
"Summary": { "ColData": [{ "value": "Total Income" }, { "value": "425136.05" }] },
"type": "Section",
"group": "Income"
},
{ "Summary": { "ColData": [{ "value": "Net Income" }, { "value": "127673.01" }] }, "type": "Section", "group": "NetIncome" }
]
}
}(Trimmed — the real Rock Castle response is 8 root rows.)
Reading the row tree
qbXML hands back a flat stream of rows; QBO wants a tree. TenkeyBridge rebuilds it:
- A
Sectionhas aHeader(the section's name), nestedRows, and aSummary(its subtotal line). - A summary-only
Section—Summarywith noHeaderand noRows— is a computed line likeGross Profit,Net Income, or a report's grandTOTAL. QBO emits these the same way. - A data row carries
ColDataonly. Rows at the top level have notype; nested rows carry"type": "Data". That asymmetry is QBO's, and it is reproduced verbatim. - Cells are always padded to the full column count, so
ColData[n]always lines up withColumns.Column[n]. A cell Desktop had no value for is{"value": ""}.
Honest boundaries
- Values are Desktop's, verbatim. No rounding, no recomputation, no client-side arithmetic. If Desktop says
127673.01, the API says127673.01. - Column titles are Desktop's, verbatim. Desktop's aging buckets read
Current,1 - 30,31 - 60,61 - 90,> 90,TOTALwhere QBO writes91 and overandTotal; a period column readsJan - Dec 26where QBO writesTotal. Aging buckets must stay Desktop's — a company file can be configured with entirely different buckets, so printing QBO's labels over them would be a lie — and the same rule is applied to every column for consistency. QBO'sMetaData.ColKeyhas no Desktop equivalent and is not invented. - Aging buckets are company-file configuration, not request parameters.
aging_period,num_periods, andaging_methodall fault withREPORT_UNSUPPORTED_OPTION. Change them in QuickBooks under Edit > Preferences > Reports & Graphs; whatever the file is configured with comes back as the report's columns. accounting_methodis rejected on the aging reports. qbXML'sAgingReportQueryRqhas noReportBasiselement, so there is no honest way to produce a cash-basis aging report.- Key on section header text, not on
group.groupis emitted only where the section name confidently maps to a QBO group (Income,COGS,Expenses,TotalAssets,GrandTotal, …). Desktop-specific sections — anything named after a numbered account, for instance — carry nogroupat all, exactly as QBO omits it for sections it does not recognise. Header.Optioncarries noAccountingStandard. QBO reports GAAP; Desktop never states an accounting standard, so it is omitted rather than assumed.- Column and filter customisation is v2.
columns,customer,vendor,item,class,department,qzurl, andadjusted_gain_lossall fault loudly. Fetch the standard report and narrow it client-side. - Report calls are not batchable. A
Reportsitem inside a batch envelope faults per-item pointing back at this endpoint — reports are a platform surface, not an entity, so the batch envelope has nothing to execute.
See also
- Compatibility matrix — Reports
REPORT_UNKNOWN·REPORT_UNSUPPORTED_OPTION·REPORT_INVALID_DATE- Batch operations — and why report calls stay out of the envelope