Coming soon · Contract draft

Period Close & Snapshots

Planned

A reporting-period contract for readiness, lock/close/reopen lifecycle, immutable snapshots, and asynchronous exports.

Reviewable specification — not callable

Documentation-first contract draft. The proposed additions on this page are not callable or available yet. Paths, payloads, scopes, names, and examples are intentionally concrete so customers can review the intended contract before and during implementation.

Canonical owner

Reporting period, close, snapshot, and export services

Contract posture

P2 · Documentation first · implementation follows approval

Contract metadata

Draft version

0.2 review draft

Review owner

Finance Platform + Developer Platform

Last reviewed

July 14, 2026

Target wave

Wave 5 · Financial operations

Contract dependencies

  • Generic asynchronous Operation resource and status contract
  • Principal × financial scope grantability matrix
  • Transactional outbox and production webhook activation gates

What this unlocks

Assess close readiness

Read a stable domain model for period close & snapshots without depending on GUI routes or database shapes.

Track close tasks

Create a reviewable proposal and apply only the bounded commands the canonical owner permits.

Publish immutable snapshots

React to durable lifecycle facts and connect external systems with explicit direction and provenance.

Lifecycle and invariants

Reporting periods use explicit commands and intermediate operation states. Failed asynchronous work returns the period to its last stable state; it never produces a partially closed period.

openlockedclosingclosedreopening
FromToCommandAuthority
openlockedLock periodFinance operator with period-close:lock
lockedopenUnlock periodFinance operator before close begins
lockedclosingStart closeNamed controller with period-close:close
closingclosedComplete close operationCanonical close worker after all proof obligations pass
closedreopeningStart reopenNamed controller with period-close:reopen and a reason
reopeningopenComplete reopen operationCanonical close worker with immutable audit linkage

Lifecycle invariants

  • Close cannot begin while blocking readiness exceptions remain unresolved or explicitly waived.
  • The snapshot created by a successful close is immutable and content-addressed.
  • Close and reopen always name an authorized human decision maker, even when a worker performs the operation.
  • A failed close or reopen returns to the prior stable state and preserves the failed operation record.
  • No invoice, time actual, or adjustment may mutate a closed period without an explicit reopen.

Authority boundaries

The interfaces expose canonical capabilities; they do not become a second owner of domain rules or state.

DigitalStack owns

  • Period state and close checklist
  • Snapshot identity and immutability
  • Export operation lifecycle

Explicitly not building

  • GraphQL close mutations
  • Autonomous close or reopen
  • Exposing worker queues instead of operations

Surface decisions

Deliberate additions, retained boundaries, and removals from the proposed external contract.

add

Readiness, tasks, lock/unlock, close/reopen, snapshots, exports, and Operation resources

The public contract must represent the complete close workflow and its asynchronous results.

keep

REST-only close and reopen with MCP preparation only

High-risk financial commands remain explicit human-authorized operations.

remove

GraphQL close mutations, autonomous MCP close, and raw worker queues

None belongs in a customer-facing financial contract.

Interface plan

REST API

Planned

Period reads, readiness, tasks, snapshots, exports, and narrow lock/close/reopen commands.

Read + explicit commands · close and reopen are asynchronous human-authorized operations

GraphQL

Planned

Composable period, readiness, exception, task, snapshot, and operation reads.

Read only · no lock, close, reopen, or export mutations

MCP / Agent API

Planned

Readiness explanation, exception analysis, and preparation of a human close request.

Read + prepare request · the agent cannot lock, close, or reopen a period

Webhooks

Planned

Durable period, snapshot, and export lifecycle facts emitted after canonical commit.

Past-tense facts only · no progress ticks or commands disguised as events

Connected Apps

Planned

ERP and analytics consumers receive approved snapshots or exports with explicit direction.

Outbound/read-only · connected systems cannot close or reopen DigitalStack periods

Cross-interface parity

Each surface delegates to the named canonical owner; a blank surface is an intentional denial of authority, not missing documentation.

CapabilityRESTGraphQLMCPWebhookCanonical owner
Read periodGET /reporting-periods/{id}reportingPeriodget_close_readinessReporting period service
Assess readinessGET /{id}/readinessReportingPeriod.readinessget_close_readiness · explain_close_exceptionClose-readiness service
Lock / unlock periodPOST /{id}/lock · POST /{id}/unlockNot exposedNot executablereporting_period.locked · reporting_period.unlockedReporting period service
Close periodPOST /{id}/close → OperationNot exposedprepare_close_request onlyreporting_period.closedClose orchestration service
Reopen periodPOST /{id}/reopen → OperationNot exposedNot exposedreporting_period.reopenedClose orchestration service
Export snapshotPOST /{id}/exports → OperationOperation status read onlyget_operation_statusexport.completed · export.failedSnapshot and export services

Proposed scopes

Proposed scopes are not grantable yet.

period-close:readplanned scope
Read periods, readiness, tasks, exceptions, snapshots, and operation status.
period-close:lockplanned scope
Lock or unlock an open period after readiness validation.
period-close:closeplanned scope
Submit an idempotent, human-authorized close operation.
period-close:reopenplanned scope
Submit a separately authorized reopen operation with a required reason.
period-close:exportplanned scope
Create and retrieve approved snapshot exports.

Behavioral contract

Cross-cutting rules every implementation and interface must satisfy.

Optimistic concurrency

Every command requires If-Match with the current period version; stale commands fail with stale_version.

Command idempotency

Lock, close, reopen, and export require Idempotency-Key and return the original operation on a safe retry.

Asynchronous operations

Close, reopen, and export return 202 with an Operation resource. Clients poll operations or subscribe to terminal events.

Atomic state transition

A period becomes closed only after validation, snapshot creation, audit append, and event enqueue commit atomically.

Named error contract

Clients can branch on period_not_ready, stale_version, period_locked, operation_conflict, and scope_required.

Durable attribution

The deciding human, submitting principal, worker operation, reason, and resulting snapshot remain linked in audit history.

REST API

Proposed endpoints

Planned
GET/api/v1/reporting-periods

List reporting periods

List authorized periods by fiscal year, state, or close date.

period-close:read

Principal
Finance viewer or operator
Execution
Synchronous
Named errors
scope_required
GET/api/v1/reporting-periods/{id}

Retrieve a reporting period

Return lifecycle state, version, readiness summary, latest snapshot, and allowed actions.

period-close:read

Principal
Finance viewer or operator
Execution
Synchronous
Named errors
period_not_found, scope_required
GET/api/v1/reporting-periods/{id}/readiness

Get close readiness

Return blocking exceptions, warnings, task completion, waivers, and readiness version.

period-close:read

Principal
Finance viewer or operator
Execution
Synchronous
Named errors
period_not_found, scope_required
GET/api/v1/reporting-periods/{id}/tasks

List close tasks

Return the close checklist, owners, evidence, due state, and blocking classification.

period-close:read

Principal
Finance viewer or operator
Execution
Synchronous
Named errors
period_not_found, scope_required
POST/api/v1/reporting-periods/{id}/lockconfirmation

Lock a period

Lock an open period using the current period and readiness versions.

period-close:lock

Principal
Finance operator
Execution
Synchronous
Idempotency
Required for every command
Named errors
period_not_ready, stale_version, operation_conflict
POST/api/v1/reporting-periods/{id}/unlockconfirmation

Unlock a period

Return a locked period to open before a close operation begins.

period-close:lock

Principal
Finance operator
Execution
Synchronous
Idempotency
Required for every command
Named errors
period_not_locked, stale_version, operation_conflict
POST/api/v1/reporting-periods/{id}/closeconfirmation

Start period close

Revalidate readiness and enqueue one atomic close operation.

period-close:close

Principal
Named controller
Execution
Asynchronous operation
Idempotency
Required; retries return the original operation
Named errors
period_not_ready, stale_version, operation_conflict, scope_required
POST/api/v1/reporting-periods/{id}/reopenconfirmation

Start period reopen

Submit a separately authorized reopen with a durable reason.

period-close:reopen

Principal
Named controller
Execution
Asynchronous operation
Idempotency
Required; retries return the original operation
Named errors
period_not_closed, stale_version, operation_conflict, scope_required
GET/api/v1/reporting-periods/{id}/snapshots

List immutable snapshots

List approved snapshots, checksums, close operations, and export availability.

period-close:read

Principal
Finance viewer or operator
Execution
Synchronous
Named errors
period_not_found, scope_required
POST/api/v1/reporting-periods/{id}/exportsconfirmation

Create snapshot export

Create an asynchronous export from an immutable approved snapshot.

period-close:export

Principal
Finance operator or analytics exporter
Execution
Asynchronous operation
Idempotency
Required per snapshot, format, and destination
Named errors
snapshot_not_found, export_not_allowed, operation_conflict
GET/api/v1/operations/{id}

Get operation status

Retrieve close, reopen, or export progress and terminal result.

period-close:read

Principal
Submitting principal or authorized finance viewer
Execution
Synchronous
Named errors
operation_not_found, scope_required

Start an authorized period close

curl --request POST \
+  --url https://www.digitalstack360.com/api/v1/reporting-periods/period_2026_06/close \
+  --header "Authorization: Bearer $DSTACK_API_KEY" \
+  --header "Content-Type: application/json" \
+  --header 'If-Match: "7"' \
+  --header "Idempotency-Key: close-period-2026-06-v7" \
+  --data '{
    "readiness_version": 12,
    "decision_maker_id": "user_controller",
    "reason": "June close checklist reviewed and approved"
  }'
Planned response
{
  "data": {
    "id": "op_close_01k5...",
    "type": "reporting_period.close",
    "status": "queued",
    "target": {
      "type": "reporting_period",
      "id": "period_2026_06",
      "expected_version": 7
    },
    "submitted_by": "api_key_123",
    "decision_maker_id": "user_controller",
    "submitted_at": "2026-07-16T14:22:04Z"
  }
}

GraphQL

Proposed graph

Planned

Types

ReportingPeriod
CloseReadiness
CloseException
CloseTask
PeriodSnapshot
Operation

Queries

reportingPeriod(id: ID!): ReportingPeriod
reportingPeriods(filter: ReportingPeriodFilter, pagination: PaginationInput): ReportingPeriodConnection!
operation(id: ID!): Operation

No GraphQL mutations planned

Lock, close, reopen, and export remain explicit REST commands. GraphQL cannot initiate or approve financial lifecycle transitions.
Planned GraphQL query
query PeriodCloseReadiness($id: ID!) {
  reportingPeriod(id: $id) {
    id
    label
    state
    version
    readiness {
      version
      ready
      blockingCount
      warningCount
      tasks { id title state blocking owner { id displayName } }
      exceptions { id code severity message canWaive }
    }
    latestSnapshot { id createdAt checksum }
    allowedActions { id label requiresConfirmation requiredScope }
  }
}

MCP / Agent API

Proposed tools

Planned

Get close readiness

get_close_readiness
Planned

Read the current period, checklist, exceptions, waivers, and allowed human actions.

Scope
period-close:read
Input
Reporting period id.
Output
Bounded readiness summary with evidence references and version.
Write boundary
Read only.

Explain a close exception

explain_close_exception
Planned

Explain one blocking or warning exception using governed evidence.

Scope
period-close:read
Input
Reporting period id and exception id.
Output
Explanation, affected records, remediation options, and source references.
Write boundary
Read only; never waives or resolves the exception.

Prepare a close request

prepare_close_request
Planned

Validate readiness and prepare the exact REST command for a named controller.

Scope
period-close:close
Input
Period id, expected version, readiness version, decision maker, and reason.
Output
A non-executing request package with validation results and command preview.
Write boundary
The agent cannot submit, approve, or execute close.

Get operation status

get_operation_status
Planned

Read a close, reopen, or export operation and its terminal result.

Scope
period-close:read
Input
Operation id.
Output
Operation state, timestamps, error code, and result references.
Write boundary
Read only; cancellation is not exposed until the domain defines a safe window.
Planned agent workflow
User: Are we ready to close June, and what would closing it do?

1. Call get_close_readiness for period_2026_06.
2. Call explain_close_exception for each blocking exception the user asks about.
3. If readiness passes, call prepare_close_request with the named controller and current versions.
4. Show the immutable snapshot, locked-data, and downstream export consequences.
5. Hand the prepared request to the authorized human workflow.

Never call the close or reopen REST command from MCP.

Webhooks

Proposed event catalog

Planned

Event types

reporting_period.openedplanned event

A reporting period became open for operational activity.

payload: reporting_period_id, period_start, period_end, opened_at

reporting_period.lockedplanned event

An authorized operator locked the period.

payload: reporting_period_id, version, locked_by, locked_at

reporting_period.unlockedplanned event

An authorized operator returned the period to open before close began.

payload: reporting_period_id, version, unlocked_by, unlocked_at

reporting_period.closedplanned event

The atomic close completed and produced an immutable snapshot.

payload: reporting_period_id, snapshot_id, close_operation_id, version, closed_at

reporting_period.reopenedplanned event

An authorized reopen completed with a durable reason.

payload: reporting_period_id, reopen_operation_id, reason_code, version, reopened_at

snapshot.completedplanned event

Snapshot materialization completed successfully.

payload: snapshot_id, reporting_period_id, checksum, completed_at

snapshot.failedplanned event

Snapshot materialization failed without closing the period.

payload: reporting_period_id, operation_id, error_code, failed_at

export.completedplanned event

A requested snapshot export became available.

payload: export_id, snapshot_id, format, operation_id, completed_at

export.failedplanned event

A requested export failed.

payload: export_id, snapshot_id, operation_id, error_code, failed_at

Planned event example
{
  "event_id": "evt_01k5...",
  "type": "reporting_period.closed",
  "event_version": 1,
  "occurred_at": "2026-07-16T14:24:31Z",
  "workspace_id": "ws_abc123",
  "resource": {
    "type": "reporting_period",
    "id": "period_2026_06"
  },
  "actor": {
    "id": "user_controller"
  },
  "payload": {
    "reporting_period_id": "period_2026_06",
    "snapshot_id": "snapshot_01k5...",
    "close_operation_id": "op_close_01k5...",
    "version": 8,
    "closed_at": "2026-07-16T14:24:31Z"
  },
  "source": null
}

Connected Apps

Proposed connection roles

Planned

Claude / ChatGPT / IDE clients

Consumer application

Explain readiness and prepare a non-executing close request.

Authority: Read and prepare only; cannot lock, close, reopen, waive exceptions, or approve.

ERP / accounting systems

Synchronization provider

Receive approved snapshot references or reconcile exported financial facts.

Authority: Outbound after close by default; provider state cannot close or reopen DigitalStack periods.

Data warehouse / BI

Analytics sink

Consume immutable period snapshots and asynchronous exports.

Authority: Read/export only; cannot mutate financial operations or operational records.

Open contract decisions

Resolve before implementation approval

  • Must reopen require two distinct human approvals, or one controller plus an audited reason?
  • What cancellation window, if any, is safe while a close operation is still queued or validating?
  • What retention and redelivery guarantees apply to large snapshot exports?
  • Which readiness warnings can be waived, and which roles may create those waivers?
  • Must reopen require dual approval for enterprise accounts?

Proof obligations

Must remain trueFailure indicator
The reporting-period service remains the singular period-state owner.A worker, GraphQL resolver, MCP tool, or ERP persists an alternate close state.
Close is atomic across validation, snapshot, audit, and event enqueue.A period is closed without a snapshot, audit decision, or durable outbox event.
Closed-period snapshots are immutable.An export or reconciliation flow changes snapshot content or checksum after close.
Close and reopen are attributable human decisions.An agent, schedule, worker, or connector becomes the recorded decision maker.
Failed operations preserve the prior stable state.A failed close leaves the period partially closed or financially inconsistent.
Every command is versioned and idempotent.A stale request overwrites newer state or a retry creates duplicate operations.
Financial data remains separately scoped and minimized.A period read or event leaks invoice, rate, margin, or personal data beyond its declared scope.