{"openapi":"3.1.0","info":{"title":"PUT /api/v1/advisory-firms/{firm_id}/slack/{webhook_id}/preferences","version":"1.0.0","description":"Update firm Slack notification preferences"},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/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"}}},"components":{"schemas":{"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."},"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."},"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."},"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]"},"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":[]}]}