{"openapi":"3.1.0","info":{"title":"Accounting Periods — DayZero API","version":"1.0.0","description":"Manage fiscal periods (month/quarter/year) and period locks."},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/accounting-periods":{"get":{"tags":["accounting-periods"],"summary":"List accounting periods","description":"List all accounting periods for the business.","operationId":"list_periods","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: open, closed, locked","title":"Status"},"description":"Filter by status: open, closed, locked"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search status, dates, or lock/reopen reasons (case-insensitive)","title":"Search"},"description":"Search status, dates, or lock/reopen reasons (case-insensitive)"},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Cursor for pagination","title":"Cursor"},"description":"Cursor for pagination"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"description":"Pagination limit","title":"Limit"},"description":"Pagination limit"},{"name":"direction","in":"query","required":false,"schema":{"type":"string","description":"Pagination direction: 'next' or 'prev'","default":"next","title":"Direction"},"description":"Pagination direction: 'next' or 'prev'"},{"name":"include_total_count","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to include total count (expensive - avoid if possible)","default":false,"title":"Include Total Count"},"description":"Whether to include total count (expensive - avoid if possible)"},{"name":"sort_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column name to sort by (e.g. 'created_at', 'amount', 'name'). When changing sort, reset cursor to None.","title":"Sort By"},"description":"Column name to sort by (e.g. 'created_at', 'amount', 'name'). When changing sort, reset cursor to None."},{"name":"descending","in":"query","required":false,"schema":{"type":"boolean","description":"Sort direction: true for descending (newest/largest first), false for ascending","default":true,"title":"Descending"},"description":"Sort direction: true for descending (newest/largest first), false for ascending"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodsListResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"list_periods_api_v1_accounting_periods_get"},"post":{"tags":["accounting-periods"],"summary":"Create accounting period","description":"Create a new accounting period.","operationId":"create_period","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingPeriodCreateRequest"},"example":{"period_end":"2026-01-31","period_start":"2026-01-01"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or is in an incompatible state","content":{"application/json":{"example":{"error":"conflict","message":"Resource already exists","code":"CONFLICT_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"create_period_api_v1_accounting_periods_post"}},"/api/v1/accounting-periods/{period_id}":{"get":{"tags":["accounting-periods"],"summary":"Get accounting period","description":"Get details of a specific accounting period.","operationId":"get_period","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_period_api_v1_accounting_periods__period_id__get"}},"/api/v1/accounting-periods/close":{"post":{"tags":["accounting-periods"],"summary":"Close accounting period","description":"Close an accounting period to prevent modifications.","operationId":"close_period","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClosePeriodRequest"},"example":{"lock_reason":"Month-end close completed","period_end":"2026-01-31"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"close_period_api_v1_accounting_periods_close_post"}},"/api/v1/accounting-periods/{period_id}/lock":{"post":{"tags":["accounting-periods"],"summary":"Lock accounting period","description":"Lock a closed period (stronger protection than close).","operationId":"lock_period","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"lock_period_api_v1_accounting_periods__period_id__lock_post"}},"/api/v1/accounting-periods/bulk-lock":{"post":{"tags":["accounting-periods"],"summary":"Bulk close-and-lock accounting periods","description":"Close and lock multiple accounting periods in one call. Designed for historical-data migration: any open period in the list is closed first, then transitioned to locked. Already-locked periods are skipped.","operationId":"bulk_lock_periods","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkLockPeriodsRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_BulkLockPeriodsResult_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"bulk_lock_periods_api_v1_accounting_periods_bulk_lock_post"}},"/api/v1/accounting-periods/{period_id}/reopen":{"post":{"tags":["accounting-periods"],"summary":"Reopen accounting period","description":"Reopen a closed or locked period (requires reason).","operationId":"reopen_period","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReopenPeriodRequest"},"example":{"reopen_reason":"Need to correct a journal entry from January"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AccountingPeriodResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"reopen_period_api_v1_accounting_periods__period_id__reopen_post"}},"/api/v1/accounting-periods/{period_id}/close-readiness":{"post":{"tags":["accounting-periods"],"summary":"AI close readiness check","description":"Check period close readiness with AI-enhanced analysis.","operationId":"check_close_readiness","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CloseReadinessResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"check_close_readiness_api_v1_accounting_periods__period_id__close_readiness_post"}},"/api/v1/accounting-periods/{period_id}/checklist-acks":{"get":{"tags":["accounting-periods"],"summary":"List checklist acknowledgements","description":"Return all manual checklist step acknowledgements recorded for the period. Used by the close dashboard so Phase 4 'trial balance reviewed', 'P&L variance reviewed', 'controller signed off' etc. persist across page refreshes.","operationId":"list_period_checklist_acks","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CloseChecklistAcksListResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"list_period_checklist_acks_api_v1_accounting_periods__period_id__checklist_acks_get"}},"/api/v1/accounting-periods/{period_id}/checklist-acks/{step_id}":{"put":{"tags":["accounting-periods"],"summary":"Acknowledge a checklist step","description":"Record (or update) a manual-step ack so the dashboard treats the step as done. Idempotent — re-calling updates the notes.","operationId":"acknowledge_checklist_step","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"step_id","in":"path","required":true,"schema":{"type":"string","title":"Step Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcknowledgeCloseStepRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CloseChecklistAckResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"acknowledge_checklist_step_api_v1_accounting_periods__period_id__checklist_acks__step_id__put"},"delete":{"tags":["accounting-periods"],"summary":"Remove a checklist acknowledgement","description":"Clear a previously-recorded checklist step ack for a period.","operationId":"unacknowledge_checklist_step","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"step_id","in":"path","required":true,"schema":{"type":"string","title":"Step Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__core__success__MessageResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"unacknowledge_checklist_step_api_v1_accounting_periods__period_id__checklist_acks__step_id__delete"}},"/api/v1/accounting-periods/{period_id}/close-score":{"get":{"tags":["accounting-periods"],"summary":"Get unified close readiness score","description":"Return the persisted close-as-score gauge value for the period. If no score has been computed yet (or upstream state has changed) the score is recomputed in-line. Components include: txn_review, categorization, reconciliation, checklist, anomalies.","operationId":"get_close_score","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetCloseScoreResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_close_score_api_v1_accounting_periods__period_id__close_score_get"}},"/api/v1/accounting-periods/{period_id}/close-score/recompute":{"post":{"tags":["accounting-periods"],"summary":"Force-recompute close score","description":"Re-run scoring for the period and persist the new value. Use this after resolving a blocker (e.g. dismissing the last anomaly) so the gauge updates immediately rather than waiting for the nightly Temporal recompute.","operationId":"recompute_close_score","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_RecomputeCloseScoreResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"recompute_close_score_api_v1_accounting_periods__period_id__close_score_recompute_post"}},"/api/v1/accounting-periods/{period_id}/blockers":{"get":{"tags":["accounting-periods"],"summary":"List what's blocking close","description":"Return only the itemized 'What's between you and 100%' blockers list ordered by severity. Used by the AccountingPeriodsPage side panel and the Daily Brief tile.","operationId":"list_close_blockers","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ListCloseBlockersResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"list_close_blockers_api_v1_accounting_periods__period_id__blockers_get"}},"/api/v1/accounting-periods/{period_id}/score-history":{"get":{"tags":["accounting-periods"],"summary":"Daily close-score trend","description":"Return the append-only daily snapshot of close score for this period (oldest first). Powers the 'Day 1 → Day 6' sparkline.","operationId":"get_score_history","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":60,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetScoreHistoryResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_score_history_api_v1_accounting_periods__period_id__score_history_get"}},"/api/v1/accounting-periods/{period_id}/sign-offs":{"get":{"tags":["accounting-periods"],"summary":"List multi-reviewer sign-offs","description":"Return all sign-off rows for the period (preparer, reviewer, controller, partner). Powers the Multi-reviewer sign-off badge on the AccountingPeriodsPage.","operationId":"list_period_sign_offs","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ListPeriodSignOffsResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"list_period_sign_offs_api_v1_accounting_periods__period_id__sign_offs_get"},"post":{"tags":["accounting-periods"],"summary":"Record a reviewer sign-off","description":"Record (or update) a reviewer's sign-off on the period. Idempotent on (user_id, role) — re-signing refreshes the snapshot score + notes. Side-effect: triggers a close-score recompute so the gauge updates immediately.","operationId":"create_period_sign_off","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignOffRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CreatePeriodSignOffResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"create_period_sign_off_api_v1_accounting_periods__period_id__sign_offs_post"},"delete":{"tags":["accounting-periods"],"summary":"Revoke a reviewer sign-off","description":"Remove the caller's sign-off for the given role. The close-score is recomputed on success so the gauge reflects the lost sign-off.","operationId":"delete_period_sign_off","parameters":[{"name":"period_id","in":"path","required":true,"schema":{"type":"string","title":"Period Id"}},{"name":"role","in":"query","required":true,"schema":{"type":"string","description":"Role to revoke (preparer/reviewer/...)","title":"Role"},"description":"Role to revoke (preparer/reviewer/...)"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__core__success__MessageResponse"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"error":"not_found","message":"Resource not found","code":"NOT_FOUND_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"delete_period_sign_off_api_v1_accounting_periods__period_id__sign_offs_delete"}}},"components":{"schemas":{"AccountingPeriodCreateRequest":{"properties":{"period_start":{"type":"string","format":"date","title":"Period Start","description":"Start date of the accounting period"},"period_end":{"type":"string","format":"date","title":"Period End","description":"End date of the accounting period"}},"type":"object","required":["period_start","period_end"],"title":"AccountingPeriodCreateRequest","description":"Request schema for creating an accounting period.","example":{"period_end":"2026-01-31","period_start":"2026-01-01"},"examples":[{"period_end":"2026-01-31","period_start":"2026-01-01"}]},"AccountingPeriodResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Period UUID"},"business_id":{"type":"string","title":"Business Id","description":"Business UUID"},"period_start":{"type":"string","format":"date","title":"Period Start","description":"Start date of the period"},"period_end":{"type":"string","format":"date","title":"Period End","description":"End date of the period"},"status":{"type":"string","title":"Status","description":"Status: open, closed, or locked"},"closed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Closed At","description":"When period was closed"},"closed_by_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Closed By User Id","description":"User who closed the period"},"lock_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lock Reason","description":"Reason period was closed"},"reopen_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reopen Reason","description":"Reason period was reopened"},"reopened_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reopened At","description":"When period was reopened"},"reopened_by_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reopened By User Id","description":"User who reopened the period"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["id","business_id","period_start","period_end","status","created_at","updated_at"],"title":"AccountingPeriodResponse","description":"Response schema for an accounting period."},"AccountingPeriodsListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AccountingPeriodResponse"},"type":"array","title":"Items","description":"List of items"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Total number of items (null when not calculated for performance)"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit","description":"Pagination limit"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor for next page"},"prev_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prev Cursor","description":"Cursor for previous page"},"has_next":{"type":"boolean","title":"Has Next","description":"Whether there are more items"},"has_prev":{"type":"boolean","title":"Has Prev","description":"Whether there are previous items"}},"type":"object","required":["items","has_next","has_prev"],"title":"AccountingPeriodsListResponse","description":"Paginated list of accounting periods."},"AcknowledgeCloseStepRequest":{"properties":{"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional free-form note"}},"type":"object","title":"AcknowledgeCloseStepRequest","description":"Body for upserting a close-checklist acknowledgement."},"BulkLockPeriodsRequest":{"properties":{"period_ids":{"items":{"type":"string"},"type":"array","maxItems":120,"minItems":1,"title":"Period Ids","description":"Period UUIDs to lock"},"lock_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lock Reason","description":"Reason recorded on each period. Defaults to 'Historical migration - bulk locked' when omitted."}},"type":"object","required":["period_ids"],"title":"BulkLockPeriodsRequest","description":"Bulk-close-and-lock a list of accounting periods.\n\nIntended for historical-data migration where the user already\nreviewed the months offline and just wants the periods locked."},"BulkLockPeriodsResult":{"properties":{"locked_count":{"type":"integer","minimum":0.0,"title":"Locked Count","description":"Periods that ended up locked"},"skipped_count":{"type":"integer","minimum":0.0,"title":"Skipped Count","description":"Periods skipped (already locked / not found)"},"locked_ids":{"items":{"type":"string"},"type":"array","title":"Locked Ids"},"skipped":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Skipped","description":"Per-period skip info: {period_id, reason}"}},"type":"object","required":["locked_count","skipped_count"],"title":"BulkLockPeriodsResult","description":"Outcome of a bulk lock operation."},"CloseChecklistAckResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Ack row UUID"},"business_id":{"type":"string","title":"Business Id","description":"Business UUID"},"period_start":{"type":"string","format":"date","title":"Period Start","description":"Period start the ack is keyed to"},"step_id":{"type":"string","title":"Step Id","description":"Checklist step ID (e.g. trial_balance_review)"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional free-form note"},"acked_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acked By","description":"User who acknowledged"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the ack was first recorded"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When the ack was last updated"}},"type":"object","required":["id","business_id","period_start","step_id","created_at","updated_at"],"title":"CloseChecklistAckResponse","description":"A persisted acknowledgement that a manual close step is done."},"CloseChecklistAcksListResponse":{"properties":{"period_id":{"type":"string","title":"Period Id","description":"Period UUID the acks belong to"},"period_start":{"type":"string","format":"date","title":"Period Start","description":"Period start date"},"items":{"items":{"$ref":"#/components/schemas/CloseChecklistAckResponse"},"type":"array","title":"Items"}},"type":"object","required":["period_id","period_start"],"title":"CloseChecklistAcksListResponse","description":"List of acknowledgements for a single period."},"ClosePeriodRequest":{"properties":{"period_end":{"type":"string","format":"date","title":"Period End","description":"End date of the period to close"},"lock_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lock Reason","description":"Reason for closing the period"},"force":{"type":"boolean","title":"Force","description":"Bypass soft client-side blockers (unresolved checklist items) and force the close. Backend still rejects already-closed periods. Required for historical migration when the period was reviewed offline.","default":false}},"type":"object","required":["period_end"],"title":"ClosePeriodRequest","description":"Request schema for closing an accounting period.","example":{"lock_reason":"Month-end close completed","period_end":"2026-01-31"},"examples":[{"lock_reason":"Month-end close completed","period_end":"2026-01-31"}]},"CloseReadinessItem":{"properties":{"check":{"type":"string","title":"Check","description":"Name of the readiness check"},"status":{"type":"string","title":"Status","description":"pass, warning, or fail"},"detail":{"type":"string","title":"Detail","description":"Explanation"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count","description":"Number of items flagged"}},"type":"object","required":["check","status","detail"],"title":"CloseReadinessItem"},"CloseReadinessResponse":{"properties":{"score":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Score","description":"Overall readiness score 0-100"},"items":{"items":{"$ref":"#/components/schemas/CloseReadinessItem"},"type":"array","title":"Items"},"summary":{"$ref":"#/components/schemas/CloseReadinessSummary","description":"Period-scoped transaction counts to power dashboards without extra fetches"}},"type":"object","required":["score"],"title":"CloseReadinessResponse"},"CloseReadinessSummary":{"properties":{"transaction_count":{"type":"integer","minimum":0.0,"title":"Transaction Count","description":"Total non-deleted transactions in the period","default":0},"unreviewed_count":{"type":"integer","minimum":0.0,"title":"Unreviewed Count","description":"Transactions in the period that are still unreviewed","default":0},"uncategorized_count":{"type":"integer","minimum":0.0,"title":"Uncategorized Count","description":"Transactions in the period that are still uncategorized","default":0},"missing_receipt_count":{"type":"integer","minimum":0.0,"title":"Missing Receipt Count","description":"Expenses in the period that the receipt policy asks a receipt for and that have none (including ones requested from the client)","default":0}},"type":"object","title":"CloseReadinessSummary","description":"Period-scoped totals computed alongside the readiness checks."},"CloseScoreBlocker":{"properties":{"category":{"type":"string","title":"Category"},"severity":{"type":"string","title":"Severity"},"label":{"type":"string","title":"Label"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count"}},"additionalProperties":true,"type":"object","required":["category","severity","label"],"title":"CloseScoreBlocker","description":"Item blocking the period close score from reaching 100."},"CloseScoreHistoryEntry":{"properties":{"snapshot_date":{"type":"string","title":"Snapshot Date"},"score":{"type":"number","title":"Score"},"color":{"type":"string","title":"Color"}},"additionalProperties":true,"type":"object","required":["snapshot_date","score","color"],"title":"CloseScoreHistoryEntry","description":"Daily close-score snapshot for trend charts."},"CreatePeriodSignOffResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"role":{"type":"string","title":"Role"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"signed_off_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed Off At"},"score_at_signoff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score At Signoff"}},"additionalProperties":true,"type":"object","required":["id","user_id","role"],"title":"CreatePeriodSignOffResponse","description":"Response for ``create_period_sign_off``."},"GetCloseScoreResponse":{"properties":{"id":{"type":"string","title":"Id"},"period_id":{"type":"string","title":"Period Id"},"score":{"type":"number","title":"Score"},"color":{"type":"string","title":"Color"},"components":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Components"},"blockers":{"items":{"$ref":"#/components/schemas/CloseScoreBlocker"},"type":"array","title":"Blockers"},"last_computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Computed At"}},"additionalProperties":true,"type":"object","required":["id","period_id","score","color","components","blockers"],"title":"GetCloseScoreResponse","description":"Response for ``get_close_score`` / ``recompute_close_score``."},"GetScoreHistoryResponse":{"properties":{"period_id":{"type":"string","title":"Period Id"},"history":{"items":{"$ref":"#/components/schemas/CloseScoreHistoryEntry"},"type":"array","title":"History"}},"additionalProperties":true,"type":"object","required":["period_id","history"],"title":"GetScoreHistoryResponse","description":"Response for ``get_score_history``."},"ListCloseBlockersResponse":{"properties":{"period_id":{"type":"string","title":"Period Id"},"score":{"type":"number","title":"Score"},"color":{"type":"string","title":"Color"},"blockers":{"items":{"$ref":"#/components/schemas/CloseScoreBlocker"},"type":"array","title":"Blockers"}},"additionalProperties":true,"type":"object","required":["period_id","score","color","blockers"],"title":"ListCloseBlockersResponse","description":"Response for ``list_close_blockers``."},"ListPeriodSignOffsResponse":{"properties":{"period_id":{"type":"string","title":"Period Id"},"sign_offs":{"items":{"$ref":"#/components/schemas/PeriodSignOffItem"},"type":"array","title":"Sign Offs"}},"additionalProperties":true,"type":"object","required":["period_id","sign_offs"],"title":"ListPeriodSignOffsResponse","description":"Response for ``list_period_sign_offs``."},"PeriodSignOffItem":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"role":{"type":"string","title":"Role"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"signed_off_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed Off At"},"score_at_signoff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score At Signoff"}},"additionalProperties":true,"type":"object","required":["id","user_id","role"],"title":"PeriodSignOffItem","description":"Multi-reviewer sign-off on a period."},"RecomputeCloseScoreResponse":{"properties":{"id":{"type":"string","title":"Id"},"period_id":{"type":"string","title":"Period Id"},"score":{"type":"number","title":"Score"},"color":{"type":"string","title":"Color"},"components":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Components"},"blockers":{"items":{"$ref":"#/components/schemas/CloseScoreBlocker"},"type":"array","title":"Blockers"},"last_computed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Computed At"}},"additionalProperties":true,"type":"object","required":["id","period_id","score","color","components","blockers"],"title":"RecomputeCloseScoreResponse","description":"Response for ``recompute_close_score`` (same shape as get)."},"ReopenPeriodRequest":{"properties":{"reopen_reason":{"type":"string","title":"Reopen Reason","description":"Reason for reopening the period (required)"}},"type":"object","required":["reopen_reason"],"title":"ReopenPeriodRequest","description":"Request schema for reopening a closed accounting period.","example":{"reopen_reason":"Need to correct a journal entry from January"},"examples":[{"reopen_reason":"Need to correct a journal entry from January"}]},"SignOffRequest":{"properties":{"role":{"type":"string","maxLength":40,"minLength":1,"title":"Role","description":"Role of the reviewer signing off (preparer, reviewer, controller, partner)."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional reviewer notes captured at sign-off."}},"type":"object","required":["role"],"title":"SignOffRequest"},"SuccessEnvelope_AccountingPeriodResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/AccountingPeriodResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[AccountingPeriodResponse]"},"SuccessEnvelope_AccountingPeriodsListResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/AccountingPeriodsListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[AccountingPeriodsListResponse]"},"SuccessEnvelope_BulkLockPeriodsResult_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/BulkLockPeriodsResult"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[BulkLockPeriodsResult]"},"SuccessEnvelope_CloseChecklistAckResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CloseChecklistAckResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CloseChecklistAckResponse]"},"SuccessEnvelope_CloseChecklistAcksListResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CloseChecklistAcksListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CloseChecklistAcksListResponse]"},"SuccessEnvelope_CloseReadinessResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CloseReadinessResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CloseReadinessResponse]"},"SuccessEnvelope_CreatePeriodSignOffResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CreatePeriodSignOffResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CreatePeriodSignOffResponse]"},"SuccessEnvelope_GetCloseScoreResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetCloseScoreResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetCloseScoreResponse]"},"SuccessEnvelope_GetScoreHistoryResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetScoreHistoryResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetScoreHistoryResponse]"},"SuccessEnvelope_ListCloseBlockersResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ListCloseBlockersResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ListCloseBlockersResponse]"},"SuccessEnvelope_ListPeriodSignOffsResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ListPeriodSignOffsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ListPeriodSignOffsResponse]"},"SuccessEnvelope_RecomputeCloseScoreResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/RecomputeCloseScoreResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[RecomputeCloseScoreResponse]"},"app__core__success__MessageResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},"additionalProperties":true,"type":"object","title":"MessageResponse","description":"Envelope for data-less mutations: ``{success, message, code}``, no ``data``.\n\nCanonical ``response_model`` for deletes and other message-only mutations so\nthe generated TypeScript client gets a single, named ``MessageResponse`` type\ninstead of dozens of empty per-route stubs. Pairs with the\n``SuccessResponse.*`` builders (which already emit this exact shape)."},"ErrorResponse":{"title":"ErrorResponse","type":"object","description":"Envelope returned by every non-2xx response. Branch on `code` (stable) rather than `message` (human-readable, may change).","required":["error","message","code"],"properties":{"error":{"type":"string","description":"Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`."},"message":{"type":"string","description":"Human-readable explanation, safe to show to end users."},"code":{"type":"string","description":"Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`)."},"request_id":{"type":"string","description":"Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied."},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Field-level validation messages keyed by field name. Present on 400/422 validation failures only."}}}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Token","description":"API token authentication. Format: `Bearer dz_...`"}}},"security":[{"BearerAuth":[]}]}