Browse the API reference

Backfill Plan History

post/extensions/roboledger/{graph_id}/operations/backfill-plan-history

Part of Extensions: RoboLedger.

Compile monthly statement history behind the close boundary — the plan's historical columns. Seeds any missing FiscalPeriod rows (baseline-closed) back to the clamped start_period, then restamps each month lacking canonical statement FactSets by running the real reopen → reclose cycle (balance validation, statement rules, and audit events per month). Chunked: at most max_periods months per call, oldest first — loop until remaining_periods comes back empty. Idempotent: already-stamped months are never touched. Months holding draft entries are skipped, never posted. start_period is clamped to the earliest month with ledger data, so deep-history tenants only backfill what actually exists.

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.

Authentication

Authenticate in any one of these ways — not all of them:

  • API key in the X-API-Key header.
  • Bearer token in the Authorization header.

Path parameters

NameTypeDescription
graph_idrequiredstringGraph Id

Header parameters

NameTypeDescription
Idempotency-KeyoptionalstringIdempotency-Key

Request body

Required, application/json.

FieldTypeDescription
start_periodoptionalstring

YYYY-MM period to backfill from. Clamped to the earliest month with ledger data; defaults to that month when omitted. Must be on or before `closed_through`.

max_periodsoptionalinteger

Maximum months to restamp in this call. Each month runs a full reopen → reclose cycle; keep chunks modest and loop on `remaining_periods`.

Default: 12

allow_stale_syncoptionalboolean

Override the sync-currency gate on each reclose. Historical months predate the last sync in the normal case, so this is rarely needed.

Default: false

allow_stranded_obligationsoptionalboolean

Override the stranded-obligation gate on each reclose. Only needed when a matured classified obligation without a drafted entry exists inside the backfill window and you have decided not to draft or void it first.

Default: false

allow_reconciling_itemsoptionalboolean

Override the reconciling-item gate on each reclose. Only needed when an event inside the backfill window is still flagged as changed upstream and you have decided not to resolve it first.

Default: false

restampoptionalboolean

Also re-derive months that ALREADY have canonical statement sets (default: skip them). Use after an engine improvement changes what a stamp produces — each month reruns the full reopen → reclose cycle and replaces its sets. A restamp run is not self-resuming (every month in range stays a candidate); advance `start_period` between chunks.

Default: false

noteoptionalstring

Free-form note attached to each close audit event

Example request

curl
curl -X POST "https://api.robosystems.ai/extensions/roboledger/{graph_id}/operations/backfill-plan-history" \
  -H "X-API-Key: $ROBOSYSTEMS_API_KEY" \
  -H "Idempotency-Key: <Idempotency-Key>"

Responses

200 Successful Response

FieldTypeDescription
operationrequiredstring

Kebab-case operation name

operationIdrequiredstring

op_-prefixed ULID for audit and SSE correlation

statusrequiredstring

Operation lifecycle state

One of: completed, pending, failed

resultoptionalBackfillPlanHistoryResponse

Command-specific result payload

BackfillPlanHistoryResponse fields
FieldTypeDescription
fiscal_calendarrequiredFiscalCalendarResponse

Current fiscal calendar state for a graph.

FiscalCalendarResponse fields
FieldTypeDescription
graph_idrequiredstring
fiscal_year_start_monthrequiredinteger
closed_throughoptionalstring

Latest closed period (YYYY-MM), or null if nothing closed

close_targetoptionalstring

Target period the user wants closed through (YYYY-MM)

gap_periodsoptionalinteger

Number of periods between closed_through and close_target (inclusive of close_target). 0 means caught up.

Default: 0

catch_up_sequenceoptionalstring[]

Ordered list of periods that a close run would process

closeable_nowoptionalboolean

Whether the next period in the catch-up sequence passes all closeable gates

Default: false

blockersoptionalstring[]

Structured blocker codes when closeable_now is False: 'sequence_violation', 'period_incomplete', 'sync_stale', 'calendar_not_initialized', 'period_already_closed', 'pending_obligations', 'stranded_obligations'

pending_obligation_countoptionalinteger

Number of pending schedule_entry_due events blocking close. Non-zero only when `pending_obligations` is in `blockers`.

Default: 0

pending_obligation_sampleoptionalPendingObligationDetailResponse[]

Sample of up to 5 pending obligations (schedule_id, schedule_name, period, event_id) ordered by occurred_at. Use `list-event-blocks` with event_type=schedule_entry_due&status=pending for the full set.

earliest_pending_periodoptionalstring

Earliest period (YYYY-MM) with a pending obligation blocking close. Null when no pending_obligations blocker is active.

sync_stale_daysoptionalinteger

Days the most recent sync is stale relative to the period to close. Populated only when `sync_stale` is in `blockers` and last_sync_at exists (null when there's a connection but no sync has ever run).

stranded_obligation_countoptionalinteger

Matured schedule_entry_due events already at 'classified' with no drafted closing entry for their (schedule, period) — adjusting entries a close would silently omit. Resolve by running promote-obligations with dispatch_handlers=true (which reaches them) or voiding the obligation.

Default: 0

stranded_obligation_sampleoptionalPendingObligationDetailResponse[]

Sample of up to 5 stranded obligations (schedule_id, schedule_name, period, event_id) ordered by occurred_at.

reconciling_item_countoptionalinteger

Posted events in or before this period whose source payload changed afterwards and that nobody has dispositioned — differences between the books and the source system. Resolve each with resolve-reconciling-item, or close over them knowingly with allow_reconciling_items.

Default: 0

reconciling_item_sampleoptionalstring[]

Source identifiers (or event ids) of up to 5 unresolved reconciling items, so the blocker names what is holding the close.

last_close_atoptionalstring (date-time)
initialized_atoptionalstring (date-time)
last_sync_atoptionalstring (date-time)

Most recent QB sync timestamp (if connected)

periodsoptionalFiscalPeriodSummary[]

Fiscal period rows for this graph

earliest_available_periodrequiredstring

First month with ledger data — the hard floor for backfill

effective_start_periodrequiredstring

The start actually used after clamping to earliest_available_period

closed_throughrequiredstring

The close boundary the backfill runs up to (inclusive)

period_rows_createdoptionalinteger

FiscalPeriod rows seeded (baseline-closed) for months the calendar didn't cover yet

Default: 0

processedoptionalBackfillPeriodOutcome[]

Months this call attempted, oldest first

BackfillPeriodOutcome fields
FieldTypeDescription
periodrequiredstring

The month, in YYYY-MM

statusrequiredstring

stamped: reopen → reclose completed. skipped_drafts: the month holds draft entries the backfill refuses to post — review via list-period-drafts, then close-period or re-run. failed: the reclose raised; processing halted (see detail).

statements_stampedoptionalboolean

Whether the reclose stamped canonical statement FactSets. False with a statement_stamp_note soft-skip when reporting isn't set up.

Default: false

statement_stamp_noteoptionalstring

Soft-skip reason when statements_stamped is false

statement_rule_summaryoptionalobject

Statement-rule verification tally for the month's stamped sets (pass/fail/error/skipped); None when no rules ran.

detailoptionalstring

Human-readable detail for skipped/failed months

remaining_periodsoptionalstring[]

Months still lacking canonical statement sets that this call did not attempt (beyond max_periods, or after a failure halt). Loop until empty.

atrequiredstring

ISO-8601 UTC timestamp

createdByoptionalstring

User ID that initiated the operation (null for legacy callers)

idempotentReplayoptionalboolean

True when this envelope came from the idempotency cache — the underlying command did not execute again. False on fresh executions.

Default: false

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