Cash flow report
Shows money in and money out over a date range, split into operating income and expenses, other income and expenses, and other items, ending with the cash the properties started and finished the period with. One row is one chart of account, nested under its parent account.
Authorization
AuthorizationstringrequiredQuery parameters
dateRange.startstring · daterequiredFirst day of the period. Read in the company's timezone.
dateRange.endstring · daterequiredLast day of the period, included in the range.
groupByenum<string>What each money column stands for: one column for everything, one per property, one per portfolio, or one per calendar month, quarter or year in the range.
portfolioIdsstring[]Narrow the report to these portfolios. Repeat the parameter once per id. An id that does not exist returns 404.
propertyIdsstring[]Narrow the report to these properties. Repeat the parameter once per id. An id that does not exist returns 404.
ownerIdsstring[]Narrow the report to properties these owners have a stake in. Repeat the parameter once per id. An id that does not exist returns 404.
companyBillsbooleanFilter on who pays. Leave it out to include everything, set it true for bills the management company pays, false for bills the owner pays.
accountingBasisenum<string>Whether to count money when it moves (cash) or when it is earned or owed (accrual).
Response
200 · The cash flow figures.
groupHeadersobject[]The money columns, in order.
incomeobject[]Operating income accounts.
incomeTotalobjectTotal operating income per column.
expensesobject[]Operating expense accounts.
expensesTotalobjectTotal operating expenses per column.
otherIncomeobject[]Non-operating income accounts.
otherIncomeTotalobjectTotal non-operating income per column.
otherExpensesobject[]Non-operating expense accounts.
otherExpensesTotalobjectTotal non-operating expenses per column.
netOperatingIncomeobjectOperating income minus operating expenses, per column.
netOtherIncomeobjectNon-operating income minus non-operating expenses, per column.
netIncomeobjectNet operating income plus net other income, per column.
otherItemsobject[]Cash movements that are neither income nor expense, such as owner contributions and distributions.
netOtherItemsobjectTotal of those other items, per column.
cashFlowobjectNet income plus net other items, per column. This is the change in cash.
beginningCashobjectCash held at the start of each column's period.
endingCashobjectCash held at the end of each column's period.
401 · The access token is missing, expired, or not valid for this company.
404 · A portfolio, property or owner id in the query does not exist in the caller's company.
portfolioIds, propertyIds and ownerIds are all resolved down to one set of properties, and they narrow each other rather than adding up. Sending a portfolio and a property that is not in it returns nothing. Sending none of the three covers every property in the company.
This report is a table with a variable number of money columns. groupHeaders names them, in order: each has an id and a name. Every amount in the report is then an object keyed by those ids, not an array.
So to render the table, read groupHeaders for the column order, then for each line read line.groups[header.id].
What the id actually looks like depends on groupBy:
groupBy | Column id | Column name |
|---|---|---|
total | total | Total |
property | The property's Snowflake id, or unknown | The property's display name, or Unknown property |
portfolio | The portfolio's Snowflake id, or unknown | The portfolio's name, or Unknown Portfolio |
month | yyyy-MM, for example 2026-03 | March 2026 |
quarter | Year and quarter number, for example 2026-1 | Q1 2026 |
year | The year, for example 2026 | 2026 |
With groupBy=quarter the id is 2026-1, while the heading reads Q1 2026. Key your lookups off id, never off name.
{
"groupHeaders": [
{ "id": "2026-1", "name": "Q1 2026" },
{ "id": "2026-2", "name": "Q2 2026" }
],
"income": [
{
"name": "Rent income",
"children": [],
"groups": { "2026-1": 55500.00, "2026-2": 56200.00 }
}
]
}Unlike most reports here, dateRange has no default on this endpoint. Leaving it out is a validation error.