---
title: "Change Calendar Start"
method: POST
path: "/extensions/roboledger/{graph_id}/operations/change-calendar-start"
tags: ["RoboLedger: Setup"]
---

# Change Calendar Start

`POST /extensions/roboledger/{graph_id}/operations/change-calendar-start`

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

Move where an entity's fiscal calendar starts, allowed only before its first close. Earlier adds open months back to `first_open_period`, for history that predates the start; later removes empty leading months. Refused once any month has closed (409), and when moving later would drop months that hold entries or unposted source lines (409).

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

- ChangeCalendarStartRequest: Move where an entity's calendar starts, before its first close. Earlier adds open months back to `first_open_period`, for history that predates the start (a bank feed's backfill, a cutover moved earlier). Later removes empty leading months. Refused once any month has closed, and when moving later would drop months that hold entries or unposted source lines.
  - `entity_id` string, nullable: The entity whose books this acts on, by id. Omit for the group parent — the single-entity default.
  - `first_open_period` string, required: YYYY-MM: the new first month of the calendar, open.
  - `note` string, nullable: Free-form note attached to the audit event

## Response `200`

Successful Response

- OperationEnvelopeChangeCalendarStartResponse
  - `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` ChangeCalendarStartResponse
    - `fiscal_calendar` FiscalCalendarResponse, required: 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.
    - `periods_created` integer: Open FiscalPeriod rows added by moving the start earlier
    - `periods_removed` integer: Empty FiscalPeriod rows removed by moving the start later
  - `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/28ffd375c457?raw)
