---
title: "Set Close Target"
method: POST
path: "/extensions/roboledger/{graph_id}/operations/set-close-target"
tags: ["RoboLedger: Fiscal Close"]
---

# Set Close Target

`POST /extensions/roboledger/{graph_id}/operations/set-close-target`

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

Set the user-controlled goal period for closing (`close_target`). Format: YYYY-MM. Distinct from `closed_through` (what's actually locked) — setting a target doesn't close anything; call `close-period` for that. The catch-up sequence between `closed_through` and this target appears on the response's `fiscal_calendar.catch_up_sequence`.

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

- SetCloseTargetOperation
  - `entity_id` string, nullable: The entity whose books this acts on, by id. Omit for the group parent — the single-entity default.
  - `period` string, required: Target period in YYYY-MM format. Must be > current `closed_through`.
  - `note` string, nullable: Free-form note attached to the audit event

## 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)
