forecast.read
Read the tenant's STORED forecast — the verify-read for this rail. view picks the answer, one of summary, monthly, variance, scenarios, weekly (default summary). summary: the outcome bands (label, growth_direction, probability_pct, final_month_revenue_low and _high, distress_risk_pct, path_count), the cash block, blend {yours_pct, peers_pct} (the share of the result from this business's own history versus businesses like it; null when shallow). monthly: per month revenue, costs and net at p10, p25, p50, p75 and p90 with distress_risk_pct, plus balance_p10 to balance_p90 and below_zero_cum_pct when a balance anchors the cash block, and the cash block. This release moved monthlyForecast out of the default answer into view 'monthly'. Every view carries view, dataMonths, history_months, shallow (true under 5 months of history) and CFO narration status, money formatted in the business's currency, named in the top-level currency field: the engine runs in USD and figures convert back at the rate pinned on the stored result (fx_rate_to_usd); before this release they were USD. Free. Refuses with VALIDATION_ERROR naming view when it is not in the list. The cash block is computed from a real bank balance plus each simulated path's revenue minus costs: with basis 'anchored' it carries provenance (the balance grade), balance_source ('statement': the latest balance on bank statements imported with banking.import_statement, used while under 31 days old in place of a typed balance for the same account; a typed account whose label ends in other last 4 digits, or the same digits in another currency, and dated on or after the statement, is added to it and provenance is then declared (an older one is left out: save it again with today's date); 'settings': entered on the Forecast page or saved by forecast.run_stored; 'upload_row': the cash row of an uploaded sheet), balance_as_of, runway_months_p10 and _p50 (null = no cash-out within the horizon), cash_out_pct, lowest_balance_p10, burn_rate_p50_per_month, cost_cut_to_survive_pct and health. With no balance dated within 45 days before the day the forecast was computed and before its first month, basis is 'unanchored': runway, cash-out and health are null, net-flow figures remain, and unavailable_reason plus next_step say how the owner adds today's balance. unavailable_reason 'forecast_out_of_date' means the forecast's months end before today or before the balance on record, so today's balance cannot start it: rebuild from recent months first (forecast.run_stored, or an upload on the Forecast page), as its next_step says. This release replaced the old cashFlow block (its runway started from an invented balance), removed the monthly cash median and renamed the monthly death-risk column to distress_risk_pct. The summary view also carries readiness, whether the books are ready for forecast.run_stored without running it: ready, months, first_period, last_period, min_months, gap_months, recent_gap_months, gap_window_months, months_with_receipts, refusal_code (null when ready, else SIMPLER_FORECAST_LEDGER_TOO_SHORT, SIMPLER_FORECAST_LEDGER_GAPS or SIMPLER_FORECAST_LEDGER_NO_RECEIPTS), message, next_step, base_currency, base_currency_source, legacy_paid_without_payments, fx_unconverted_currencies, bucket_timezone and excluded_period; when the books cannot be read just now readiness is null and readiness_unavailable {code SIMPLER_FORECAST_LEDGER_READ_FAIL, message, next_step} says to retry, and the forecast still returns. variance: the track record, earlier saved forecasts against what happened, worked out on each read and never stored. variance.rows has one row per month with both an actual and an earlier forecast: month, horizon_months (1 = the forecast whose data ended the month before), forecast_made_on, actual, p10, p50, p90, inside_80 (the actual landed between p10 and p90), error_pct ((actual - p50) / p50 x 100, null when p50 is not above zero) and fx_pinned (false = converted at today's rate because that saved forecast carries no rate of its own). variance.summary: n, inside_80_count, inside_80_pct, median_abs_pct_error, min_months and verdict, one of too_few, too_narrow, consistent, too_wide: too_few under 12 months, otherwise whether the share inside sits below, within or above what an 80% range should give over n months. Actuals are paid receipts from the books for a books forecast, or the latest upload's revenue for a sheet, in variance.currency; months with zero revenue count. When they cannot be read, variance is null and variance_unavailable {code SIMPLER_FORECAST_VARIANCE_READ_FAIL, message, next_step} says to retry. scenarios: what if, on the stored forecast. It reruns the stored months at the stored fx_rate_to_usd (never a live rate) and applies up to 3 driver sets to the same simulated paths; it stores nothing and calls no model. drivers is a flat list of {kind, start, end?, amount?, pct?, customer_ref?, set?}: set (1 to 3, default 1) says which compared set a driver belongs to, at most 20 in a set; kinds, dates and amounts as forecast.run describes, amounts in the stored forecast's currency; lose_customer takes customer_ref (an invoice client id from invoice_client_list; the books give its average monthly receipts over the 6 months before the first forecast month) or amount. With no drivers it answers the base alone. scenarios.base and each scenarios.compared entry carry set, drivers, floored_path_months (path-months a driver would have taken below zero, held at zero), months (revenue, costs and net at p10 to p90, financing, and balance_p10 to _p90 with below_zero_cum_pct when a balance anchors it) and a cash block; scenarios.lose_customer echoes each customer average used. Drivers change the money on the paths, not growth or closures (no knock-on effects). Refuses with VALIDATION_ERROR and simpler_code SIMPLER_FORECAST_DRIVER_INVALID (a field is wrong, an amount names another currency than the stored forecast's, or a start falls outside the forecast months: fix it as the field says), SIMPLER_FORECAST_DRIVER_LIMIT (more than 20 drivers in a set, or a set above 3: split the call) or SIMPLER_FORECAST_DRIVER_UNKNOWN_CUSTOMER (no such client: use an id from invoice_client_list, or send amount); drivers with a view other than scenarios or weekly, or cash_on with a view other than weekly, is a VALIDATION_ERROR; when the books cannot be read for a customer_ref it refuses with SERVICE_UNAVAILABLE SIMPLER_FORECAST_LEDGER_READ_FAIL: retry, or send amount. weekly: the next 13 weeks, Monday to Sunday in weekly.bucket_timezone, worked out from the books on each read (2000 seeded draws, the same answer all week for the same books; it stores nothing and calls no model), money in weekly.currency, the books' currency, which driver amounts are read in too. Days before weekly.model_start are the books' own money. From it on, open invoices (the 2000 largest; truncated_invoices counts the rest) are paid per their receipt timing, recurring invoices and expenses land on their schedule, and typical new invoices, cash sales and spend are drawn from the last 26 weeks and spread evenly over each week's days (resampled_flows_spread 'even_by_day'). weekly.weeks has week, start, end, recorded_days, receipts, payments and net at p10, p50 and p90, financing, and top_contributors (up to 5: kind, ref, label, direction, expected). With a stored balance dated within 31 days, rolled forward with the books' movements, each week also has balance_p10, _p50 and _p90 at Sunday's end, below_zero_pct, lowest_day and lowest_day_balance_p10 (the week's lowest end-of-day balance at p10 and its day); without one, weekly.balance is null and balance_reason plus next_step say how to add it. drivers (one set, no set field) apply as in scenarios, except that a dated one moves money on its day: a one-off lands whole on that day, and a hire, a loan_repayment, or a revenue_step or cost_step above zero with a start day lands its whole monthly amount on that day of each month through its end (the month's last day when the month is shorter; a day already past adds nothing), where cash_on lists it; a step below zero (a cut) and a month-only monthly driver are spread evenly over each month's days from their start, and a month-only one-off over its days from model_start, or whole on model_start when none of its days is left. View scenarios, which is monthly, spreads a dated monthly driver's first month by the days it covers. cash_on (YYYY-MM-DD, weekly only) adds weekly.cash_on: that day's balance at p10, p50 and p90, below_zero_pct and dated_items due on or before it. weekly refuses with VALIDATION_ERROR and simpler_code SIMPLER_FORECAST_CASH_ON_OUT_OF_RANGE when cash_on is outside the 13 weeks (send a date inside them) or SIMPLER_FORECAST_DRIVER_INVALID when a driver starts outside them or its amount names another currency than the books' (a row's amount the same way refuses with SIMPLER_FORECAST_AGENT_INPUT_INVALID); with SIMPLER_FORECAST_WC_NEEDS_CASH when cash_on is asked with no usable balance stored (save today's balance first, as its next_step says); and with SERVICE_UNAVAILABLE SIMPLER_FORECAST_WEEKLY_READ_FAIL when the books cannot be read (retry). view weekly also takes your own accounting system's rows, open_receivables, paid_history, open_payables and recurring, in the shapes and caps forecast.run describes (a row without currency is in weekly.currency): paid and past-due rows join the books' history for the receipt timing, the items join the books' own (the 2000 largest open invoices across both are drawn), a row in a currency with no rate is left out and named in fx_unconverted_currencies, weekly.accounting_inputs counts the rows used, and nothing is stored. The starting balance stays the stored one; to try another balance send the lists to forecast.run. The lists with a view other than weekly are a VALIDATION_ERROR; they refuse with PAYLOAD_TOO_LARGE SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE over a cap (send the largest rows up to it) and VALIDATION_ERROR SIMPLER_FORECAST_AGENT_INPUT_INVALID naming each wrong field (fix it as it says), before the compute count. The variance, scenarios and weekly views count toward 60 compute reads an hour per workspace, shared with the Forecast page and apart from forecast.run, checked after the drivers are validated (a scenarios or weekly start outside the forecast's months included) and a stored forecast is found (a NOT_FOUND is not counted); past it the call refuses with RATE_LIMITED, simpler_code SIMPLER_FORECAST_READ_COMPUTE_LIMITED and a next_step: try again within the hour, and views summary and monthly are not counted. No stored forecast yet → NOT_FOUND whose error carries the runnable forecast.run_stored call and the same readiness and readiness_unavailable keys: when readiness.ready is false, fix the books as its next_step says before calling run_stored, which would refuse with the same code. For a member or viewer token, which run_stored refuses, next_call is instead a sentence: ask a workspace owner or admin to run the forecast.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | One of summary, monthly, variance, scenarios, weekly; leave it out for summary. | |
| cash_on | No | View weekly only: a date YYYY-MM-DD inside the 13 weeks; the answer adds that day's end-of-day balance. | |
| drivers | No | Optional, views scenarios and weekly only: at most 20 drivers in each of up to 3 sets, one flat list; weekly takes one set (no set field). | |
| recurring | No | Optional, view weekly only, joined with the books' own for this answer: repeating money, at most 100 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). direction out leaves on each date; direction in falls due on each date and is paid on the receipt-timing curve, like a receivable. | |
| paid_history | No | Optional, view weekly only, joined with the books' own for this answer: invoices already paid, at most 5,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). The receipt-timing curve learns from the days between due_date and paid_at; with no paid history at all the labelled prior times every receivable (source 'prior'). | |
| open_payables | No | Optional, view weekly only, joined with the books' own for this answer: bills you owe, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). Each is paid on its due date (one already due is paid on the first modelled day). | |
| open_receivables | No | Optional, view weekly only, joined with the books' own for this answer: invoices your own accounting system shows unpaid, at most 2,000 rows (more refuses with SIMPLER_FORECAST_AGENT_INPUT_TOO_LARGE). Each is paid on the receipt-timing curve from its due date. |