Browse the extensions reference

Backfill Plan History

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

Part of RoboLedger: Fiscal Close.

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

Constraints: matches ^(kg[a-f0-9]{16,}(?:_[a-zA-Z0-9]{1,20})?|sec(?:_[a-zA-Z0-9]{1,20})?|library)$

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.

Constraints: matches ^\d{4}-(0[1-9]|1[0-2])$

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

Constraints: 1–24

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

allow_unposted_source_eventsoptionalboolean

Override the unposted-source-event gate on each reclose. Only needed when a source event inside the backfill window was never committed and you have decided not to commit or void it first.

Default: false

allow_unreconciled_accountsoptionalboolean

Override the reconciliation gate on each reclose. Needed when a month inside the backfill window has a reconciliation the close waits on that was never compared for it, which is every month closed before the reconciliation existed.

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 · example 1 of 3
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>"
curl · example 2 of 3
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>" \
  -H "Content-Type: application/json" \
  -d '{
  "max_periods": 12,
  "start_period": "2019-07"
}'
curl · example 3 of 3
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>" \
  -H "Content-Type: application/json" \
  -d '{
  "max_periods": 12,
  "restamp": true,
  "start_period": "2024-08"
}'

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', 'reconciling_items', 'unposted_source_events', 'unreconciled_accounts'

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.

unposted_source_event_countoptionalinteger

Source events dated in this period that were never committed: bank-feed lines still captured or classified, and QuickBooks transactions whose automatic posting failed. Commit or void each, or close over them knowingly with allow_unposted_source_events.

Default: 0

unposted_source_event_sampleoptionalstring[]

Source identifiers (or event ids) of up to 5 unposted source events, so the blocker names what is holding the close.

unreconciled_account_countoptionalinteger

Reconciliations the close waits on that are not reconciled for this period, including any never compared for it. Run refresh-reconciliations and clear what it reports, release one with set-reconciliation-policy, or close over them knowingly with allow_unreconciled_accounts.

Default: 0

unreconciled_account_sampleoptionalstring[]

Name and status of up to 5 of those reconciliations, 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

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