{"openapi":"3.1.0","info":{"title":"Advisory Firms — DayZero API","version":"1.0.0","description":"Advisory firm management for multi-tenant accounting."},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/advisory-firms":{"get":{"tags":["advisory-firms"],"summary":"List advisory firms","description":"List advisory firms for a user. Defaults to the authenticated user; pass `user_id` to filter by a different user.","operationId":"list_advisory_firms","parameters":[{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter firms by this user's memberships","title":"User Id"},"description":"Filter firms by this user's memberships"},{"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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AdvisoryFirmListResponse_"}}}},"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_advisory_firms_api_v1_advisory_firms_get"},"post":{"tags":["advisory-firms"],"summary":"Create advisory firm","description":"Create a new advisory firm. Operators only: sign-up links and checkout are how firms come to exist otherwise.","operationId":"create_advisory_firm","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvisoryFirmCreateRequest"},"example":{"address":"100 Financial District, Suite 500, San Francisco, CA 94105","ein":"12-3456789","name":"Smith & Associates CPA"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AdvisoryFirmResponse_"}}}},"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_advisory_firm_api_v1_advisory_firms_post"}},"/api/v1/advisory-firms/{firm_id}":{"get":{"tags":["advisory-firms"],"summary":"Get advisory firm","description":"Get details of a specific advisory firm.","operationId":"get_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AdvisoryFirmResponse_"}}}},"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_firm_api_v1_advisory_firms__firm_id__get"},"put":{"tags":["advisory-firms"],"summary":"Update advisory firm","description":"Update advisory firm details.","operationId":"update_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvisoryFirmUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_AdvisoryFirmResponse_"}}}},"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_firm_api_v1_advisory_firms__firm_id__put"},"delete":{"tags":["advisory-firms"],"summary":"Delete advisory firm","description":"Delete an advisory firm and all associations. Requires a JSON body with 'confirm_password' — the caller's own account password.","operationId":"delete_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvisoryFirmDeleteRequest"}}}},"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_firm_api_v1_advisory_firms__firm_id__delete"}},"/api/v1/advisory-firms/{firm_id}/logo":{"get":{"tags":["advisory-firms"],"summary":"Get firm logo download URL","description":"Generate a short-lived presigned download URL for the firm logo.","operationId":"get_firm_logo","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetFirmLogoResponse_"}}}},"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_firm_logo_api_v1_advisory_firms__firm_id__logo_get"}},"/api/v1/advisory-firms/{firm_id}/businesses":{"get":{"tags":["advisory-firms"],"summary":"List firm businesses","description":"List all businesses assigned to an advisory firm.","operationId":"list_firm_businesses","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmBusinessesCursorResponse_"}}}},"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_firm_businesses_api_v1_advisory_firms__firm_id__businesses_get"},"post":{"tags":["advisory-firms"],"summary":"Assign business to firm","description":"Assign a business to an advisory firm.\n\nThe caller must administer both the firm (owner/admin) **and** the\nbusiness being linked. The business-side check prevents a firm admin from\nattaching an arbitrary business by ID and inheriting cross-tenant access\nto its data (IDOR).","operationId":"assign_business_to_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessFirmAssociationCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_BusinessFirmAssociationResponse_"}}}},"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":"assign_business_to_firm_api_v1_advisory_firms__firm_id__businesses_post"}},"/api/v1/advisory-firms/{firm_id}/stripe-customer":{"put":{"tags":["advisory-firms"],"summary":"Link Stripe customer","description":"Link an advisory firm to a Stripe customer for billing.","operationId":"update_stripe_customer","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStripeCustomerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_UpdateStripeCustomerResponse_"}}}},"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_stripe_customer_api_v1_advisory_firms__firm_id__stripe_customer_put"}},"/api/v1/advisory-firms/{firm_id}/users":{"get":{"tags":["advisory-firms"],"summary":"List firm users","description":"List all users in an advisory firm.\n\nDayZero superusers on the roster are only listed to another superuser;\nregular firm staff never see them (see ``app.utils.hidden_members``).","operationId":"list_firm_users","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmUsersListResponse_"}}}},"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_firm_users_api_v1_advisory_firms__firm_id__users_get"},"post":{"tags":["advisory-firms"],"summary":"Add user to firm","description":"Add a user to an advisory firm by user_id or email.","operationId":"add_user_to_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFirmAssociationCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_UserFirmAssociationResponse_"}}}},"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":"add_user_to_firm_api_v1_advisory_firms__firm_id__users_post"}},"/api/v1/advisory-firms/{firm_id}/users/{user_id}":{"delete":{"tags":["advisory-firms"],"summary":"Remove user from firm","description":"Remove a user from an advisory firm.\n\nOnly firm owners (or superusers) may remove another owner, and the firm's\nlast owner can never be removed — transfer ownership first.","operationId":"remove_user_from_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__core__success__MessageResponse"}}}},"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":"remove_user_from_firm_api_v1_advisory_firms__firm_id__users__user_id__delete"}},"/api/v1/advisory-firms/{firm_id}/users/{user_id}/role":{"put":{"tags":["advisory-firms"],"summary":"Update user role in firm","description":"Update a user's role in an advisory firm.\n\nOnly firm owners (or superusers) may grant the owner role or change an\nexisting owner's role, and the firm's last owner cannot be demoted.","operationId":"update_user_role_in_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRoleUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_UserFirmAssociationResponse_"}}}},"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_user_role_in_firm_api_v1_advisory_firms__firm_id__users__user_id__role_put"}},"/api/v1/advisory-firms/{firm_id}/users/{user_id}/api-access":{"patch":{"tags":["advisory-firms"],"summary":"Set firm user API access","description":"Allow or block DayZero API access for a firm staff member. The firm-side switch is on by default and can only restrict: a member still needs DayZero to approve their API access request before they can create or use API tokens.","operationId":"set_firm_user_api_access","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirmUserApiAccessRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmUserApiAccessResponse_"}}}},"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":"set_firm_user_api_access_api_v1_advisory_firms__firm_id__users__user_id__api_access_patch"}},"/api/v1/advisory-firms/{firm_id}/users/{user_id}/menu":{"get":{"tags":["advisory-firms"],"summary":"Get a firm staff member's sidebar menu","description":"The stored sidebar menus for a firm staff member: their firm-wide default plus any per-client overrides. Firm owners/admins can read any member's menu; a member can read their own. The menu that applies on a client resolves business-level first (a direct membership's menu, else the per-client override), then firm-wide, then all sections.","operationId":"get_firm_staff_menu","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmStaffMenuDetailResponse_"}}}},"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_firm_staff_menu_api_v1_advisory_firms__firm_id__users__user_id__menu_get"},"put":{"tags":["advisory-firms"],"summary":"Set a firm staff member's sidebar menu","description":"Restrict which app sections a firm staff member can reach, either firm-wide or for one client business. Firm staff reach clients *through the firm* and have no membership row there, so the per-membership menu could not be stored for them at all — this is where their menu lives instead. Unlike the per-membership menu, this one is enforced server-side: a request for a section outside the menu is rejected with 403, not merely hidden from the sidebar.","operationId":"set_firm_staff_menu","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirmStaffMenuRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmStaffMenuResponse_"}}}},"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":"set_firm_staff_menu_api_v1_advisory_firms__firm_id__users__user_id__menu_put"}},"/api/v1/advisory-firms/{firm_id}/businesses/accounting-basis":{"patch":{"tags":["advisory-firms"],"summary":"Bulk-set client accounting basis","description":"Set the default accounting basis (cash or accrual) that financial reports open on for several of the firm's client businesses at once. Every id must be an active client of the firm; otherwise the whole batch is rejected and nothing is changed. Firm owners/admins only.","operationId":"set_firm_businesses_accounting_basis","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirmBusinessAccountingBasisRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmBusinessAccountingBasisResponse_"}}}},"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":"set_firm_businesses_accounting_basis_api_v1_advisory_firms__firm_id__businesses_accounting_basis_patch"}},"/api/v1/advisory-firms/{firm_id}/businesses/{business_id}":{"delete":{"tags":["advisory-firms"],"summary":"Unassign business from firm","description":"Unassign a business from an advisory firm.","operationId":"unassign_business_from_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__core__success__MessageResponse"}}}},"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":"unassign_business_from_firm_api_v1_advisory_firms__firm_id__businesses__business_id__delete"}},"/api/v1/advisory-firms/{firm_id}/businesses/{business_id}/invite-client":{"post":{"tags":["advisory-firms"],"summary":"Invite a client user to a business","description":"Invite a user by email to access a client business. If the user already exists they are added immediately; otherwise an invitation email is sent and they are added on signup.","operationId":"invite_client_to_business","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteClientRequest"},"example":{"email":"client@example.com"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_InviteClientResponse_"}}}},"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"}}}},"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":"invite_client_to_business_api_v1_advisory_firms__firm_id__businesses__business_id__invite_client_post"}},"/api/v1/advisory-firms/{firm_id}/users/invite":{"post":{"tags":["advisory-firms"],"summary":"Invite a staff member to the firm","description":"Invite a user by email to join the firm as staff (admin or member). If the user already exists they are added immediately; otherwise an invitation email is sent and they are added on signup. Owner role cannot be assigned via invitation.","operationId":"invite_staff_to_firm","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteStaffRequest"},"example":{"business_ids":["b1111111-1111-1111-1111-111111111111"],"email":"staff@example.com","role":"member"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_InviteStaffResponse_"}}}},"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":"invite_staff_to_firm_api_v1_advisory_firms__firm_id__users_invite_post"}},"/api/v1/advisory-firms/{firm_id}/invitations":{"get":{"tags":["advisory-firms"],"summary":"List pending invitations","description":"List all invitations for a firm, optionally filtered by type (client, staff, or all) and status.","operationId":"list_firm_invitations","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"type","in":"query","required":false,"schema":{"enum":["client","staff","all"],"type":"string","description":"Filter by invitation type","default":"all","title":"Type"},"description":"Filter by invitation type"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status (e.g. pending)","title":"Status"},"description":"Filter by status (e.g. pending)"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_InvitationListResponse_"}}}},"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_firm_invitations_api_v1_advisory_firms__firm_id__invitations_get"}},"/api/v1/advisory-firms/{firm_id}/invitations/{invitation_id}/resend":{"post":{"tags":["advisory-firms"],"summary":"Resend an invitation","description":"Resend the invitation email and reset the expiry to 7 days from now. Only works on pending invitations.","operationId":"resend_invitation","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","title":"Invitation Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ResendInvitationResponse_"}}}},"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":"resend_invitation_api_v1_advisory_firms__firm_id__invitations__invitation_id__resend_post"}},"/api/v1/advisory-firms/{firm_id}/invitations/{invitation_id}":{"delete":{"tags":["advisory-firms"],"summary":"Cancel an invitation","description":"Cancel a pending invitation. Cannot undo.","operationId":"cancel_invitation","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","title":"Invitation Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__core__success__MessageResponse"}}}},"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":"cancel_invitation_api_v1_advisory_firms__firm_id__invitations__invitation_id__delete"}},"/api/v1/advisory-firms/{firm_id}/clients":{"get":{"tags":["advisory-firms"],"summary":"List firm clients","description":"List all users with the 'client' role in this firm, with their assigned businesses.","operationId":"list_firm_clients","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by client name or email","title":"Search"},"description":"Search by client name or email"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_FirmClientsListResponse_"}}}},"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_firm_clients_api_v1_advisory_firms__firm_id__clients_get"}},"/api/v1/advisory-firms/{firm_id}/clients/{user_id}/businesses":{"post":{"tags":["advisory-firms"],"summary":"Grant client business access","description":"Grant a client user access to a specific business within the firm.","operationId":"grant_client_business_access","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientBusinessAccessRequest"},"example":{"business_id":"019ab37c-b051-7000-8000-000000000001"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ClientBusinessAccessResponse_"}}}},"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"}}}},"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":"grant_client_business_access_api_v1_advisory_firms__firm_id__clients__user_id__businesses_post"},"get":{"tags":["advisory-firms"],"summary":"List client business access","description":"List which businesses a specific client can access.","operationId":"list_client_business_access","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ListClientBusinessAccessResponse_"}}}},"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_client_business_access_api_v1_advisory_firms__firm_id__clients__user_id__businesses_get"}},"/api/v1/advisory-firms/{firm_id}/clients/{user_id}/businesses/{business_id}":{"delete":{"tags":["advisory-firms"],"summary":"Revoke client business access","description":"Revoke a client's access to a specific business.","operationId":"revoke_client_business_access","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"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":"revoke_client_business_access_api_v1_advisory_firms__firm_id__clients__user_id__businesses__business_id__delete"}},"/api/v1/advisory-firms/{firm_id}/slack/status":{"get":{"tags":["advisory-firms"],"summary":"Get firm Slack status","description":"Check whether a Slack webhook is configured and get notification preferences.","operationId":"get_firm_slack_status","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackIntegrationStatus_"}}}},"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_firm_slack_status_api_v1_advisory_firms__firm_id__slack_status_get"}},"/api/v1/advisory-firms/{firm_id}/slack":{"put":{"tags":["advisory-firms"],"summary":"Save firm Slack webhook","description":"Configure a Slack Incoming Webhook URL for the advisory firm.","operationId":"save_firm_slack_webhook","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackWebhookSaveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackIntegrationStatus_"}}}},"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":"save_firm_slack_webhook_api_v1_advisory_firms__firm_id__slack_put"}},"/api/v1/advisory-firms/{firm_id}/slack/{webhook_id}/preferences":{"put":{"tags":["advisory-firms"],"summary":"Update firm Slack notification preferences","description":"Toggle which notification categories are sent to the firm's Slack.","operationId":"update_firm_slack_preferences","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackPreferencesUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackIntegrationStatus_"}}}},"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_firm_slack_preferences_api_v1_advisory_firms__firm_id__slack__webhook_id__preferences_put"}},"/api/v1/advisory-firms/{firm_id}/slack/{webhook_id}/test":{"post":{"tags":["advisory-firms"],"summary":"Test Slack webhook","description":"Send a test message to the firm's configured Slack webhook.","operationId":"test_firm_slack_webhook","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackTestSendResult_"}}}},"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":"test_firm_slack_webhook_api_v1_advisory_firms__firm_id__slack__webhook_id__test_post"}},"/api/v1/advisory-firms/{firm_id}/slack/test":{"post":{"tags":["advisory-firms"],"summary":"Test Slack webhook","description":"Send a test message to the firm's first configured Slack webhook (legacy).","operationId":"test_firm_slack_webhook_legacy","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackTestSendResult_"}}}},"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":"test_firm_slack_webhook_legacy_api_v1_advisory_firms__firm_id__slack_test_post"}},"/api/v1/advisory-firms/{firm_id}/slack/{webhook_id}":{"delete":{"tags":["advisory-firms"],"summary":"Disconnect Slack","description":"Remove the firm's Slack webhook URL and notification preferences.","operationId":"disconnect_firm_slack","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_SlackDisconnectResult_"}}}},"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":"disconnect_firm_slack_api_v1_advisory_firms__firm_id__slack__webhook_id__delete"}},"/api/v1/advisory-firms/{firm_id}/preferences/notifications/topics":{"get":{"tags":["advisory-firms"],"summary":"Get firm notification topic policy","description":"Per-topic channel toggles applied firm-wide to firm staff.","operationId":"get_firm_notification_topic_policy","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_TopicChannelOverridesResponse_"}}}},"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_firm_notification_topic_policy_api_v1_advisory_firms__firm_id__preferences_notifications_topics_get"},"put":{"tags":["advisory-firms"],"summary":"Update firm notification topic policy","description":"Replace the firm-wide per-topic channel policy.","operationId":"update_firm_notification_topic_policy","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicChannelOverridesUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_TopicChannelOverridesResponse_"}}}},"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_firm_notification_topic_policy_api_v1_advisory_firms__firm_id__preferences_notifications_topics_put"}},"/api/v1/advisory-firms/{firm_id}/businesses/{business_id}/preferences/notifications/topics":{"get":{"tags":["advisory-firms"],"summary":"Get a business notification topic policy","description":"Per-topic channel toggles applied to a client business's users.","operationId":"get_business_notification_topic_policy","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_TopicChannelOverridesResponse_"}}}},"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":"get_business_notification_topic_policy_api_v1_advisory_firms__firm_id__businesses__business_id__preferences_notifications_topics_get"},"put":{"tags":["advisory-firms"],"summary":"Update a business notification topic policy","description":"Replace the per-topic channel policy for a client business.","operationId":"update_business_notification_topic_policy","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicChannelOverridesUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_TopicChannelOverridesResponse_"}}}},"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_business_notification_topic_policy_api_v1_advisory_firms__firm_id__businesses__business_id__preferences_notifications_topics_put"}},"/api/v1/advisory-firms/{firm_id}/ai-insights":{"post":{"tags":["advisory-firms"],"summary":"AI cross-client insights","description":"Get AI-powered cross-client insights for an advisory firm.","operationId":"get_firm_ai_insights","parameters":[{"name":"firm_id","in":"path","required":true,"schema":{"type":"string","title":"Firm Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetFirmAIInsightsResponse_"}}}},"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_firm_ai_insights_api_v1_advisory_firms__firm_id__ai_insights_post"}}},"components":{"schemas":{"AccountSchema":{"properties":{"plaid_account_id":{"type":"string","title":"Plaid Account Id","description":"Plaid's unique account ID."},"ledger_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ledger Id","description":"Linked ledger UUID in chart of accounts."},"teal_source_account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Teal Source Account Id","description":"Teal accounting system source account ID."},"balance":{"$ref":"#/components/schemas/BalanceSchema","description":"Current account balances."},"mask":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mask","description":"Last 4 digits of account number (e.g., '1234')."},"name":{"type":"string","title":"Name","description":"Account name from the bank."},"official_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Official Name","description":"Official account name from the bank."},"subtype":{"type":"string","title":"Subtype","description":"Account subtype (e.g., 'checking', 'savings', 'credit card')."},"type":{"type":"string","title":"Type","description":"Account type: depository, credit, loan, investment."},"last_synced":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Synced","description":"When transactions were last synced."},"business_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Id","description":"Business UUID."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When account was linked."},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"Plaid error code if sync failed."},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Error","description":"Error details if sync failed."},"is_linked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Linked","description":"Whether account is saved in our database."},"is_synced_to_teal":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Synced To Teal","description":"Whether account is synced to Teal accounting."},"superseded_by_item_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Superseded By Item Id","description":"Set when this account sits on a Plaid connection that is no longer active and the same real account (institution, mask and subtype) is linked on another live connection of the business; the value is that connection's id. Shown as Replaced rather than Unlinked."},"linked_via_item_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Via Item Id","description":"Set when this connection reports an account that is linked to a ledger through another live connection of the business; the value is that connection's id. The account is not stored under this connection. POST /plaid/account/move moves the link here."},"linked_via_institution_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Via Institution Name","description":"Institution name of the connection in linked_via_item_id."}},"additionalProperties":true,"type":"object","required":["plaid_account_id","balance","name","subtype","type"],"title":"AccountSchema","description":"Schema for a bank account connected via Plaid.\n\nRepresents a single bank account (checking, savings, credit card, etc.)\nthat is linked to the business through a Plaid connection.\n\n**Account Types:**\n- `depository`: Checking, savings accounts\n- `credit`: Credit cards\n- `loan`: Loans, mortgages\n- `investment`: Brokerage, retirement accounts","example":{"balance":{"available":1523450,"current":1548200,"iso_currency_code":"USD"},"business_id":"019ab37c-b051-7000-8000-000000000001","is_linked":true,"is_synced_to_teal":true,"last_synced":"2024-01-15T14:00:00Z","ledger_id":"019ab37c-1ed1-7000-8000-000000000001","mask":"1234","name":"Chase Business Checking","official_name":"CHASE BUSINESS COMPLETE CHECKING","plaid_account_id":"plaid_acc_abc123","subtype":"checking","teal_source_account_id":"teal_src_xyz789","type":"depository"},"examples":[{"balance":{"available":1523450,"current":1548200,"iso_currency_code":"USD"},"business_id":"019ab37c-b051-7000-8000-000000000001","is_linked":true,"is_synced_to_teal":true,"last_synced":"2024-01-15T14:00:00Z","ledger_id":"019ab37c-1ed1-7000-8000-000000000001","mask":"1234","name":"Chase Business Checking","official_name":"CHASE BUSINESS COMPLETE CHECKING","plaid_account_id":"plaid_acc_abc123","subtype":"checking","teal_source_account_id":"teal_src_xyz789","type":"depository"}]},"AdvisoryFirmCreateRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Firm name."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address","description":"Firm business address."},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein","description":"Tax Employer Identification Number."},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url","description":"URL or S3 key for the firm logo."},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id","description":"Stripe customer ID for subscription billing."},"client_messaging_enabled":{"type":"boolean","title":"Client Messaging Enabled","description":"Whether clients can use the messaging portal.","default":false},"ap_automation_enabled":{"type":"boolean","title":"Ap Automation Enabled","description":"Whether clients see the AP automation bills page in the client portal.","default":false},"client_visible_integrations":{"items":{"type":"string"},"type":"array","title":"Client Visible Integrations","description":"Integration IDs visible to clients in the client portal."},"client_ai_assistant_enabled":{"type":"boolean","title":"Client Ai Assistant Enabled","description":"Whether clients can use the read-only AI assistant in the client portal.","default":false},"client_digest_email_enabled":{"type":"boolean","title":"Client Digest Email Enabled","description":"Whether clients receive the proactive financial digest email.","default":false},"client_digest_frequency":{"type":"string","enum":["weekly","monthly"],"title":"Client Digest Frequency","description":"Cadence of the client digest email: 'weekly' or 'monthly'.","default":"monthly"},"mfa_enforced":{"type":"boolean","title":"Mfa Enforced","description":"When true, firm owners/admins must use Clerk MFA for sensitive actions.","default":true}},"type":"object","required":["name"],"title":"AdvisoryFirmCreateRequest","description":"Request schema for creating an advisory firm.","example":{"address":"100 Financial District, Suite 500, San Francisco, CA 94105","ein":"12-3456789","name":"Smith & Associates CPA"},"examples":[{"address":"100 Financial District, Suite 500, San Francisco, CA 94105","ein":"12-3456789","name":"Smith & Associates CPA"}]},"AdvisoryFirmDeleteRequest":{"properties":{"confirm_password":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Confirm Password","description":"Deprecated and ignored. Retained so clients sending the old body keep working during rollout. Step-up is now proven by Clerk re-verification (an emailed code, or the account's own factor), which works for SSO accounts that have no password.","deprecated":true}},"type":"object","title":"AdvisoryFirmDeleteRequest","description":"Body required to delete an advisory firm.\n\nDeleting a firm removes every user association and unassigns every\nbusiness, with no undo, so the caller must retype their own account\npassword. It is verified against Clerk before anything is removed."},"AdvisoryFirmListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdvisoryFirmResponse"},"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":"AdvisoryFirmListResponse","description":"Paginated list of advisory firms."},"AdvisoryFirmResponse":{"properties":{"name":{"type":"string","title":"Name","description":"Firm name."},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address","description":"Firm business address."},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein","description":"Tax Employer Identification Number."},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url","description":"URL or S3 key for the firm logo."},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id","description":"Stripe customer ID for subscription billing."},"client_messaging_enabled":{"type":"boolean","title":"Client Messaging Enabled","description":"Whether clients can use the messaging portal.","default":false},"ap_automation_enabled":{"type":"boolean","title":"Ap Automation Enabled","description":"Whether clients see the AP automation bills page in the client portal.","default":false},"client_visible_integrations":{"items":{"type":"string"},"type":"array","title":"Client Visible Integrations","description":"Integration IDs visible to clients in the client portal."},"client_ai_assistant_enabled":{"type":"boolean","title":"Client Ai Assistant Enabled","description":"Whether clients can use the read-only AI assistant in the client portal.","default":false},"client_digest_email_enabled":{"type":"boolean","title":"Client Digest Email Enabled","description":"Whether clients receive the proactive financial digest email.","default":false},"client_digest_frequency":{"type":"string","enum":["weekly","monthly"],"title":"Client Digest Frequency","description":"Cadence of the client digest email: 'weekly' or 'monthly'.","default":"monthly"},"mfa_enforced":{"type":"boolean","title":"Mfa Enforced","description":"When true, firm owners/admins must use Clerk MFA for sensitive actions.","default":true},"id":{"type":"string","title":"Id","description":"Advisory firm UUID."},"slack_connected":{"type":"boolean","title":"Slack Connected","description":"Whether a Slack webhook URL is configured.","default":false},"slack_webhook_url_masked":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slack Webhook Url Masked","description":"Masked Slack webhook URL (never exposes the full secret)."}},"type":"object","required":["name","id"],"title":"AdvisoryFirmResponse","description":"Response schema for an advisory firm.","example":{"address":"100 Financial District, Suite 500, San Francisco, CA 94105","ein":"12-3456789","id":"019ab37c-f123-7000-8000-000000000001","name":"Smith & Associates CPA","slack_connected":false,"stripe_customer_id":"cus_abc123xyz"},"examples":[{"address":"100 Financial District, Suite 500, San Francisco, CA 94105","ein":"12-3456789","id":"019ab37c-f123-7000-8000-000000000001","name":"Smith & Associates CPA","slack_connected":false,"stripe_customer_id":"cus_abc123xyz"}]},"AdvisoryFirmUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"client_messaging_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Client Messaging Enabled"},"ap_automation_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ap Automation Enabled"},"client_ai_assistant_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Client Ai Assistant Enabled"},"client_digest_email_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Client Digest Email Enabled"},"client_digest_frequency":{"anyOf":[{"type":"string","enum":["weekly","monthly"]},{"type":"null"}],"title":"Client Digest Frequency"},"slack_webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slack Webhook Url","description":"Slack Incoming Webhook URL. Set to empty string to disconnect."},"client_visible_integrations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Client Visible Integrations","description":"Integration IDs visible to clients. Valid values: stripe, plaid, ramp, square, shopify, slack."},"mfa_enforced":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Mfa Enforced","description":"Require Clerk MFA for firm owners/admins on sensitive actions."}},"type":"object","title":"AdvisoryFirmUpdateRequest"},"BalanceSchema":{"properties":{"available":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Available","description":"Available balance in cents (what can be spent now)."},"current":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current","description":"Current balance in cents (includes pending transactions)."},"iso_currency_code":{"type":"string","title":"Iso Currency Code","description":"ISO 4217 currency code (e.g., 'USD')."},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit","description":"Credit limit in cents (for credit cards)."},"unofficial_currency_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unofficial Currency Code","description":"Unofficial currency code if ISO code unavailable."},"is_available":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Is Available","description":"Whether available balance is reported (0 or 1)."}},"additionalProperties":true,"type":"object","required":["iso_currency_code"],"title":"BalanceSchema","description":"Schema for a bank account balance from Plaid.\n\nAmounts are in cents (e.g., 150000 = $1,500.00).","example":{"available":1523450,"current":1548200,"is_available":1,"iso_currency_code":"USD"},"examples":[{"available":1523450,"current":1548200,"is_available":1,"iso_currency_code":"USD"}]},"BusinessFirmAssociationCreateRequest":{"properties":{"business_id":{"type":"string","title":"Business Id"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["business_id"],"title":"BusinessFirmAssociationCreateRequest"},"BusinessFirmAssociationResponse":{"properties":{"id":{"type":"string","title":"Id"},"business_id":{"type":"string","title":"Business Id"},"advisory_firm_id":{"type":"string","title":"Advisory Firm Id"},"is_active":{"type":"boolean","title":"Is Active"},"start_date":{"type":"string","format":"date-time","title":"Start Date"},"end_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Date"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","business_id","advisory_firm_id","is_active","start_date","end_date","created_at","updated_at"],"title":"BusinessFirmAssociationResponse"},"BusinessResponse":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Business UUID."},"firm_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firm Id","description":"Advisory firm UUID this business belongs to."},"mailbox":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mailbox","description":"Email prefix for bill forwarding."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Business name."},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url","description":"URL to business logo/avatar image."},"default_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Currency","description":"Default currency for the business (USD, CAD, AUD, EUR, or GBP)."},"tax_year_end_month":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tax Year End Month","description":"Month when the tax/fiscal year ends (1-12). 12 = calendar year."},"accounting_basis":{"anyOf":[{"type":"string","enum":["cash","accrual"]},{"type":"null"}],"title":"Accounting Basis","description":"Default accounting basis financial reports open on: 'accrual' or 'cash'. Null means accrual."},"start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date","description":"Date the business started operating (founding date). Distinct from entries_start, which anchors bookkeeping imports."},"tax_year_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tax Year Display","description":"Human-readable tax year description (e.g., 'Calendar Year (Jan-Dec)')."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Last update timestamp."},"teal_instance_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Teal Instance Id","description":"Teal instance ID (API format)."},"teal_instance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Teal Instance","description":"Teal database ID."},"entries_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Entries Start","description":"Start date for transaction imports."},"stripe_account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Account Id","description":"Connected Stripe account ID."},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id","description":"Stripe subscription ID."},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id","description":"Stripe customer ID."},"subscription_items":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Subscription Items","description":"Stripe subscription items/products linked to this business."},"shopify_shop_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shopify Shop Domain","description":"Connected Shopify domain."},"shopify_access_token_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shopify Access Token Id","description":"Shopify token UUID."},"ramp_connection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ramp Connection Id","description":"Ramp connection UUID."},"square_connection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Square Connection Id","description":"Square connection UUID."},"finch_connection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finch Connection Id","description":"Finch payroll connection UUID."},"hubspot_connection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hubspot Connection Id","description":"HubSpot connection UUID."},"plaid_connections":{"anyOf":[{"items":{"$ref":"#/components/schemas/PlaidConnectionSchema"},"type":"array"},{"type":"null"}],"title":"Plaid Connections","description":"Connected bank accounts via Plaid."},"slack_connected":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Slack Connected","description":"Whether a Slack webhook URL is configured."},"sync":{"anyOf":[{"$ref":"#/components/schemas/SyncStatus"},{"type":"null"}],"description":"Teal sync status."},"inventory_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inventory Mode","description":"Inventory module flavor: 'cpg' or 'finished_goods'."},"ap_approval_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ap Approval Enabled","description":"Whether the AP bill approval workflow is enabled for this business. When off (default), bills post directly to 'received'."},"ap_due_date_basis":{"anyOf":[{"type":"string","enum":["invoice_date","received_date"]},{"type":"null"}],"title":"Ap Due Date Basis","description":"Which date vendor-bill payment terms count from on ingest: 'invoice_date' (default, trust the invoice) or 'received_date' (terms run from the day the business received the bill)."},"auto_rename_counterparties":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Rename Counterparties","description":"Whether automated counterparty re-resolution is enabled for transactions that already have a counterparty assigned. On by default. Manually-set counterparties are always protected regardless of this setting."}},"additionalProperties":true,"type":"object","title":"BusinessResponse","description":"Response schema for a business.\n\nContains all business details including connected integrations\nand sync status with the accounting system.","example":{"created_at":"2024-01-10T10:30:00Z","entries_start":"2024-01-01T00:00:00Z","firm_id":"019ab37c-f123-7000-8000-000000000001","id":"019ab37c-b051-7000-8000-000000000001","mailbox":"acme","name":"Acme Corporation","plaid_connections":[],"shopify_shop_domain":"acme-store.myshopify.com","stripe_account_id":"acct_abc123","sync":{"last_synced":"2024-01-15T14:00:00Z","status":"completed"},"teal_instance_id":"teal_inst_abc123","updated_at":"2024-01-15T14:00:00Z"},"examples":[{"created_at":"2024-01-10T10:30:00Z","entries_start":"2024-01-01T00:00:00Z","firm_id":"019ab37c-f123-7000-8000-000000000001","id":"019ab37c-b051-7000-8000-000000000001","mailbox":"acme","name":"Acme Corporation","plaid_connections":[],"shopify_shop_domain":"acme-store.myshopify.com","stripe_account_id":"acct_abc123","sync":{"last_synced":"2024-01-15T14:00:00Z","status":"completed"},"teal_instance_id":"teal_inst_abc123","updated_at":"2024-01-15T14:00:00Z"}]},"ClientBusinessAccessListItem":{"properties":{"id":{"type":"string","title":"Id"},"business_id":{"type":"string","title":"Business Id"},"business_name":{"type":"string","title":"Business Name"},"granted_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Granted By"},"created_at":{"type":"string","title":"Created At"}},"additionalProperties":true,"type":"object","required":["id","business_id","business_name","created_at"],"title":"ClientBusinessAccessListItem"},"ClientBusinessAccessRequest":{"properties":{"business_id":{"type":"string","title":"Business Id","description":"Business ID to grant access to."}},"type":"object","required":["business_id"],"title":"ClientBusinessAccessRequest","description":"Request schema for granting a client access to a business.","example":{"business_id":"019ab37c-b051-7000-8000-000000000001"},"examples":[{"business_id":"019ab37c-b051-7000-8000-000000000001"}]},"ClientBusinessAccessResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"business_id":{"type":"string","title":"Business Id"},"firm_id":{"type":"string","title":"Firm Id"},"granted_by":{"type":"string","title":"Granted By"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","user_id","business_id","firm_id","granted_by","created_at"],"title":"ClientBusinessAccessResponse","description":"Single client business access grant."},"FirmBusinessAccountingBasisRequest":{"properties":{"business_ids":{"items":{"type":"string"},"type":"array","maxItems":500,"minItems":1,"title":"Business Ids","description":"Client business IDs to update. Every id must be an active client of the firm."},"accounting_basis":{"type":"string","enum":["cash","accrual"],"title":"Accounting Basis","description":"Default basis financial reports open on for the selected businesses: 'accrual' or 'cash'."}},"type":"object","required":["business_ids","accounting_basis"],"title":"FirmBusinessAccountingBasisRequest","description":"Bulk-set the default accounting basis on a firm's client businesses."},"FirmBusinessAccountingBasisResponse":{"properties":{"updated":{"type":"integer","title":"Updated","description":"Number of businesses updated"}},"type":"object","required":["updated"],"title":"FirmBusinessAccountingBasisResponse"},"FirmBusinessesCursorResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/BusinessResponse"},"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":"FirmBusinessesCursorResponse"},"FirmClientResponse":{"properties":{"id":{"type":"string","title":"Id"},"email":{"type":"string","title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"businesses":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Businesses","description":"Businesses this client can access [{id, name}]"}},"type":"object","required":["id","email"],"title":"FirmClientResponse","description":"A client user within a firm, with their assigned businesses."},"FirmClientsListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FirmClientResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","total"],"title":"FirmClientsListResponse","description":"Response schema for listing firm clients."},"FirmInsightItem":{"properties":{"type":{"type":"string","title":"Type","description":"attention, workload, anomaly, or stale_data"},"title":{"type":"string","title":"Title","description":"Short headline"},"description":{"type":"string","title":"Description","description":"Explanation"},"severity":{"type":"string","title":"Severity","description":"info, warning, or critical"},"business_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Id","description":"Related business ID"},"business_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Name","description":"Related business name"}},"type":"object","required":["type","title","description","severity"],"title":"FirmInsightItem"},"FirmStaffMenuDetailResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"firm_id":{"type":"string","title":"Firm Id"},"visible_sections":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Visible Sections","description":"Firm-wide default menu. null = all sections."},"menu_enforced":{"type":"boolean","title":"Menu Enforced","description":"Whether a menu binds this member at all. Firm owners/admins manage menus and are never restricted by one.","default":true},"overrides":{"items":{"$ref":"#/components/schemas/FirmStaffMenuOverride"},"type":"array","title":"Overrides"}},"type":"object","required":["user_id","firm_id"],"title":"FirmStaffMenuDetailResponse","description":"A firm staff member's stored sidebar menus.\n\n``visible_sections`` is the firm-wide default (null = all sections);\n``overrides`` lists the clients where a per-client menu replaces it. The\nmenu that applies on a client is resolved business-level first (a direct\nmembership's menu, else the per-client override), then firm-wide, then\nall sections."},"FirmStaffMenuOverride":{"properties":{"business_id":{"type":"string","title":"Business Id"},"business_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Name"},"visible_sections":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Visible Sections"}},"type":"object","required":["business_id"],"title":"FirmStaffMenuOverride","description":"A per-client menu a firm admin set for one staff member."},"FirmStaffMenuRequest":{"properties":{"business_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Id","description":"Client business to scope the menu to. Omit or null for the staff member's firm-wide default."},"visible_sections":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Visible Sections","description":"Sidebar section keys this staff member may reach. null clears the menu (all sections); an empty list grants none."}},"type":"object","title":"FirmStaffMenuRequest","description":"Request to set a firm staff member's sidebar menu.\n\n``business_id`` None sets the firm-wide default (the only place a menu can\nlive for clients reached via a team grant, or by a firm owner/admin's\nblanket access); a business id sets the override for that one client."},"FirmStaffMenuResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"firm_id":{"type":"string","title":"Firm Id"},"business_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Id"},"visible_sections":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Visible Sections"}},"type":"object","required":["user_id","firm_id"],"title":"FirmStaffMenuResponse","description":"Result of setting a firm staff member's sidebar menu."},"FirmUserApiAccessRequest":{"properties":{"api_access_enabled":{"type":"boolean","title":"Api Access Enabled","description":"Whether the user may use the DayZero API."}},"type":"object","required":["api_access_enabled"],"title":"FirmUserApiAccessRequest","description":"Request to enable/disable API access for a firm staff member."},"FirmUserApiAccessResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"api_access_enabled":{"type":"boolean","title":"Api Access Enabled"}},"type":"object","required":["user_id","api_access_enabled"],"title":"FirmUserApiAccessResponse","description":"Result of updating a firm staff member's API access."},"FirmUserResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"photo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photo Url"},"onboarded":{"type":"boolean","title":"Onboarded","default":false},"role":{"type":"string","enum":["owner","admin","member","client"],"title":"Role","description":"User's role in the firm. `owner`: Full access + billing + user management. `admin`: Full access + user management (no billing). `member`: Access to assigned businesses only."},"api_access_enabled":{"type":"boolean","title":"Api Access Enabled","description":"Whether this user may use the DayZero API. Enabled by default; firm owners/admins can turn it off for specific staff.","default":true},"visible_sections":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Visible Sections","description":"Firm-wide sidebar menu for this staff member (null = all sections). Per-client overrides live on GET /advisory-firms/{firm_id}/users/{user_id}/menu."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","user_id","email","role","created_at","updated_at"],"title":"FirmUserResponse","description":"Response schema for a user in an advisory firm, including their role."},"FirmUsersListResponse":{"properties":{"users":{"items":{"$ref":"#/components/schemas/FirmUserResponse"},"type":"array","title":"Users"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["users","total"],"title":"FirmUsersListResponse","description":"Response schema for listing users in an advisory firm."},"GetFirmAIInsightsResponse":{"properties":{"insights":{"items":{"$ref":"#/components/schemas/FirmInsightItem"},"type":"array","title":"Insights"}},"type":"object","title":"GetFirmAIInsightsResponse"},"GetFirmLogoResponse":{"properties":{"download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Download Url"},"firm_id":{"type":"string","title":"Firm Id"}},"additionalProperties":true,"type":"object","required":["firm_id"],"title":"GetFirmLogoResponse","description":"Response for ``get_firm_logo``."},"InvitationItemResponse":{"properties":{"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type","description":"'client' or 'staff'."},"email":{"type":"string","title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"role":{"type":"string","title":"Role"},"status":{"type":"string","title":"Status"},"reason":{"anyOf":[{"type":"string","enum":["clerk_confirmed","new_user","needs_clerk_signup","clerk_unavailable","resent"]},{"type":"null"}],"title":"Reason","description":"Derived at list time for pending invitations — explains why the invite hasn't been accepted yet (new_user / needs_clerk_signup / clerk_unavailable). None for terminal states (accepted / cancelled / expired)."},"firm_id":{"type":"string","title":"Firm Id"},"business_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Id","description":"Business ID (client invitations only)."},"invited_by":{"type":"string","title":"Invited By"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"last_sent_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Sent At"},"email_opened_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Email Opened At","description":"Best-effort: first hit on the tracking pixel embedded in the email."},"email_delivered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Email Delivered At","description":"When SES reported the email as delivered to the recipient's inbox."},"email_bounced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Email Bounced At","description":"When SES reported the email as bounced. Indicates the mailbox is invalid or unreachable."},"email_bounce_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email Bounce Reason","description":"Short SES-supplied reason for the bounce, when available."},"email_complaint_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Email Complaint At","description":"When the recipient marked the message as spam."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"business_ids":{"items":{"type":"string"},"type":"array","title":"Business Ids","description":"Businesses queued to be assigned to the invitee on accept (staff member invitations only)."},"assign_all_firm_businesses":{"type":"boolean","title":"Assign All Firm Businesses","description":"If true, the invitee will be assigned to every active firm business on accept (staff member invitations only).","default":false},"team_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Team Id","description":"Team the invitee will join on accept (staff member invitations only)."}},"type":"object","required":["id","type","email","role","status","firm_id","invited_by","created_at"],"title":"InvitationItemResponse","description":"A single invitation in a list response."},"InvitationListResponse":{"properties":{"invitations":{"items":{"$ref":"#/components/schemas/InvitationItemResponse"},"type":"array","title":"Invitations"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["invitations","total"],"title":"InvitationListResponse","description":"Response schema for listing firm invitations."},"InviteClientRequest":{"properties":{"email":{"type":"string","title":"Email","description":"Email address of the client to invite."},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name","description":"Optional first name to personalize the invitation."},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name","description":"Optional last name to personalize the invitation."},"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message","description":"Optional personal message from the inviter included in the email."}},"type":"object","required":["email"],"title":"InviteClientRequest","description":"Request schema for inviting a client user to a business.","example":{"email":"client@example.com"},"examples":[{"email":"client@example.com"}]},"InviteClientResponse":{"properties":{"status":{"type":"string","title":"Status","description":"'added' if user existed and was added, 'invited' if a new invitation email was sent, 'resent' if a pending invitation already existed and was resent with refreshed details."},"reason":{"anyOf":[{"type":"string","enum":["clerk_confirmed","new_user","needs_clerk_signup","clerk_unavailable","resent"]},{"type":"null"}],"title":"Reason","description":"Why this branch was chosen. Lets the UI render the right confirmation message without parsing 'message'."},"message":{"type":"string","title":"Message"},"email_sent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Email Sent","description":"Whether the notification email was sent successfully."}},"type":"object","required":["status","message"],"title":"InviteClientResponse","description":"Response schema for a client invitation."},"InviteStaffRequest":{"properties":{"email":{"type":"string","title":"Email","description":"Email address of the person to invite."},"role":{"type":"string","enum":["admin","member"],"title":"Role","description":"Role to assign: 'admin' or 'member'. Owner cannot be invited.","default":"member"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name","description":"Optional first name to personalize the invitation."},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name","description":"Optional last name to personalize the invitation."},"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message","description":"Optional personal message from the inviter included in the email."},"business_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Business Ids","description":"For 'member' role: explicit list of businesses the invitee should be assigned to on acceptance. Ignored for 'admin' (admins see every firm business)."},"team_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Team Id","description":"For 'member' role: team to add the invitee to on acceptance. Mutually exclusive with 'business_ids' and 'assign_all_firm_businesses'."},"assign_all_firm_businesses":{"type":"boolean","title":"Assign All Firm Businesses","description":"For 'member' role: if true, grant the invitee direct assignment to every currently active firm business on acceptance.","default":false}},"type":"object","required":["email"],"title":"InviteStaffRequest","description":"Request schema for inviting a staff user to a firm.","example":{"business_ids":["b1111111-1111-1111-1111-111111111111"],"email":"staff@example.com","role":"member"},"examples":[{"business_ids":["b1111111-1111-1111-1111-111111111111"],"email":"staff@example.com","role":"member"}]},"InviteStaffResponse":{"properties":{"status":{"type":"string","title":"Status","description":"'added' if user existed and was added, 'invited' if a new invitation email was sent, 'resent' if the admin re-invited an email with an existing pending invite (refreshed details + rotated token)."},"reason":{"anyOf":[{"type":"string","enum":["clerk_confirmed","new_user","needs_clerk_signup","clerk_unavailable","resent"]},{"type":"null"}],"title":"Reason","description":"Why this branch was chosen. Lets the UI render the right confirmation message without parsing 'message'."},"message":{"type":"string","title":"Message"},"email_sent":{"type":"boolean","title":"Email Sent","description":"Whether the notification email was sent successfully.","default":true}},"type":"object","required":["status","message"],"title":"InviteStaffResponse","description":"Response schema for a staff invitation."},"ListClientBusinessAccessResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ClientBusinessAccessListItem"},"type":"array","title":"Items"}},"additionalProperties":true,"type":"object","required":["items"],"title":"ListClientBusinessAccessResponse","description":"Response for ``list_client_business_access``."},"PlaidConnectionSchema":{"properties":{"id":{"type":"string","title":"Id","description":"Plaid Item UUID."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When connection was established."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp."},"item_id":{"type":"string","title":"Item Id","description":"Plaid Item ID."},"institution_id":{"type":"string","title":"Institution Id","description":"Plaid institution ID (e.g., 'ins_3')."},"institution_name":{"type":"string","title":"Institution Name","description":"Bank/institution name."},"accounts":{"anyOf":[{"items":{"$ref":"#/components/schemas/AccountSchema"},"type":"array"},{"type":"null"}],"title":"Accounts","description":"Bank accounts associated with this connection.","default":[]},"business_id":{"type":"string","title":"Business Id","description":"Business UUID."},"sync_status":{"type":"string","title":"Sync Status","description":"Current sync status."},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"Plaid error code if sync failed."}},"additionalProperties":true,"type":"object","required":["id","created_at","updated_at","item_id","institution_id","institution_name","business_id","sync_status"],"title":"PlaidConnectionSchema","description":"Response schema for a Plaid bank connection.\n\nRepresents a linked bank institution with its associated accounts.\nCreated when a user connects a bank via the Plaid Link flow.\n\n**Sync Status Values:**\n- `syncing`: Initial sync in progress\n- `synced`: Fully synced and up to date\n- `error`: Sync failed (check error_code)\n- `disconnected`: Connection needs re-authentication","example":{"accounts":[{"id":"019ab37c-acc1-7000-8000-000000000001","mask":"1234","name":"Chase Business Checking","subtype":"checking","type":"depository"}],"business_id":"019ab37c-b051-7000-8000-000000000001","created_at":"2024-01-10T10:30:00Z","id":"019ab37c-plaid-7000-8000-000000000001","institution_id":"ins_3","institution_name":"Chase","item_id":"plaid_item_abc123","sync_status":"synced","updated_at":"2024-01-15T14:00:00Z"},"examples":[{"accounts":[{"id":"019ab37c-acc1-7000-8000-000000000001","mask":"1234","name":"Chase Business Checking","subtype":"checking","type":"depository"}],"business_id":"019ab37c-b051-7000-8000-000000000001","created_at":"2024-01-10T10:30:00Z","id":"019ab37c-plaid-7000-8000-000000000001","institution_id":"ins_3","institution_name":"Chase","item_id":"plaid_item_abc123","sync_status":"synced","updated_at":"2024-01-15T14:00:00Z"}]},"ResendInvitationResponse":{"properties":{"status":{"type":"string","title":"Status","default":"ok"},"message":{"type":"string","title":"Message"},"email_sent":{"type":"boolean","title":"Email Sent","default":true},"new_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"New Expires At"}},"type":"object","required":["message"],"title":"ResendInvitationResponse","description":"Response after resending an invitation."},"SlackCategoryItem":{"properties":{"key":{"type":"string","title":"Key","description":"Stable category key"},"label":{"type":"string","title":"Label","description":"User-facing label"},"description":{"type":"string","title":"Description","description":"One-line explanation"},"group":{"type":"string","title":"Group","description":"Group key used to render the UI in sections"},"enabled":{"type":"boolean","title":"Enabled","description":"Whether the user has this category enabled"}},"type":"object","required":["key","label","description","group","enabled"],"title":"SlackCategoryItem","description":"One toggleable notification category in a Slack integration status."},"SlackDisconnectResult":{"properties":{"status":{"type":"string","title":"Status","description":"\"ok\" on success"},"message":{"type":"string","title":"Message","description":"Human-readable status message"}},"type":"object","required":["status","message"],"title":"SlackDisconnectResult","description":"Result of removing a configured Slack webhook."},"SlackGroupInfo":{"properties":{"key":{"type":"string","title":"Key","description":"Group key (matches SlackCategoryItem.group)"},"label":{"type":"string","title":"Label","description":"User-facing section label"}},"type":"object","required":["key","label"],"title":"SlackGroupInfo","description":"Render metadata for a category group."},"SlackIntegrationStatus":{"properties":{"connected":{"type":"boolean","title":"Connected","description":"Whether at least one webhook URL is configured"},"webhooks":{"items":{"$ref":"#/components/schemas/SlackWebhookItem"},"type":"array","title":"Webhooks","description":"List of configured webhooks"},"groups":{"items":{"$ref":"#/components/schemas/SlackGroupInfo"},"type":"array","title":"Groups","description":"Group definitions for UI section rendering"}},"type":"object","required":["connected"],"title":"SlackIntegrationStatus","description":"Status of a business- or firm-level Slack incoming-webhook integration."},"SlackPreferencesUpdateRequest":{"properties":{"preferences":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Preferences","description":"Map of category key to enabled flag, e.g. {'workflow_completions': false}. Unknown keys are silently ignored."}},"type":"object","required":["preferences"],"title":"SlackPreferencesUpdateRequest","description":"Toggle which notification categories deliver to Slack."},"SlackTestSendResult":{"properties":{"status":{"type":"string","title":"Status","description":"\"ok\" on success"},"message":{"type":"string","title":"Message","description":"Human-readable status message"}},"type":"object","required":["status","message"],"title":"SlackTestSendResult","description":"Result of sending a test notification to Slack."},"SlackWebhookItem":{"properties":{"id":{"type":"string","title":"Id","description":"Webhook ID"},"channel_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Name","description":"User-defined channel or webhook name"},"webhook_url_masked":{"type":"string","title":"Webhook Url Masked","description":"Masked URL for display"},"notification_preferences":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Notification Preferences","description":"Per-category enabled flags"},"notification_categories":{"items":{"$ref":"#/components/schemas/SlackCategoryItem"},"type":"array","title":"Notification Categories","description":"Categories with metadata for UI rendering"}},"type":"object","required":["id","webhook_url_masked","notification_preferences","notification_categories"],"title":"SlackWebhookItem","description":"A configured Slack webhook."},"SlackWebhookSaveRequest":{"properties":{"slack_webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slack Webhook Url","description":"Slack Incoming Webhook URL, or empty/null to disconnect"},"channel_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Name","description":"Optional name for the channel or webhook"},"preferences":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Preferences","description":"Optional per-category enabled flags for the new webhook. Omitted categories default to enabled."}},"type":"object","title":"SlackWebhookSaveRequest","description":"Save (or clear) a Slack Incoming Webhook URL.\n\nSend ``slack_webhook_url`` as an empty string or ``null`` to disconnect."},"SuccessEnvelope_AdvisoryFirmListResponse_":{"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/AdvisoryFirmListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[AdvisoryFirmListResponse]"},"SuccessEnvelope_AdvisoryFirmResponse_":{"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/AdvisoryFirmResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[AdvisoryFirmResponse]"},"SuccessEnvelope_BusinessFirmAssociationResponse_":{"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/BusinessFirmAssociationResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[BusinessFirmAssociationResponse]"},"SuccessEnvelope_ClientBusinessAccessResponse_":{"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/ClientBusinessAccessResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ClientBusinessAccessResponse]"},"SuccessEnvelope_FirmBusinessAccountingBasisResponse_":{"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/FirmBusinessAccountingBasisResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmBusinessAccountingBasisResponse]"},"SuccessEnvelope_FirmBusinessesCursorResponse_":{"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/FirmBusinessesCursorResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmBusinessesCursorResponse]"},"SuccessEnvelope_FirmClientsListResponse_":{"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/FirmClientsListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmClientsListResponse]"},"SuccessEnvelope_FirmStaffMenuDetailResponse_":{"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/FirmStaffMenuDetailResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmStaffMenuDetailResponse]"},"SuccessEnvelope_FirmStaffMenuResponse_":{"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/FirmStaffMenuResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmStaffMenuResponse]"},"SuccessEnvelope_FirmUserApiAccessResponse_":{"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/FirmUserApiAccessResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmUserApiAccessResponse]"},"SuccessEnvelope_FirmUsersListResponse_":{"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/FirmUsersListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[FirmUsersListResponse]"},"SuccessEnvelope_GetFirmAIInsightsResponse_":{"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/GetFirmAIInsightsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetFirmAIInsightsResponse]"},"SuccessEnvelope_GetFirmLogoResponse_":{"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/GetFirmLogoResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetFirmLogoResponse]"},"SuccessEnvelope_InvitationListResponse_":{"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/InvitationListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[InvitationListResponse]"},"SuccessEnvelope_InviteClientResponse_":{"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/InviteClientResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[InviteClientResponse]"},"SuccessEnvelope_InviteStaffResponse_":{"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/InviteStaffResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[InviteStaffResponse]"},"SuccessEnvelope_ListClientBusinessAccessResponse_":{"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/ListClientBusinessAccessResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ListClientBusinessAccessResponse]"},"SuccessEnvelope_ResendInvitationResponse_":{"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/ResendInvitationResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ResendInvitationResponse]"},"SuccessEnvelope_SlackDisconnectResult_":{"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/SlackDisconnectResult"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[SlackDisconnectResult]"},"SuccessEnvelope_SlackIntegrationStatus_":{"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/SlackIntegrationStatus"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[SlackIntegrationStatus]"},"SuccessEnvelope_SlackTestSendResult_":{"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/SlackTestSendResult"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[SlackTestSendResult]"},"SuccessEnvelope_TopicChannelOverridesResponse_":{"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/TopicChannelOverridesResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[TopicChannelOverridesResponse]"},"SuccessEnvelope_UpdateStripeCustomerResponse_":{"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/UpdateStripeCustomerResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[UpdateStripeCustomerResponse]"},"SuccessEnvelope_UserFirmAssociationResponse_":{"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/UserFirmAssociationResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[UserFirmAssociationResponse]"},"SyncStatus":{"properties":{"status":{"type":"string","enum":["syncing","completed","nothing_to_sync"],"title":"Status","description":"Sync status: 'syncing', 'completed', or 'nothing_to_sync'"},"last_synced":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Synced","description":"ISO timestamp of last successful sync"},"sync_in_progress":{"type":"boolean","title":"Sync In Progress","description":"Whether a teal-sync task is currently running (from tasks table)","default":false}},"type":"object","required":["status"],"title":"SyncStatus","description":"Sync status for a business."},"TopicCatalogEntry":{"properties":{"value":{"type":"string","title":"Value","description":"NotificationTopic enum value"},"label":{"type":"string","title":"Label","description":"Human-readable label"}},"type":"object","required":["value","label"],"title":"TopicCatalogEntry","description":"A selectable notification topic and its display label."},"TopicChannelOverridesResponse":{"properties":{"overrides":{"additionalProperties":{"additionalProperties":{"type":"boolean"},"type":"object"},"type":"object","title":"Overrides","description":"Map of topic -> {channel: bool}"},"available_channels":{"items":{"type":"string"},"type":"array","title":"Available Channels","description":"Channels the override grid can toggle"},"available_topics":{"items":{"$ref":"#/components/schemas/TopicCatalogEntry"},"type":"array","title":"Available Topics","description":"Every notification topic + label, generated from the backend enum so the preference grid never hardcodes the topic list"}},"type":"object","title":"TopicChannelOverridesResponse","description":"User's per-topic channel overrides + the channel set this UI accepts.\n\nThe ``available_channels`` field lets the frontend stay in\nsync with backend without hardcoding the channel list."},"TopicChannelOverridesUpdate":{"properties":{"overrides":{"additionalProperties":{"additionalProperties":{"type":"boolean"},"type":"object"},"type":"object","title":"Overrides"}},"type":"object","title":"TopicChannelOverridesUpdate","description":"Replace-style update for the per-topic override map.\n\nSending an empty dict for a topic clears that topic's\noverrides (falls back to ``CHANNEL_POLICY`` defaults).\nSending an empty top-level dict clears all overrides."},"UpdateStripeCustomerRequest":{"properties":{"stripe_customer_id":{"type":"string","title":"Stripe Customer Id","description":"Stripe customer ID (e.g., cus_xxx)"}},"type":"object","required":["stripe_customer_id"],"title":"UpdateStripeCustomerRequest","description":"Request schema for linking an advisory firm to a Stripe customer."},"UpdateStripeCustomerResponse":{"properties":{"advisory_firm_id":{"type":"string","title":"Advisory Firm Id","description":"Advisory firm ID"},"stripe_customer_id":{"type":"string","title":"Stripe Customer Id","description":"Linked Stripe customer ID"}},"type":"object","required":["advisory_firm_id","stripe_customer_id"],"title":"UpdateStripeCustomerResponse","description":"Response schema for linking an advisory firm to a Stripe customer."},"UserFirmAssociationCreateRequest":{"properties":{"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"User UUID. Supply either user_id or email."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"User email. When provided without user_id, the backend resolves it."},"role":{"type":"string","enum":["owner","admin","member","client"],"title":"Role","description":"User's role in the firm. `owner`: Full access + billing + user management. `admin`: Full access + user management (no billing). `member`: Access to assigned businesses only.","default":"member"}},"type":"object","title":"UserFirmAssociationCreateRequest"},"UserFirmAssociationResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"advisory_firm_id":{"type":"string","title":"Advisory Firm Id"},"role":{"type":"string","enum":["owner","admin","member","client"],"title":"Role","description":"User's role in the firm. `owner`: Full access + billing + user management. `admin`: Full access + user management (no billing). `member`: Access to assigned businesses only.","default":"member"}},"type":"object","required":["id","user_id","advisory_firm_id"],"title":"UserFirmAssociationResponse"},"UserRoleUpdateRequest":{"properties":{"role":{"type":"string","enum":["owner","admin","member","client"],"title":"Role","description":"New role for the user. `owner`: Full access + billing + user management. `admin`: Full access + user management (no billing). `member`: Access to assigned businesses only."}},"type":"object","required":["role"],"title":"UserRoleUpdateRequest"},"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":[]}]}