Balances Tell You What a Wallet Has. Flows Tell You What It Does.
Every lender in the traditional world eventually asks for bank statements. Not because the balance is unknown, but because the balance is the least informative number on the page. What they want to see is the movement: does money arrive regularly, from how many sources, how much of it leaves again, how quickly, and to whom. A $50,000 balance that turns over three times a quarter from one employer is a different borrower from a $50,000 balance that turned over four hundred times last month from forty counterparties.
On-chain, every one of those movements is public. Until now, Cred Protocol summarised what a wallet holds: balances, lending positions, debt, and since this week, how those looked 30, 60 and 90 days ago. Today we are adding the other half. The Cash Flow endpoint reads every transfer that touched a wallet over the last year, values each one at that day's price, and reduces them to the statistics a cash-flow analysis is built on.
curl https://api.credprotocol.com/api/v2/report/address/vitalik.eth/cash-flow -H "Authorization: Bearer YOUR_API_KEY"
What You Get
One response, three windows: 30, 90 and 365 days, each summed across every chain the wallet has used. Per window:
- Inflow, outflow and net flow in USD, with transfer counts and active days.
- Lending flows, kept separate: borrows and withdrawals coming in, supplies and repayments going out.
- Conversion volume: swaps, wraps and LP entries, where money changed form rather than arriving or leaving.
- Stablecoin inflow regularity: how many of the window's 30-day periods saw stablecoin income, and how evenly it was spread.
- Counterparty concentration: distinct senders and recipients, and the share of inflow that came from the single largest source.
- Largest single inflow and outflow, and days since the last inflow.
- Average balance and turnover: total flow divided by what the wallet held, so a treasury and a trading desk read differently even at the same balance.
A trimmed example for one window:
{
"days": 90,
"inflow_usd": 36000.0,
"outflow_usd": 29400.5,
"net_flow_usd": 6599.5,
"lending_inflow_usd": 0.0,
"lending_outflow_usd": 7500.0,
"conversion_usd": 12800.0,
"stablecoin_inflow_usd": 36000.0,
"stablecoin_inflow_periods": 3,
"periods": 3,
"stablecoin_inflow_cv": 0.04,
"counterparties_in": 2,
"top_counterparty_inflow_share": 0.97,
"largest_outflow_usd": 4100.0,
"days_since_last_inflow": 6,
"average_balance_usd": 18420.55,
"turnover_ratio": 3.55,
"complete": true
}
Read that the way an underwriter would. Twelve thousand dollars of stablecoins arrived in each of the last three 30-day periods, almost all from one sender, with a coefficient of variation near zero. That is a salary. A fifth of the inflow went to a lending protocol as repayments. The rest was spent or converted, and the wallet ended the quarter ahead. Nothing in the balance alone would have told you any of that.
Getting the Counting Right
Raw transfer logs lie if you add them up naively, so most of the work in this endpoint is deciding what not to count.
Swaps are not income. A DEX trade shows up as an outflow of one token and an inflow of another in the same transaction. Counted as flows, a single swap inflates both sides of the ledger. Any transaction that moved value both into and out of the wallet is classified as a conversion and reported on its own line, never as inflow or outflow.
Lending is not spending. Depositing USDC into Aave is not a payment and borrowing it back is not income. Transfers whose counterparty is a known lending contract, Aave pools and aTokens, Compound markets, are reported as lending flows so that you can see them, and so that they do not masquerade as external cash.
Receipt tokens are not money. The aToken you receive for a deposit and the debt token minted when you borrow are positions, not funds, and are dropped before anything is counted.
Spam is not money either. Every transfer is valued at that day's market price. A token with no market price contributes nothing and is counted in unpriced_transfers. This single rule keeps the thousands of airdropped dust tokens that land in active wallets out of the totals, without a blocklist.
Use Cases
Underwriting on income, not just collateral
Overcollateralised lending never needed to know whether a borrower had income. Undercollateralised and reputation-based credit does. A wallet with steady stablecoin inflow across every period of the last year, low variation and a small number of senders looks like a borrower with a job or a business. One with a single large inflow six months ago and nothing since does not, however healthy its balance. The regularity fields give you that distinction directly, and lending_outflow_usd against inflow_usd tells you whether existing repayments are funded by income or by new borrowing.
Catching a drain before it finishes
A wallet being emptied shows a negative 30-day net flow against a positive 365-day one, a large single outflow relative to its average balance, and a rising number of days since the last inflow. Pair the 30-day window with the 90-day one and the trend is visible before the balance hits zero, which is when a balance check would have noticed.
Measuring dependence on a single counterparty
A wallet funded entirely by one address is either a payroll recipient or a sybil farm, and top_counterparty_inflow_share near 1.0 with counterparties_in of 1 is the signal in both cases. Combined with the sybil score and the transaction graph, you can tell which one you are looking at.
Telling a treasury from a trader
Turnover is the fastest way to characterise a wallet. A protocol treasury or a long-term holder turns over a fraction of its balance per quarter. A market maker turns over tens or hundreds of times. The same balance means very different things for the two, and turnover_ratio separates them in one number.
Giving agents a cash-flow view
The endpoint is exposed as the get_cash_flow tool on our MCP server, so an agent deciding whether to extend terms to a counterparty can ask for its flow profile in the same breath as its score. The field names are the ones above, and the tool description explains how to read them.
Pairs With Balance History
Cash Flow ships alongside Balance History, which returns a wallet's assets, lending deposits, collateral and debt as they stood today and 30, 60 and 90 days ago, valued at each day's prices. One endpoint gives you the stock at four instants, the other gives you the movement between them. Turnover in the cash-flow response is computed against those same balance points, so the two agree with each other by construction.
What It Does Not Do Yet
Transfers between a user's own wallets read as external flows, because nothing on-chain says two addresses share an owner. Gas is not counted as an outflow. We do not yet tag exchange deposit addresses, so an off-ramp and a payment look the same. And the average balance behind turnover is taken from the four balance-history points rather than a daily series. Each of these is on the list; none of them changes the shape of the response.
One more thing we are deliberate about. These are strong capacity signals, and they are also the easiest signals to manufacture by cycling funds through a wallet. For that reason they live in the report, where you can weigh them with your own judgment, and not yet in the Cred Score. As with every input we have added to the model, the robust ones will enter the score behind a version bump, with notice.
Try It
The endpoint costs 8 Cred Units per call and is available now to every API key. A cold request for an active wallet takes a few seconds while we read three transfer feeds per chain and price each token; repeat requests are served from cache.
import requests
r = requests.get(
"https://api.credprotocol.com/api/v2/report/address/vitalik.eth/cash-flow",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
for w in r.json()["windows"]:
print(f'{w["days"]:>3}d in ${w["inflow_usd"]:>12,.0f} out ${w["outflow_usd"]:>12,.0f} '
f'turnover {w["turnover_ratio"]} top sender {w["top_counterparty_inflow_share"]}')
The reference page documents every field and how to read it, and the sandbox returns deterministic mock data at /api/v2/sandbox/report/address/{address}/cash-flow for integration tests. If you do not have an API key yet, create one in the console.
