Overview

A cash flow report shows how cash has flowed in and out of the business and is a powerful way to transform a linear list of bank transactions into a view of the health and liquidity of a business. It takes transaction data you already have and presents it in a structured format that helps small business owners figure out how much money they have and how they spend their money.

An effective cash flow report interface should provide:

  • The starting balance for the time period.
  • A list of the categories of income and expenses that have affected the balance.
  • An ending balance for the time period.

How it works

Teal’s simplified cash flow report shows where cash began, what ledgers caused the cash balance to change, and then reports where cash ended. To do this, we have to identify which ledgers to track cash flow movements in.

When you create a new financial account ledger for an account that holds funds, such as a bank or credit card, you can enable the report_cash_flow parameter. This will cause the ledger to be included in the cash flow report calculation.

Generally, all accounts that hold funds, such as bank accounts and credit cards, should be the only accounts included in the cash flow report. If you want to create an advanced cash flow report, you can include loans and investments, but we only recommend this if your users are looking for a specific circumstance.

Teal will automatically tabulate movements of cash in and out of report_cash_flow enabled accounts to produce a cash flow report. Movements of cash between report_cash_flow enabled accounts are not reported, as they are movements of cash within the business rather than into or out of the business.


Build a cash flow report

Prerequisites

The user must have at least one report_cash_flow enabled account. See the creating ledgers guide for more info.


1. Make the request

Use the /v0/reports/cash-flow to get the cash flow report data.

const CashFlow = () => {
    const options = {
        method: 'GET',
        headers: {
            Authorization: AUTHORIZATION_KEY,
            'teal-instance-id': TEAL_INSTANCE_ID
        }
    }

    const cashFlowRequest = await fetch(
        'https://api.sandbox.teal.dev/v0/reports/cash-flow', 
        options
    );

    const cashFlowData: CashFlowReport = await request.json();

    return (
        // ...
    )
}

export default CashFlow;


2. Display the starting and ending balances

To start, display the starting balance and its breakdown by ledger included in the report. The starting_cash_balance is the sum of each total_cash_balance in the starting_balance array. Group these together to make the hierachy clear and repeat for the ending balance.

Be aware of the difference between amount and total_amount: amount reports the sum of entries in that ledger, where total_amount reports the sum of entries in that ledger and all child ledgers.

const CashFlow = () => {
    // ...

    return (
        <main>
            <h1>Cash flow report</h1>

            <section>
                <h2>Starting balance</h2>
                <p>{data.starting_cash_balance}</p>
                <ul role="list">
                    {data.starting_balances.map(ledgerStartingBalance => {
                        return (
                            <li key={ledgerStartingBalance.ledger_id}>
                                <div>
                                    <p>{ledgerStartingBalance.ledger_name}</p>
                                    <p>{ledgerStartingBalance.total_cash_balance}</p>
                                </div>
                            </li>
                        )
                    })}
                </ul>
            </section>

            <section>
                <h2>Ending balance</h2>
                <p>{data.ending_cash_balance}</p>
                <ul role="list">
                    {data.ending_balances.map(ledgerEndingBalance => {
                        return (
                            <li key={ledgerEndingBalance.ledger_id}>
                                <div>
                                    <p>{ledgerEndingBalance.ledger_name}</p>
                                    <p>{ledgerEndingBalance.total_cash_balance}</p>
                                </div>
                            </li>
                        )
                    })}
                </ul>
            </section>
        </main>
    )
}

export default CashFlow;


3. Display the ledgers and line entries

Iterate over the cash_flow_ledgers array to list each ledger that has affected the balance.


const CashFlow = () => {
    // ...

    return (
        <main>
            <h1>Cash flow report</h1>

            <section>
                {/* Starting balances ... */}
            </section>
            <section>
                <h2>Cash flows</h2>
                <ul role="list">
                    {data.cash_flow_ledgers.map(ledger => {
                        return (
                            <li key={ledger.ledger_id}>
                                <h3>{ledger.name}</h3>
                                <p>{ledger.total_net_cash_flow}</p>
                            </li>
                        )
                    })}
                </ul>
            </section>
            <section>
                {/* Ending balances ... */}
            </section>
        </main>
    )
}

export default CashFlow;


4. Filter by date

Add a date picker to the UI and use the start_date and end_date parameters to filter the request. If you need a date picker to get started, see the Reports introduction for an example. In this example, we use the date picker to set the start_date and end_date as query parameters and use those in our request. If the query params have not been set, you should have a default date range to fall back to, for example the year to date, in YYYY-MM-DD format.

To ensure all of our reports are consistent regardless of where a user is located, all dates in Teal are in UTC. If you adjust the displayed timezone to where the user is, you may see transactions listed on incorrect days.

const CashFlow = () => {
    // Set the default date range to year to date
    const date = new Date();
    const currentYear = date.getUTCYear();
    const currentMonth = date.getUTCMonth();
    const currentDate = date.getUTCDate();
    const defaultStartDate = `${currentYear}-01-01`;
    const defaultEndDate = `${currentYear}-${currentMonth}-${currentDate}`;

    // Get the search params
    const params = new URL(document.location).searchParams
    const startDate = params.get("start_date") ?? defaultStartDate;
    const endDate = params.get("end_date") ?? defaultEndDate;

    const cashFlowRequest = await fetch(
        'https://api.sandbox.teal.dev/v0/reports/cash-flow?start_date=${start_date}&end_date=${end_date}', 
        options
    );

    const cashFlowData: CashFlowReport = await request.json();

    return (
        // ...
    )

}

Best practices

  • If an account is missing from the cash flow report, check that its report_cash_flow attribute is true.
  • It can be helpful for users to see transactions associated with the cash flow ledgers using the Get Ledger Statement endpoint. Consider either linking to the ledger or showing the transactions inline. If you decide to display them inline, consider a design pattern that will handle pagination.
  • If you are displaying transactions inline, users may find miscategorized transactions while they review the cash flow report. Consider building a way to recategorize transactions directly into the screen so they don’t have to change contexts to complete their action.

On amount formats:

  • Be aware of how you display amount values. Money moving in and out of a credit card account will have the opposite signs from debit accounts.
  • Use a standard number formatter (new Intl.NumberFormat() in JavaScript) to ensure symbols, decimal places, and commas are appropriately accounted for.
  • Additionally, we strongly recommend that you use the font-variant-numeric: tabular-nums; css rule to display the amounts to keep consistent spacing for optimal legibility.

Relevant resources