{"openapi":"3.1.0","info":{"title":"AP Approval — DayZero API","version":"1.0.0","description":"Accounts payable approval workflows for bill review and authorization."},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/ap-approval":{"get":{"tags":["ap-approval"],"summary":"Get AP approval workflow","description":"Get the AP approval workflow for the current business's firm.","operationId":"get_ap_approval_workflow","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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ApApprovalGetResponse_"}}}},"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_ap_approval_workflow_api_v1_ap_approval_get"}},"/api/v1/ap-approval/provision":{"post":{"tags":["ap-approval"],"summary":"Provision AP approval workflow for firm","description":"Create or retrieve the AP approval workflow for the firm associated with this business.","operationId":"provision_ap_approval_workflow","parameters":[{"name":"auto_approve_max_cents","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Max amount in cents for auto-approval (default: $500)","default":50000,"title":"Auto Approve Max Cents"},"description":"Max amount in cents for auto-approval (default: $500)"},{"name":"ops_approve_max_cents","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Max amount in cents for ops approval (default: $5,000)","default":500000,"title":"Ops Approve Max Cents"},"description":"Max amount in cents for ops approval (default: $5,000)"},{"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_ApApprovalProvisionResponse_"}}}},"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":"provision_ap_approval_workflow_api_v1_ap_approval_provision_post"}},"/api/v1/ap-approval/pending":{"get":{"tags":["ap-approval"],"summary":"List pending AP approvals","description":"List bills currently suspended at an AP approval gate.","operationId":"list_pending_approvals","parameters":[{"name":"tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a specific tier: 'ops', 'advisor', or 'owner'.","title":"Tier"},"description":"Filter to a specific tier: 'ops', 'advisor', or 'owner'."},{"name":"mine","in":"query","required":false,"schema":{"type":"boolean","description":"When true, only show approvals whose gate tier the caller is configured as an approver for.","default":false,"title":"Mine"},"description":"When true, only show approvals whose gate tier the caller is configured as an approver for."},{"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_PendingApprovalsResponse_"}}}},"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_pending_approvals_api_v1_ap_approval_pending_get"}},"/api/v1/ap-approval/completed":{"get":{"tags":["ap-approval"],"summary":"List completed AP approvals","description":"List recently approved or rejected bills that have left the pending queue (their workflow run reached a terminal state).","operationId":"list_completed_approvals","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Maximum number of completed rows to return.","default":50,"title":"Limit"},"description":"Maximum number of completed rows to return."},{"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_CompletedApprovalsResponse_"}}}},"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_completed_approvals_api_v1_ap_approval_completed_get"}},"/api/v1/ap-approval/approvers":{"get":{"tags":["ap-approval"],"summary":"Get approvers by tier","description":"Return the configured approver user IDs grouped by tier.","operationId":"get_approvers","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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ApproversResponse_"}}}},"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_approvers_api_v1_ap_approval_approvers_get"}},"/api/v1/ap-approval/approvers/{tier}":{"put":{"tags":["ap-approval"],"summary":"Update approvers for a tier","description":"Replace the approver list for a tier in the workflow graph.","operationId":"update_approvers","parameters":[{"name":"tier","in":"path","required":true,"schema":{"type":"string","title":"Tier"}},{"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/SetApproversRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ApproversResponse_"}}}},"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":"update_approvers_api_v1_ap_approval_approvers__tier__put"}},"/api/v1/ap-approval/thresholds":{"patch":{"tags":["ap-approval"],"summary":"Update approval thresholds","description":"Update amount thresholds and/or escalation timeout without re-provisioning. Only provided fields are changed; the rest retain their current values.","operationId":"update_thresholds","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/UpdateThresholdsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_UpdateThresholdsResponse_"}}}},"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":"update_thresholds_api_v1_ap_approval_thresholds_patch"}},"/api/v1/ap-approval/batch-approve":{"post":{"tags":["ap-approval"],"summary":"Batch approve pending items","description":"Approve multiple suspended workflow executions in a single request.","operationId":"batch_approve","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/BatchApproveRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_BatchApproveResponse_"}}}},"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":"batch_approve_api_v1_ap_approval_batch_approve_post"}},"/api/v1/ap-approval/vendor/{vendor_id}/history":{"get":{"tags":["ap-approval"],"summary":"Vendor payment history","description":"Return recent bill history for a vendor to provide context at approval time.","operationId":"get_vendor_history","parameters":[{"name":"vendor_id","in":"path","required":true,"schema":{"type":"string","title":"Vendor Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Number of recent bills to return.","default":10,"title":"Limit"},"description":"Number of recent bills to return."},{"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_VendorHistoryResponse_"}}}},"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":"get_vendor_history_api_v1_ap_approval_vendor__vendor_id__history_get"}},"/api/v1/ap-approval/analytics":{"get":{"tags":["ap-approval"],"summary":"Approval queue analytics","description":"Return queue health stats: pending counts by tier, average age, and oldest pending item.","operationId":"get_analytics","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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AnalyticsResponse_"}}}},"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":"get_analytics_api_v1_ap_approval_analytics_get"}},"/api/v1/ap-approval/risk-score":{"post":{"tags":["ap-approval"],"summary":"AI approval risk scores","description":"Get AI-powered risk scores for pending bill approvals.","operationId":"score_approval_risk","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"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ApprovalRiskResponse_"}}}},"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":"score_approval_risk_api_v1_ap_approval_risk_score_post"}}},"components":{"schemas":{"AnalyticsResponse":{"properties":{"pending_count":{"type":"integer","title":"Pending Count","description":"Total suspended approval executions."},"pending_by_tier":{"additionalProperties":{"type":"integer"},"type":"object","title":"Pending By Tier","description":"Suspended count per tier (ops, advisor, owner)."},"avg_pending_age_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Pending Age Hours","description":"Average age of pending items in hours. Null when queue is empty."},"oldest_pending_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Oldest Pending Hours","description":"Age of the oldest pending item in hours. Null when queue is empty."},"workflow_enabled":{"type":"boolean","title":"Workflow Enabled","description":"Whether an AP approval workflow is provisioned for this business."}},"type":"object","required":["pending_count","workflow_enabled"],"title":"AnalyticsResponse","description":"Response for ``GET /ap-approval/analytics``.\n\nProvides a snapshot of the current approval queue health for the business."},"ApApprovalGetResponse":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"True when a published workflow exists for the firm."},"workflow":{"anyOf":[{"$ref":"#/components/schemas/ApApprovalWorkflowSummary"},{"type":"null"}],"description":"Workflow summary, or null when not enabled."}},"type":"object","required":["enabled"],"title":"ApApprovalGetResponse","description":"Response for ``GET /ap-approval``.\n\n``enabled=False`` means the firm hasn't provisioned a workflow yet; the\npage should offer a \"Set up approval policy\" CTA."},"ApApprovalProvisionResponse":{"properties":{"workflow_id":{"type":"string","title":"Workflow Id","description":"Provisioned workflow UUID."},"name":{"type":"string","title":"Name","description":"Workflow name."},"is_published":{"type":"boolean","title":"Is Published","description":"Whether the workflow is published."},"version":{"type":"integer","title":"Version","description":"Workflow version."},"graph":{"$ref":"#/components/schemas/WorkflowGraphSchema-Output","description":"Workflow graph."},"auto_approve_max_cents":{"type":"integer","title":"Auto Approve Max Cents","description":"Auto-approve threshold in cents."},"ops_approve_max_cents":{"type":"integer","title":"Ops Approve Max Cents","description":"Ops approval threshold in cents."}},"type":"object","required":["workflow_id","name","is_published","version","graph","auto_approve_max_cents","ops_approve_max_cents"],"title":"ApApprovalProvisionResponse","description":"Response for ``POST /ap-approval/provision``."},"ApApprovalWorkflowSummary":{"properties":{"id":{"type":"string","title":"Id","description":"Workflow UUID."},"name":{"type":"string","title":"Name","description":"Human-readable workflow name."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Workflow description."},"graph":{"$ref":"#/components/schemas/WorkflowGraphSchema-Output","description":"Workflow graph (nodes + edges)."},"is_published":{"type":"boolean","title":"Is Published","description":"Whether the workflow is published."},"version":{"type":"integer","title":"Version","description":"Workflow version (monotonic)."},"auto_approve_max_cents":{"type":"integer","title":"Auto Approve Max Cents","description":"Max bill amount (cents) eligible for auto-approval."},"ops_approve_max_cents":{"type":"integer","title":"Ops Approve Max Cents","description":"Max bill amount (cents) routed to operations approval. Bills above this require advisor + owner sign-off."}},"type":"object","required":["id","name","graph","is_published","version","auto_approve_max_cents","ops_approve_max_cents"],"title":"ApApprovalWorkflowSummary","description":"Summary of a provisioned AP approval workflow."},"ApprovalRiskItem":{"properties":{"bill_id":{"type":"string","title":"Bill Id","description":"Bill UUID (as string)."},"vendor_name":{"type":"string","title":"Vendor Name","description":"Vendor name as resolved at scoring time.","default":""},"amount":{"anyOf":[{"type":"number"},{"type":"integer"}],"title":"Amount","description":"Amount in dollars (display value).","default":0},"risk_score":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Risk Score","description":"Risk score (0-100, higher = riskier).","default":0},"risk_factors":{"items":{"type":"string"},"type":"array","title":"Risk Factors","description":"Up to 3 short risk factor strings."}},"type":"object","required":["bill_id"],"title":"ApprovalRiskItem","description":"One AI-scored bill in the approval risk queue."},"ApprovalRiskResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ApprovalRiskItem"},"type":"array","title":"Items","description":"Risk-scored bills."}},"type":"object","title":"ApprovalRiskResponse","description":"Response for ``POST /ap-approval/risk-score``."},"ApproversResponse":{"properties":{"approvers":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Approvers","description":"Approver user IDs grouped by tier ('ops', 'advisor', 'owner')."}},"type":"object","title":"ApproversResponse","description":"Response for ``GET /ap-approval/approvers`` and the PUT counterpart.\n\n``approvers`` is a map from tier name → list of user UUID strings. Tiers\nwith no approvers configured are absent (or empty), and the run-time\nenforcement falls back to business authority (any business owner or\nadmin may respond) for those tiers."},"BatchApproveRequest":{"properties":{"execution_ids":{"items":{"type":"string"},"type":"array","maxItems":50,"minItems":1,"title":"Execution Ids","description":"List of workflow execution UUIDs to approve."},"comment":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Comment","description":"Optional comment applied to all approvals in the batch."}},"type":"object","required":["execution_ids"],"title":"BatchApproveRequest","description":"Body for ``POST /ap-approval/batch-approve``."},"BatchApproveResponse":{"properties":{"total":{"type":"integer","title":"Total","description":"Total executions submitted."},"succeeded":{"type":"integer","title":"Succeeded","description":"Number of successful approvals."},"failed":{"type":"integer","title":"Failed","description":"Number of failed approvals."},"results":{"items":{"$ref":"#/components/schemas/BatchApproveResultItem"},"type":"array","title":"Results","description":"Per-execution results."}},"type":"object","required":["total","succeeded","failed"],"title":"BatchApproveResponse","description":"Response for ``POST /ap-approval/batch-approve``."},"BatchApproveResultItem":{"properties":{"execution_id":{"type":"string","title":"Execution Id","description":"Execution UUID."},"success":{"type":"boolean","title":"Success","description":"Whether this approval succeeded."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if the approval failed."}},"type":"object","required":["execution_id","success"],"title":"BatchApproveResultItem","description":"Result for a single execution in a batch-approve request."},"CompletedApprovalItem":{"properties":{"execution_id":{"type":"string","title":"Execution Id","description":"Workflow execution UUID."},"workflow_id":{"type":"string","title":"Workflow Id","description":"AP approval workflow UUID."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Tier at which the final decision was recorded."},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"Final human decision: 'approve' or 'reject'."},"comment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment","description":"Comment attached to the final decision, if any."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"ISO timestamp when the run reached its terminal state."},"bill":{"$ref":"#/components/schemas/PendingApprovalBill","description":"Bill the run decided on."}},"type":"object","required":["execution_id","workflow_id","bill"],"title":"CompletedApprovalItem","description":"One AP approval run that has left the pending queue.\n\nBacked by a workflow execution in a terminal ``completed`` state — the bill\nwas either approved through its final gate or rejected. Surfaces the final\nhuman decision so the \"Completed\" view can show what happened and when."},"CompletedApprovalsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CompletedApprovalItem"},"type":"array","title":"Items","description":"Recently completed approval rows, newest first."}},"type":"object","title":"CompletedApprovalsResponse","description":"Response for ``GET /ap-approval/completed``."},"PendingApprovalBill":{"properties":{"id":{"type":"string","title":"Id","description":"Bill UUID (as string)."},"amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amount","description":"Bill amount in cents (0 when unavailable)."},"vendor_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Id","description":"Vendor UUID, if set on the bill."},"vendor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Name","description":"Resolved vendor name."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Bill description."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Bill status name."}},"type":"object","required":["id"],"title":"PendingApprovalBill","description":"Trimmed bill payload embedded in pending approval items."},"PendingApprovalItem":{"properties":{"execution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Execution Id","description":"Workflow execution UUID. Null for an orphaned ``pending_approval`` bill that has no live execution yet (``needs_routing``)."},"workflow_id":{"type":"string","title":"Workflow Id","description":"AP approval workflow UUID."},"node_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Node Id","description":"Approval gate node id the run is waiting on."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Tier of the suspended gate ('ops', 'advisor', 'owner')."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Human-readable label of the suspended gate."},"suspended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suspended At","description":"ISO timestamp when execution was suspended."},"needs_routing":{"type":"boolean","title":"Needs Routing","description":"True when this is a ``pending_approval`` bill with no live execution — it is being (re)routed into the workflow and is not yet actionable from the queue.","default":false},"bill":{"$ref":"#/components/schemas/PendingApprovalBill","description":"Bill awaiting approval."}},"type":"object","required":["workflow_id","bill"],"title":"PendingApprovalItem","description":"One AP approval item waiting on human input.\n\nUsually backed by a suspended workflow execution. Bills whose status is\n``pending_approval`` but which have no live execution (the run never\nstarted or never suspended) are also surfaced here with\n``needs_routing=True`` and a null ``execution_id`` so they never silently\nvanish from the queue."},"PendingApprovalsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PendingApprovalItem"},"type":"array","title":"Items","description":"Suspended approval rows, newest first (max 200)."}},"type":"object","title":"PendingApprovalsResponse","description":"Response for ``GET /ap-approval/pending``."},"SetApproversRequest":{"properties":{"user_ids":{"items":{"type":"string"},"type":"array","title":"User Ids","description":"List of user UUIDs to set as approvers for the tier."}},"type":"object","title":"SetApproversRequest","description":"Body for ``PUT /ap-approval/approvers/{tier}``."},"SuccessEnvelope_AnalyticsResponse_":{"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/AnalyticsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[AnalyticsResponse]"},"SuccessEnvelope_ApApprovalGetResponse_":{"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/ApApprovalGetResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ApApprovalGetResponse]"},"SuccessEnvelope_ApApprovalProvisionResponse_":{"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/ApApprovalProvisionResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ApApprovalProvisionResponse]"},"SuccessEnvelope_ApprovalRiskResponse_":{"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/ApprovalRiskResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ApprovalRiskResponse]"},"SuccessEnvelope_ApproversResponse_":{"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/ApproversResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ApproversResponse]"},"SuccessEnvelope_BatchApproveResponse_":{"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/BatchApproveResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[BatchApproveResponse]"},"SuccessEnvelope_CompletedApprovalsResponse_":{"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/CompletedApprovalsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CompletedApprovalsResponse]"},"SuccessEnvelope_PendingApprovalsResponse_":{"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/PendingApprovalsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[PendingApprovalsResponse]"},"SuccessEnvelope_UpdateThresholdsResponse_":{"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/UpdateThresholdsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[UpdateThresholdsResponse]"},"SuccessEnvelope_VendorHistoryResponse_":{"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/VendorHistoryResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[VendorHistoryResponse]"},"UpdateThresholdsRequest":{"properties":{"auto_approve_max_cents":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Auto Approve Max Cents","description":"Max bill amount (cents) for auto-approval. Must be less than ops threshold."},"ops_approve_max_cents":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Ops Approve Max Cents","description":"Max bill amount (cents) for ops-tier approval. Must be greater than auto threshold."},"escalation_hours":{"anyOf":[{"type":"integer","maximum":720.0,"minimum":1.0},{"type":"null"}],"title":"Escalation Hours","description":"Hours before a pending approval automatically escalates to the next tier. Applies to ops and advisor gates. Set to null to use per-gate defaults."}},"type":"object","title":"UpdateThresholdsRequest","description":"Body for ``PATCH /ap-approval/thresholds``.\n\nAll fields are optional — only provided fields are updated."},"UpdateThresholdsResponse":{"properties":{"workflow_id":{"type":"string","title":"Workflow Id","description":"Workflow UUID."},"auto_approve_max_cents":{"type":"integer","title":"Auto Approve Max Cents","description":"Auto-approve threshold in cents."},"ops_approve_max_cents":{"type":"integer","title":"Ops Approve Max Cents","description":"Ops approval threshold in cents."},"escalation_hours":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Escalation Hours","description":"Escalation timeout in hours (null = per-gate default)."}},"type":"object","required":["workflow_id","auto_approve_max_cents","ops_approve_max_cents"],"title":"UpdateThresholdsResponse","description":"Response for ``PATCH /ap-approval/thresholds``."},"VendorHistoryBill":{"properties":{"id":{"type":"string","title":"Id","description":"Bill UUID."},"amount":{"type":"integer","title":"Amount","description":"Bill amount in cents."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Bill status."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Bill description."},"bill_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bill Number","description":"Vendor-issued bill number."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"ISO timestamp when the bill was created."}},"type":"object","required":["id","amount"],"title":"VendorHistoryBill","description":"A single bill in a vendor's payment history."},"VendorHistoryResponse":{"properties":{"vendor_id":{"type":"string","title":"Vendor Id","description":"Vendor UUID."},"vendor_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor Name","description":"Resolved vendor name."},"recent_bills":{"items":{"$ref":"#/components/schemas/VendorHistoryBill"},"type":"array","title":"Recent Bills","description":"Most recent bills from this vendor (newest first)."},"total_paid_cents":{"type":"integer","title":"Total Paid Cents","description":"Sum of paid bill amounts in cents (status = paid).","default":0},"bill_count":{"type":"integer","title":"Bill Count","description":"Total number of bills from this vendor.","default":0}},"type":"object","required":["vendor_id"],"title":"VendorHistoryResponse","description":"Response for ``GET /ap-approval/vendor/{vendor_id}/history``."},"WorkflowGraphSchema-Output":{"properties":{"nodes":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Nodes"},"edges":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Edges"}},"additionalProperties":true,"type":"object","title":"WorkflowGraphSchema","description":"Loose schema for a custom workflow graph.\n\nThe full graph shape is governed elsewhere (custom workflow builder); this\nschema just types the top-level ``nodes`` / ``edges`` arrays so the\nfrontend gets a non-``unknown`` field."},"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":[]}]}