---
title: "Compute Forecast for a Forecast Block"
method: POST
path: "/extensions/roboledger/{graph_id}/operations/compute-forecast"
tags: ["RoboLedger: Information Blocks"]
---

# Compute Forecast for a Forecast Block

`POST /extensions/roboledger/{graph_id}/operations/compute-forecast`

## Request

- Base URL: `https://api.robosystems.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.robosystems.ai/extensions/roboledger/{graph_id}/operations/compute-forecast`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Walks a forecast block's driver cascade month-by-month forward from its base period: lever-driven rs-driver Derive rules in dependency order, carry-forward for unmodeled income-statement lines, calc-DAG subtotals — upserting one scenario income-statement FactSet (plus a working-capital balance-sheet set) per forward month, all keyed by the block's scenario_id (NULL = actuals; scenario reads pass it as a filter). Re-running replaces each month's values. Rules with missing lever months or unbound operands are skipped with a reason (their targets fall back to carry-forward), never errored. Deterministic and non-AI — no credits consumed.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.

## Path parameters

- `graph_id` string, required

## Headers

- `Idempotency-Key` string, nullable

## Request body

- ComputeForecastRequest: Request body for the `compute-forecast` operation. Walks the scenario's driver cascade month-by-month forward from the forecast block's `base_period`: lever-driven Derive rules in dependency order, carry-forward for unmodeled IS lines, calc-DAG subtotals — upserting one scenario IS FactSet (+ a working-capital BS set) per forward month, all keyed by the forecast block's `scenario_id`. Re-running replaces each month's values (the compute-metrics drift semantics). Deterministic and non-AI — no credits consumed.
  - `structure_id` string, required: Forecast block structure (block_type='forecast') to compute.
  - `months` integer, nullable: Forward months to compute — defaults to the block's full horizon_months; must not exceed it (lever assertions don't extend past the horizon).
  - `entity_id` string, nullable: Entity to compute for. Defaults to the lever FactSet's entity (the entity the scenario was authored against).

## Response `200`

Successful Response

- OperationEnvelopeComputeForecastResponse
  - `operation` string, required: Kebab-case operation name
  - `operationId` string, required: op_-prefixed ULID for audit and SSE correlation
  - `status` 'completed' | 'pending' | 'failed', required: Operation lifecycle state
  - `result` ComputeForecastResponse: Response for the `compute-forecast` operation.
    - `structure_id` string, required
    - `scenario_id` string, required: The scenario key every emitted FactSet carries — the forecast block's own structure id.
    - `entity_id` string, required
    - `base_period` string, required: Origin month of the block's authored horizon window — where its levers are keyed from. Equal to `anchor_period` unless the walk re-anchored at the seam.
    - `anchor_period` string, required: Month the walk actually seeded its opening balances from. With `base_anchor='seam'` this advances to the newest closed month as periods close, so the first forward month rolls off real balances instead of a stale base; with `'fixed'` it always equals `base_period`.
    - `months` integer, required: Forward months requested.
    - `months_computed` ForecastMonthLite[]
      - `period` string, required: Month key (`YYYY-MM`).
      - `period_start` string, date, required
      - `period_end` string, date, required
      - `income_statement_fact_set_id` string, nullable: Scenario IS FactSet upserted for the month.
      - `balance_sheet_fact_set_id` string, nullable: Scenario BS FactSet upserted for the month — the full roll: carry-forward, rule-driven working capital, schedule movements, RE roll, balancing cash (A = L + E by construction).
      - `cash_flow_fact_set_id` string, nullable: Scenario CF FactSet upserted for the month — indirect-method, derived from BS deltas + NI, reconciled to the balancing ΔCash.
      - `computed_count` integer: Number of facts emitted for the month across all sets.
      - `verification_passed` boolean, nullable: Whether every rule evaluated against the month's scenario sets passed. Three states, and the third is not the first: `true` = rules ran and all passed; `false` = at least one failed or errored, which halts the walk (see `halted_at`); `null` = **no rules ran**, so the month is unverified rather than verified. Treat null as absence of evidence, never as a pass.
      - `verification_failures` string[]: Failed/errored rule messages for the month (capped).
    - `halted_at` string, nullable: Month (`YYYY-MM`) where the walk stopped because verification failed, or null if it ran the full horizon. Each month's opening balances are the previous month's closing balances, so computing past a failure yields months derived from a known-wrong one rather than merely unverified months. When set, `months_computed` ends at this month and is shorter than `months`; the failing month's facts are kept so the failure can be inspected.
    - `skipped` SkippedForecastLite[]
      - `rule_id` string, nullable
      - `element_qname` string, nullable
      - `period` string, required: Month key (`YYYY-MM`) of the skip.
      - `reason` string, required
      - `missing` string[]
    - `diagnostics` string[]: Articulation notes — a missing cash/earnings anchor, schedule contributions with no base-set landing spot, an absent cash-flow structure. Informational; the walk still computed.
  - `at` string, required: ISO-8601 UTC timestamp
  - `createdBy` string, nullable: User ID that initiated the operation
  - `idempotentReplay` boolean: True when this envelope came from the idempotency cache — the underlying command did not execute again. False on fresh executions.

## Other responses

- `400`: Invalid request
- `401`: Authentication required
- `403`: Access denied
- `404`: Resource not found
- `409`: Idempotency-Key conflict — key reused with different body
- `422`: Validation error
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/robosystems/apis/robosystems-api.md) · [All operations](https://skmtc.dev/robosystems/apis/robosystems-api/llms.txt) · [OpenAPI document](https://skmtc.dev/robosystems/apis/robosystems-api/revisions/e661e2d5ca6a?raw)
