---
title: "Reopen Fiscal Period"
method: POST
path: "/extensions/roboledger/{graph_id}/operations/reopen-period"
tags: ["RoboLedger: Fiscal Close"]
---

# Reopen Fiscal Period

`POST /extensions/roboledger/{graph_id}/operations/reopen-period`

## 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/reopen-period`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Reopen a closed period for adjustment. Only the latest closed period (`closed_through`) can be reopened; it decrements by one and the period's entries become writable again. To reach an earlier month, reopen latest-first down to it, then re-close forward — an out-of-order reopen is refused (422) with the ordered list, because every later closed month carries statements stamped from the earlier month's numbers. Retracts the month's canonical statement FactSets (a reopened month is no longer a closed assertion; re-closing restamps them). The required `reason` is captured in the audit log. Use sparingly — reopen invalidates downstream artifacts that trusted the closed state (reports, shared filings).

**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

- ReopenPeriodOperation: Reopen a closed fiscal period.
  - `entity_id` string, nullable: The entity whose books this acts on, by id. Omit for the group parent — the single-entity default.
  - `reason` string, required: Required reason for the reopen (captured in audit log)
  - `note` string, nullable: Additional free-form note
  - `period` string, required: Period to reopen, in YYYY-MM. Only the latest closed period (the current `closed_through`) can be reopened, and reopening it retreats `closed_through` by one month. To reach an earlier period, reopen the later ones first, latest to earliest.

## Response `200`

Successful Response

- OperationEnvelopeFiscalCalendarResponse
  - `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` FiscalCalendarResponse: Current fiscal calendar state for one entity of a graph.
    - `graph_id` string, required
    - `entity_id` string, nullable: The entity whose calendar this is.
    - `fiscal_year_start_month` integer, required
    - `closed_through` string, nullable: Latest closed period (YYYY-MM), or null if nothing closed
    - `close_target` string, nullable: Target period the user wants closed through (YYYY-MM)
    - `gap_periods` integer: Number of periods between closed_through and close_target (inclusive of close_target). 0 means caught up.
    - `catch_up_sequence` string[]: Ordered list of periods that a close run would process
    - `closeable_now` boolean: Whether the next period in the catch-up sequence passes all closeable gates
    - `blockers` string[]: 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'; on the consolidation entity, whose close is the group's, also 'entity_open', 'adjustments_unposted', 'residual_unexplained', 'consolidated_does_not_foot'
    - `pending_obligation_count` integer: Number of pending schedule_entry_due events blocking close. Non-zero only when `pending_obligations` is in `blockers`.
    - `pending_obligation_sample` PendingObligationDetailResponse[]: 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.
      - `event_id` string, required
      - `schedule_id` string, nullable
      - `schedule_name` string, nullable
      - `period` string, required: Period in YYYY-MM format
    - `earliest_pending_period` string, nullable: Earliest period (YYYY-MM) with a pending obligation blocking close. Null when no pending_obligations blocker is active.
    - `sync_stale_days` integer, nullable: 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_count` integer: 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.
    - `stranded_obligation_sample` PendingObligationDetailResponse[]: Sample of up to 5 stranded obligations (schedule_id, schedule_name, period, event_id) ordered by occurred_at.
      - `event_id` string, required
      - `schedule_id` string, nullable
      - `schedule_name` string, nullable
      - `period` string, required: Period in YYYY-MM format
    - `reconciling_item_count` integer: 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.
    - `reconciling_item_sample` string[]: Source identifiers (or event ids) of up to 5 unresolved reconciling items, so the blocker names what is holding the close.
    - `unposted_source_event_count` integer: 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.
    - `unposted_source_event_sample` string[]: Source identifiers (or event ids) of up to 5 unposted source events, so the blocker names what is holding the close.
    - `unreconciled_account_count` integer: 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.
    - `unreconciled_account_sample` string[]: Name and status of up to 5 of those reconciliations, so the blocker names what is holding the close.
    - `group_open_entities` string[]: The group close: the entities the month consolidates, the parent and its equity-method members included, that have not closed it. Close each first.
    - `group_pending_adjustments` string[]: The group close: the consolidating entries the consolidation entity neither holds nor has drafted, by kind and member, or what the engine left out and why. Run propose-consolidation-entries.
    - `group_unexplained` string[]: The group close: residuals and intercompany disagreements left unexplained. Correct the books or post the explaining entry, or close over them knowingly with allow_unexplained_residuals.
    - `group_not_footing` string[]: The group close: the consolidated balance sheet's and equity statement's validation failures for the month.
    - `last_close_at` string, date-time, nullable
    - `initialized_at` string, date-time, nullable
    - `last_sync_at` string, date-time, nullable: Most recent QB sync timestamp (if connected)
    - `periods` FiscalPeriodSummary[]: Fiscal period rows for this graph
      - `name` string, required: Period name (YYYY-MM)
      - `start_date` string, date, required
      - `end_date` string, date, required
      - `status` string, required: 'open' | 'closing' | 'closed'
      - `closed_at` string, date-time, nullable
      - `has_close_receipt` boolean: Whether this period carries a close receipt. A flag rather than the receipt itself keeps the calendar listing compact; fetch the receipt from `get-period-close-status` for the period. False on open periods and on periods closed before receipts shipped.
  - `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)
