{"openapi":"3.1.0","info":{"title":"FlagHound API","description":"Predictive compliance intelligence for NYC HVAC contractors","version":"0.2.0"},"paths":{"/companies/":{"post":{"tags":["companies"],"summary":"Create Company","operationId":"create_company_companies__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["companies"],"summary":"List Companies","operationId":"list_companies_companies__get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompanyOut"},"title":"Response List Companies Companies  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me":{"get":{"tags":["companies"],"summary":"Get My Company","description":"Return the authenticated user's company.","operationId":"get_my_company_companies_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyOut"}}}}}},"delete":{"tags":["companies"],"summary":"Delete My Company","description":"Customer-initiated account deletion.\n\nTwo-step confirmation: caller must echo their exact company name in\nthe request body. The auth dependency provides the actual company\nso a confused user can't accidentally delete a different account.\nOn success returns 200 with a summary; the frontend should then\nsign the user out and redirect to /.","operationId":"delete_my_company_companies_me_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyDeleteConfirmation"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/usage":{"get":{"tags":["companies"],"summary":"Get Usage","description":"Return current usage vs tier limits for the authenticated company.","operationId":"get_usage_companies_me_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/companies/me/notifications":{"patch":{"tags":["companies"],"summary":"Patch Me Notifications","description":"Update notification toggles + preferred_language for the authenticated company.","operationId":"patch_me_notifications_companies_me_notifications_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPrefsIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Patch Me Notifications Companies Me Notifications Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/resolve-address":{"post":{"tags":["companies"],"summary":"Resolve Address","description":"Resolve a freeform address to a BIN via NYC Geoclient.","operationId":"resolve_address_companies_resolve_address_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAddressRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/discover-permits":{"post":{"tags":["companies"],"summary":"Discover Permits","description":"Look up DOB NOW jobs + permits filed by a given license number and\nreturn a deduplicated list of jobsite candidates for the user to\nreview. Does not persist anything — the frontend sends the user's\nselections to POST /companies/{id}/watched-entities/bulk to commit.","operationId":"discover_permits_companies_me_discover_permits_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverPermitsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}":{"get":{"tags":["companies"],"summary":"Get Company","operationId":"get_company_companies__company_id__get","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["companies"],"summary":"Update Company","operationId":"update_company_companies__company_id__put","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/pe":{"post":{"tags":["companies"],"summary":"Add Pe Association","operationId":"add_pe_association_companies__company_id__pe_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyPECreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyPEOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["companies"],"summary":"List Pe Associations","description":"List active PE license associations for a company.","operationId":"list_pe_associations_companies__company_id__pe_get","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompanyPEOut"},"title":"Response List Pe Associations Companies  Company Id  Pe Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/pe/{pe_id}":{"delete":{"tags":["companies"],"summary":"Deactivate Pe Association","description":"Soft-delete a PE association. Leaves the row in place for audit\nbut flips is_active=False so it stops counting for Layer 1 attribution.","operationId":"deactivate_pe_association_companies__company_id__pe__pe_id__delete","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}},{"name":"pe_id","in":"path","required":true,"schema":{"type":"string","title":"Pe Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/watched-entities":{"post":{"tags":["companies"],"summary":"Add Watched Entity","description":"Add a watched entity (job site BIN) for a company.","operationId":"add_watched_entity_companies__company_id__watched_entities_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedEntityCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedEntityOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/watched-entities/{entity_id}":{"delete":{"tags":["companies"],"summary":"Delete Watched Entity","description":"Remove a watched entity (jobsite) from the company's watch list.","operationId":"delete_watched_entity_companies__company_id__watched_entities__entity_id__delete","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/watched-entities/bulk":{"post":{"tags":["companies"],"summary":"Bulk Add Watched Entities","description":"Bulk add watched entities (up to 100 BINs at a time).\n\nValidates all BINs, skips duplicates, and creates entities in a single transaction.","operationId":"bulk_add_watched_entities_companies__company_id__watched_entities_bulk_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkWatchedEntityCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkWatchedEntityResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/backfill":{"post":{"tags":["companies"],"summary":"Backfill Company","description":"Re-pull NYC SODA data for every watched BIN on this company.","operationId":"backfill_company_companies__company_id__backfill_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/complete-onboarding":{"post":{"tags":["companies"],"summary":"Complete Onboarding","description":"Mark a company's onboarding as complete + kick off an initial SODA sweep.\n\nWithout the sweep, new customers land on an empty dashboard for 2-4\nhours until the first scheduled Celery poll finds their permits and\nviolations. The sweep enqueues a backfill for every watched BIN on\nthe company and returns immediately - same logic as the manual\n/backfill endpoint, but asynchronous.","operationId":"complete_onboarding_companies__company_id__complete_onboarding_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/properties":{"get":{"tags":["companies"],"summary":"Get Company Properties","description":"Return properties grouped by BIN, shaped for the frontend Property type.","operationId":"get_company_properties_companies__company_id__properties_get","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/team":{"get":{"tags":["companies"],"summary":"Get Team Members","description":"List all team members for the authenticated company.","operationId":"get_team_members_companies_me_team_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["companies"],"summary":"Add Team Member","description":"Add a team member by Clerk user ID. Requires Enterprise tier for >1 member.\n\nThe supplied `clerk_user_id` is verified against Clerk's REST API\nbefore insert. An attacker who plants `user_<victim>` without a real\nClerk record is rejected here; the dependency reorder in\n`get_current_company` covers the corresponding routing risk.","operationId":"add_team_member_companies_me_team_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/team/{member_id}":{"delete":{"tags":["companies"],"summary":"Remove Team Member","description":"Remove a team member. Only the owner can remove members.","operationId":"remove_team_member_companies_me_team__member_id__delete","parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","title":"Member Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/roi-reports":{"get":{"tags":["companies"],"summary":"List Roi Reports","operationId":"list_roi_reports_companies_me_roi_reports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"object"},"type":"array","title":"Response List Roi Reports Companies Me Roi Reports Get"}}}}}}},"/companies/me/roi-reports/{report_id}.pdf":{"get":{"tags":["companies"],"summary":"Download Roi Report","operationId":"download_roi_report_companies_me_roi_reports__report_id__pdf_get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/outcomes":{"get":{"tags":["companies"],"summary":"Get Outcomes","description":"Aggregated outcome counts and total estimated value since a given date.","operationId":"get_outcomes_companies_me_outcomes_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO date YYYY-MM-DD, default 30 days ago","title":"Since"},"description":"ISO date YYYY-MM-DD, default 30 days ago"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Outcomes Companies Me Outcomes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/complaints/{complaint_id}/unlink":{"post":{"tags":["companies"],"summary":"Unlink Complaint","description":"Mark a complaint as not-actually-linked-to-my-work for this company.\n\nIdempotent. On conflict, does nothing. The complaint must be at a BIN\nthis company watches; otherwise 404 so we don't leak complaint IDs\nacross tenants.","operationId":"unlink_complaint_companies__company_id__complaints__complaint_id__unlink_post","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}},{"name":"complaint_id","in":"path","required":true,"schema":{"type":"string","title":"Complaint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["companies"],"summary":"Undo Unlink Complaint","description":"Remove a prior dismissal. Idempotent.","operationId":"undo_unlink_complaint_companies__company_id__complaints__complaint_id__unlink_delete","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}},{"name":"complaint_id","in":"path","required":true,"schema":{"type":"string","title":"Complaint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/{company_id}/complaints/{complaint_id}/context":{"get":{"tags":["companies"],"summary":"Get Complaint Context","description":"Return the three-panel context payload for a single complaint.\n\nPanels:\n- at_a_glance: filed N days ago, priority + response-time hint\n- your_permits_at_bin: this company's active owner permits at the complaint BIN\n- building_history: complaints at this BIN in the last 12 months + top categories + category conversion rate (when sample >= 10)","operationId":"get_complaint_context_companies__company_id__complaints__complaint_id__context_get","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}},{"name":"complaint_id","in":"path","required":true,"schema":{"type":"string","title":"Complaint Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/api-keys":{"get":{"tags":["companies"],"summary":"List My Api Keys","description":"List API keys for the caller's company. Never returns plaintext.","operationId":"list_my_api_keys_companies_me_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["companies"],"summary":"Create My Api Key","description":"Mint an API key for the caller's company.\n\nBody::\n\n    { \"label\": \"Claude Desktop\", \"expires_at\": \"...\" (optional) }\n\nThe plaintext is returned ONCE. Save it now; you can never retrieve\nit again. If you lose it, revoke and regenerate.","operationId":"create_my_api_key_companies_me_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"Body"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/companies/me/api-keys/{key_id}":{"delete":{"tags":["companies"],"summary":"Revoke My Api Key","description":"Revoke (soft-delete) one of the caller's API keys.\n\nVerifies the key belongs to the caller's company before revoking;\notherwise returns 404 to avoid leaking the existence of keys owned\nby other tenants.","operationId":"revoke_my_api_key_companies_me_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/":{"get":{"tags":["alerts"],"summary":"List Alerts","operationId":"list_alerts_alerts__get","parameters":[{"name":"alert_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by alert_type (violation, expiry_warning, regulatory_change)","title":"Alert Type"},"description":"Filter by alert_type (violation, expiry_warning, regulatory_change)"},{"name":"unread_only","in":"query","required":false,"schema":{"type":"boolean","description":"Return only unread alerts","default":false,"title":"Unread Only"},"description":"Return only unread alerts"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/triage":{"get":{"tags":["alerts"],"summary":"Get Triage","description":"Server-bucketed triage feed: UNRESOLVED / TODAY / THIS_WEEK / LATER.\n\nSingle endpoint that consolidates violations, permits, complaints,\nhearings, licenses, and computed inspection deadlines per spec\ndocs/superpowers/specs/2026-05-13-alerts-triage-redesign-design.md §3.3.","operationId":"get_triage_alerts_triage_get","parameters":[{"name":"include_snoozed","in":"query","required":false,"schema":{"type":"boolean","description":"Include snoozed events in the response (drawer UI).","default":false,"title":"Include Snoozed"},"description":"Include snoozed events in the response (drawer UI)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/triage/{triage_event_id}/snooze":{"post":{"tags":["alerts"],"summary":"Snooze Event","operationId":"snooze_event_alerts_triage__triage_event_id__snooze_post","parameters":[{"name":"triage_event_id","in":"path","required":true,"schema":{"type":"string","title":"Triage Event Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnoozeIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnoozeOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/triage/{triage_event_id}/unsnooze":{"post":{"tags":["alerts"],"summary":"Unsnooze Event","operationId":"unsnooze_event_alerts_triage__triage_event_id__unsnooze_post","parameters":[{"name":"triage_event_id","in":"path","required":true,"schema":{"type":"string","title":"Triage Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/triage/{triage_event_id}/resolve":{"post":{"tags":["alerts"],"summary":"Resolve Triage Event","description":"Mark a triage event as handled. Phase 4 Track A.\n\nWrites an alert_outcomes row keyed on (company_id, triage_event_id),\nbypassing the legacy CompanyAlert stitch entirely. Idempotent: same\nargs twice resolves once. The route enforces ownership via\n_assert_triage_event_owned (404 if the caller can't see the event).","operationId":"resolve_triage_event_alerts_triage__triage_event_id__resolve_post","parameters":[{"name":"triage_event_id","in":"path","required":true,"schema":{"type":"string","title":"Triage Event Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolutionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriageResolveOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/triage/{triage_event_id}/reopen":{"post":{"tags":["alerts"],"summary":"Reopen Triage Event","description":"Reverse a Mark Handled. Companion to /resolve for the Track G undo.\n\nDeletes the alert_outcomes row so the event resurfaces in subsequent\n/alerts/triage calls. Owner check matches /resolve. Returns\n{\"reopened\": True} regardless of whether a row existed (idempotent\nfrom the caller's perspective).","operationId":"reopen_triage_event_alerts_triage__triage_event_id__reopen_post","parameters":[{"name":"triage_event_id","in":"path","required":true,"schema":{"type":"string","title":"Triage Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}":{"get":{"tags":["alerts"],"summary":"Get Alert","operationId":"get_alert_alerts__alert_id__get","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}/read":{"post":{"tags":["alerts"],"summary":"Mark Alert Read","operationId":"mark_alert_read_alerts__alert_id__read_post","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}/dismiss":{"post":{"tags":["alerts"],"summary":"Dismiss Alert","operationId":"dismiss_alert_alerts__alert_id__dismiss_post","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}/restore":{"post":{"tags":["alerts"],"summary":"Restore Alert","description":"Reverse a dismissal. Clears is_dismissed and dismissed_at.","operationId":"restore_alert_alerts__alert_id__restore_post","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}/resolve":{"post":{"tags":["alerts"],"summary":"Resolve Alert","operationId":"resolve_alert_alerts__alert_id__resolve_post","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolutionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutcomeOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alerts/{alert_id}/reopen":{"post":{"tags":["alerts"],"summary":"Reopen Alert","operationId":"reopen_alert_alerts__alert_id__reopen_post","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"string","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Reopen Alert Alerts  Alert Id  Reopen Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/lead":{"post":{"tags":["webhooks"],"summary":"Receive Lead","description":"Store a CTA form lead captured from the landing page.\n\nThe landing page sends company_name, contact_name, email, and optionally\nphone + pain_point. We store it to the leads table for manual follow-up\nuntil an automated onboarding flow is in place.","operationId":"receive_lead_webhooks_lead_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/clerk":{"post":{"tags":["webhooks"],"summary":"Clerk Webhook","description":"Clerk webhook receiver with Svix signature verification.\n\nOn user.created: creates a Company skeleton so the dashboard has a record\nas soon as the user completes sign-up. The onboarding flow fills in\ncompany details (name, trade type, job sites, etc.).","operationId":"clerk_webhook_webhooks_clerk_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/webhooks/stripe":{"post":{"tags":["webhooks"],"summary":"Stripe Webhook","description":"Stripe webhook receiver with signature verification.\n\nProcesses subscription lifecycle events to keep company tiers in sync.","operationId":"stripe_webhook_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scores/{bin}":{"get":{"tags":["scores"],"summary":"Get Compliance Score","description":"Get composite compliance score and additive risk score for a BIN.\n\nRisk score scope (2026-05-15 product decision):\n  - owner: only this BIN's attribution=owner activity counts.\n  - site (default for public): every event at the BIN counts.\n\nPublic BIN lookups have no company context, so owner scope drops all\ncomplaints (Layer 4 match needs a company_id). For an authenticated\ndashboard caller, the property page calls the service directly with\ncompany_id so owner scope is meaningful.","operationId":"get_compliance_score_scores__bin__get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"owner | site (default site for public lookup)","title":"Scope"},"description":"owner | site (default site for public lookup)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scores/address/lookup":{"get":{"tags":["scores"],"summary":"Get Score By Address","description":"Resolve address to BIN via Geoclient, then return compliance + risk scores.","operationId":"get_score_by_address_scores_address_lookup_get","parameters":[{"name":"house_number","in":"query","required":true,"schema":{"type":"string","title":"House Number"}},{"name":"street","in":"query","required":true,"schema":{"type":"string","title":"Street"}},{"name":"borough","in":"query","required":true,"schema":{"type":"string","title":"Borough"}},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"owner | site (default site for public lookup)","title":"Scope"},"description":"owner | site (default site for public lookup)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{bin}":{"get":{"tags":["reports"],"summary":"Get Compliance Report","description":"Get full property compliance report for a BIN.","operationId":"get_compliance_report_reports__bin__get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{bin}/pdf":{"get":{"tags":["reports"],"summary":"Get Compliance Report Pdf","description":"Download the public compliance report for a BIN as a branded PDF.\n\nFree for users who already pulled the JSON report (cache hit), otherwise\nburns one report quota slot and runs Turnstile + backfill. The PDF is\nrendered with `is_public=True` so it omits the per-customer attribution\nline and reads as a property report rather than a customer report.","operationId":"get_compliance_report_pdf_reports__bin__pdf_get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/address/lookup":{"get":{"tags":["reports"],"summary":"Get Report By Address","description":"Resolve address to BIN via Geoclient, then return compliance report.","operationId":"get_report_by_address_reports_address_lookup_get","parameters":[{"name":"house_number","in":"query","required":true,"schema":{"type":"string","title":"House Number"}},{"name":"street","in":"query","required":true,"schema":{"type":"string","title":"Street"}},{"name":"borough","in":"query","required":true,"schema":{"type":"string","title":"Borough"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/calendar/events":{"get":{"tags":["calendar"],"summary":"Get Calendar Events","description":"Get upcoming compliance deadline events for the authenticated company.","operationId":"get_calendar_events_calendar_events_get","parameters":[{"name":"start","in":"query","required":false,"schema":{"type":"string","description":"Start date YYYY-MM-DD","title":"Start"},"description":"Start date YYYY-MM-DD"},{"name":"end","in":"query","required":false,"schema":{"type":"string","description":"End date YYYY-MM-DD","title":"End"},"description":"End date YYYY-MM-DD"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","description":"Create a Stripe Checkout session for subscription upgrade.","operationId":"create_checkout_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Create Portal","description":"Create a Stripe Customer Portal session for billing management.","operationId":"create_portal_billing_portal_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/preferences/":{"get":{"tags":["preferences"],"summary":"List Preferences","description":"List all notification preferences for the authenticated company.","operationId":"list_preferences_preferences__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PreferenceOut"},"type":"array","title":"Response List Preferences Preferences  Get"}}}}}},"post":{"tags":["preferences"],"summary":"Create Preference","description":"Create a new notification preference.","operationId":"create_preference_preferences__post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferenceCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferenceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/preferences/{pref_id}":{"put":{"tags":["preferences"],"summary":"Update Preference","description":"Update an existing notification preference.","operationId":"update_preference_preferences__pref_id__put","parameters":[{"name":"pref_id","in":"path","required":true,"schema":{"type":"string","title":"Pref Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferenceUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferenceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/risk/{bin}/history":{"get":{"tags":["risk"],"summary":"Get Risk History","description":"Return risk score history for a BIN (last 30 days).","operationId":"get_risk_history_risk__bin__history_get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/exports/report/{bin}/pdf":{"get":{"tags":["exports"],"summary":"Download Pdf Report","description":"Download a branded PDF compliance report for a BIN.\n\nRequires Professional tier or above.","operationId":"download_pdf_report_exports_report__bin__pdf_get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/companies":{"get":{"tags":["admin"],"summary":"List Companies","description":"List all companies with usage stats.","operationId":"list_companies_admin_companies_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/companies/{company_id}/tier":{"put":{"tags":["admin"],"summary":"Update Company Tier","description":"Override a company's subscription tier (admin only).\n\n`free` was removed because no billing or usage path supports it\n(TIER_LIMITS in services/usage.py and the price allow-list in\nroutes/billing.py both reject it). `standard` was the pre-rename\nlabel for `starter` and is preserved as a read-only alias in\n`dependencies.TIER_RANK` for in-flight Stripe subscriptions, but\nadmin writes must use the canonical `starter` going forward so we\ndon't multiply tier names in fresh rows.","operationId":"update_company_tier_admin_companies__company_id__tier_put","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TierUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/companies/{company_id}":{"delete":{"tags":["admin"],"summary":"Admin Delete Company","description":"Admin-initiated account deletion.\n\nSame cascade behaviour as the customer-facing DELETE /companies/me\n(FK ON DELETE CASCADE on most tables, audit_log rows anonymized to\nNULL company_id so the trail survives). Logs a `company_deleted_by_admin`\naudit row BEFORE the cascade fires so the admin's identity is on\nrecord with the company name + timestamp. The audit row is then\nanonymized along with everything else, leaving a NULL-company_id\nrow in audit_log naming the admin who did it.\n\nNo two-step body confirmation here — admins routinely target\naccounts by ID and we don't want to invent a different ergonomics\nthan the existing admin endpoints (tier override, etc.). The\nClerk-admin-IDs allowlist is the access control.","operationId":"admin_delete_company_admin_companies__company_id__delete","parameters":[{"name":"company_id","in":"path","required":true,"schema":{"type":"string","title":"Company Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/pipeline-health":{"get":{"tags":["admin"],"summary":"Get Pipeline Health","description":"Detailed pipeline health with service statuses and last-run timestamps.","operationId":"get_pipeline_health_admin_pipeline_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/metrics/weekly":{"get":{"tags":["admin"],"summary":"Get Weekly Metrics","description":"Return the most recent weekly metric snapshots (default trailing 8).\n\nSnapshots are written by `compute_weekly_metrics` Celery task every\nMonday at 5:00 UTC. Read this endpoint to see matcher precision,\ndedup health, alert lead time, onboarding TTV, engagement per\nalert_type, and fuzzy graduation readiness over time.\n\nReturns empty `items` if no snapshots exist yet (first run of the\ntask hasn't fired).","operationId":"get_weekly_metrics_admin_metrics_weekly_get","parameters":[{"name":"weeks","in":"query","required":false,"schema":{"type":"integer","maximum":52,"minimum":1,"default":8,"title":"Weeks"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api-keys":{"get":{"tags":["admin"],"summary":"Admin List Api Keys","description":"List every API key in the system (admin only). No plaintexts.","operationId":"admin_list_api_keys_admin_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ApiKeyOut"},"type":"array","title":"Response Admin List Api Keys Admin Api Keys Get"}}}}}},"post":{"tags":["admin"],"summary":"Admin Create Api Key","description":"Mint an API key (admin only). The plaintext is returned ONCE.","operationId":"admin_create_api_key_admin_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api-keys/{key_id}":{"delete":{"tags":["admin"],"summary":"Admin Revoke Api Key","description":"Revoke (soft-delete) an API key by setting revoked_at.\n\nHard-deletes are intentionally not supported: the audit trail is\nmore useful if you can still see which keys existed and when they\nwere turned off.","operationId":"admin_revoke_api_key_admin_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/webhooks":{"get":{"tags":["integrations"],"summary":"List Webhooks","description":"List all registered webhooks for the authenticated company.","operationId":"list_webhooks_integrations_webhooks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["integrations"],"summary":"Create Webhook","description":"Register an outbound webhook URL. Enterprise tier required.\n\nReturns the webhook registration including a signing secret.\nStore the secret securely — it won't be shown again.","operationId":"create_webhook_integrations_webhooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/webhooks/{webhook_id}":{"delete":{"tags":["integrations"],"summary":"Delete Webhook","description":"Remove a registered webhook.","operationId":"delete_webhook_integrations_webhooks__webhook_id__delete","parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/today":{"get":{"tags":["today"],"summary":"Get Today","operationId":"get_today_today_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Today Today Get"}}}}}}},"/pulse":{"get":{"tags":["pulse"],"summary":"Get Pulse","operationId":"get_pulse_pulse_get","parameters":[{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"owner | site","title":"Scope"},"description":"owner | site"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"},"title":"Response Get Pulse Pulse Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/bin/{bin}":{"get":{"tags":["public"],"summary":"Get Public Compliance Report","description":"Property compliance report for a BIN, gated by API key.\n\nSame response shape as `GET /reports/{bin}` (which is the route the\nbrowser uses behind Turnstile). The MCP server, partner backends,\nand any other server-to-server caller should target this endpoint\ninstead.\n\nSide note on freshness: we call the same SODA backfill as the\npublic browser route so a key holder asking about a cold BIN\ntriggers the fetch-and-cache cycle. The 24h compliance-report\ncache means subsequent calls within the window are served from\nPostgres without hitting NYC.","operationId":"get_public_compliance_report_v1_public_bin__bin__get","parameters":[{"name":"bin","in":"path","required":true,"schema":{"type":"string","title":"Bin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/public/address/lookup":{"get":{"tags":["public"],"summary":"Get Public Report By Address","description":"Address -> BIN -> compliance report, gated by API key.\n\nMirrors `GET /reports/address/lookup` so the MCP `lookup_address`\ntool can resolve a borough-keyed street address into the same\ncompliance report payload as `/v1/public/bin/{bin}`.","operationId":"get_public_report_by_address_v1_public_address_lookup_get","parameters":[{"name":"house_number","in":"query","required":true,"schema":{"type":"string","title":"House Number"}},{"name":"street","in":"query","required":true,"schema":{"type":"string","title":"Street"}},{"name":"borough","in":"query","required":true,"schema":{"type":"string","title":"Borough"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email-actions/resolve":{"get":{"tags":["email-actions"],"summary":"Get Resolve","description":"Email-anchor resolve: a contractor taps \"Responded\" in their alert\nemail, the email client opens this URL, we render a confirmation\npage. No login required.","operationId":"get_resolve_email_actions_resolve_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","description":"Signed resolution token.","default":"","title":"Token"},"description":"Signed resolution token."},{"name":"resolution_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(renewed|responded|appeared|dismissed|noise|other|)$","description":"Resolution type, must match the token's signed value.","default":"","title":"Resolution Type"},"description":"Resolution type, must match the token's signed value."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["email-actions"],"summary":"Post Resolve","description":"Programmatic resolve. Used by any client that wants to POST a\nJSON body instead of clicking through a GET anchor. Same trust\nboundary: the token is the auth.","operationId":"post_resolve_email_actions_resolve_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveTokenIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email-actions/closure-complete":{"get":{"tags":["email-actions"],"summary":"Closure Complete","description":"Mark a closure_check's underlying completing-outcome as kept_promise=True\n(late but kept). Dismisses the closure_check alert.","operationId":"closure_complete_email_actions_closure_complete_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email-actions/closure-extend":{"get":{"tags":["email-actions"],"summary":"Closure Extend Form","description":"Render a date-picker form so the contractor can choose a new expected\ncompletion date without logging in.","operationId":"closure_extend_form_email_actions_closure_extend_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["email-actions"],"summary":"Closure Extend Submit","description":"Accept the new date from the closure-extend form and create a fresh\ncompleting-outcome on the closure_check alert, then dismiss it.","operationId":"closure_extend_submit_email_actions_closure_extend_post","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_closure_extend_submit_email_actions_closure_extend_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/roi-summary":{"get":{"tags":["dashboard"],"summary":"Get Roi Summary","description":"Return month-to-date Outcome Loop aggregates for the dashboard tile.\n\nShape:\n{\n  \"month_label\": \"May 2026\",\n  \"handled_count\": 12,\n  \"fines_avoided_estimated\": 27500,\n  \"by_resolution_type\": {\n    \"renewed\": 4, \"responded\": 3, \"appeared\": 2,\n    \"dismissed\": 2, \"noise\": 1, \"other\": 0\n  },\n  \"comparison_last_month\": {\n    \"handled_count\": 9,\n    \"fines_avoided_estimated\": 20000,\n    \"change_pct\": 33.3,           # null when last_month is 0\n  }\n}","operationId":"get_roi_summary_dashboard_roi_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Roi Summary Dashboard Roi Summary Get"}}}}}}},"/dashboard/activity":{"get":{"tags":["dashboard"],"summary":"Get Activity","operationId":"get_activity_dashboard_activity_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","description":"Public health check — returns only status, no internal details.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AlertListResponse":{"properties":{"total":{"type":"integer","title":"Total"},"items":{"items":{"$ref":"#/components/schemas/AlertOut"},"type":"array","title":"Items"}},"type":"object","required":["total","items"],"title":"AlertListResponse"},"AlertOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"regulatory_update_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Regulatory Update Id"},"compliance_item_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compliance Item Id"},"alert_type":{"type":"string","title":"Alert Type"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"severity":{"type":"string","title":"Severity"},"is_read":{"type":"boolean","title":"Is Read"},"is_dismissed":{"type":"boolean","title":"Is Dismissed"},"action_taken":{"type":"boolean","title":"Action Taken"},"action_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action Notes"},"bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bin"},"trigger_explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trigger Explanation"},"delivered_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Delivered At"},"read_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Read At"},"dismissed_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dismissed At"},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"outcome":{"anyOf":[{"$ref":"#/components/schemas/AlertOutcomeNested"},{"type":"null"}]}},"type":"object","required":["id","company_id","alert_type","title","summary","severity","is_read","is_dismissed","action_taken"],"title":"AlertOut"},"AlertOutcomeNested":{"properties":{"resolution_type":{"type":"string","title":"Resolution Type"},"resolved_at":{"type":"string","title":"Resolved At"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"estimated_value_usd":{"type":"integer","title":"Estimated Value Usd"}},"type":"object","required":["resolution_type","resolved_at","estimated_value_usd"],"title":"AlertOutcomeNested"},"ApiKeyCreate":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Label","description":"Optional human-readable label (e.g. 'Claude Desktop')"},"company_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Id","description":"Admin-only: which company to scope the key to. Self-service endpoints ignore this field and always use the caller's company."},"scopes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Scopes","description":"Override the default scopes (`['public:read']`). Admin-only."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Optional expiration timestamp. Omit for non-expiring keys."}},"type":"object","title":"ApiKeyCreate","description":"Body for POST /admin/api-keys or POST /companies/me/api-keys."},"ApiKeyCreated":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"key_prefix":{"type":"string","title":"Key Prefix"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At"},"plaintext_key":{"type":"string","title":"Plaintext Key","description":"The full plaintext key. Save it now; it cannot be retrieved later."}},"type":"object","required":["id","company_id","label","key_prefix","scopes","created_at","last_used_at","expires_at","revoked_at","plaintext_key"],"title":"ApiKeyCreated","description":"Creation response — includes the plaintext token, returned ONCE."},"ApiKeyOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"key_prefix":{"type":"string","title":"Key Prefix"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At"}},"type":"object","required":["id","company_id","label","key_prefix","scopes","created_at","last_used_at","expires_at","revoked_at"],"title":"ApiKeyOut","description":"Listing / revoke response — never includes the plaintext token."},"Body_closure_extend_submit_email_actions_closure_extend_post":{"properties":{"token":{"type":"string","title":"Token"},"expected_completion_date":{"type":"string","title":"Expected Completion Date"}},"type":"object","required":["token","expected_completion_date"],"title":"Body_closure_extend_submit_email_actions_closure_extend_post"},"BulkWatchedEntityCreate":{"properties":{"entities":{"items":{"$ref":"#/components/schemas/BulkWatchedEntityItem"},"type":"array","title":"Entities"}},"type":"object","required":["entities"],"title":"BulkWatchedEntityCreate"},"BulkWatchedEntityItem":{"properties":{"entity_name":{"type":"string","title":"Entity Name"},"dob_bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dob Bin"},"entity_type":{"type":"string","title":"Entity Type","default":"job_site"}},"type":"object","required":["entity_name"],"title":"BulkWatchedEntityItem"},"BulkWatchedEntityResult":{"properties":{"created":{"type":"integer","title":"Created"},"skipped":{"type":"integer","title":"Skipped"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","required":["created","skipped","errors"],"title":"BulkWatchedEntityResult"},"CheckoutRequest":{"properties":{"tier":{"type":"string","title":"Tier"},"success_url":{"type":"string","title":"Success Url"},"cancel_url":{"type":"string","title":"Cancel Url"},"billing_cycle":{"type":"string","enum":["monthly","yearly"],"title":"Billing Cycle","default":"monthly"}},"type":"object","required":["tier","success_url","cancel_url"],"title":"CheckoutRequest"},"CheckoutResponse":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"CheckoutResponse"},"CompanyContactCreate":{"properties":{"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"is_primary":{"type":"boolean","title":"Is Primary","default":false},"receives_alerts":{"type":"boolean","title":"Receives Alerts","default":true}},"type":"object","required":["first_name","last_name","email"],"title":"CompanyContactCreate"},"CompanyContactOut":{"properties":{"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"is_primary":{"type":"boolean","title":"Is Primary","default":false},"receives_alerts":{"type":"boolean","title":"Receives Alerts","default":true},"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["first_name","last_name","email","id","company_id"],"title":"CompanyContactOut"},"CompanyCreate":{"properties":{"name":{"type":"string","title":"Name"},"dba_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dba Name"},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein"},"borough":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Borough"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"type":"string","title":"City","default":"New York"},"state":{"type":"string","title":"State","default":"NY"},"zip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zip"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"employee_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Employee Count"},"trade_type":{"type":"string","title":"Trade Type","default":"HVAC"},"contacts":{"items":{"$ref":"#/components/schemas/CompanyContactCreate"},"type":"array","title":"Contacts","default":[]},"pe_associations":{"items":{"$ref":"#/components/schemas/CompanyPECreate"},"type":"array","title":"Pe Associations","default":[]},"watched_entities":{"items":{"$ref":"#/components/schemas/WatchedEntityCreate"},"type":"array","title":"Watched Entities","default":[]}},"type":"object","required":["name"],"title":"CompanyCreate"},"CompanyDeleteConfirmation":{"properties":{"confirm_company_name":{"type":"string","title":"Confirm Company Name"}},"type":"object","required":["confirm_company_name"],"title":"CompanyDeleteConfirmation","description":"Two-step confirmation for DELETE /companies/me.\n\nCaller must echo the company's exact `name` field. Prevents trivial\nmistakes (misclicks, autofilled forms) from nuking a paying account.\nThe match is case-sensitive on a trimmed comparison; the privacy\npolicy promises 30-day fulfilment so we'd rather refuse a typo and\nbounce the request than silently delete the wrong account."},"CompanyOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"dba_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dba Name"},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein"},"borough":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Borough"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State"},"zip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zip"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"employee_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Employee Count"},"trade_type":{"type":"string","title":"Trade Type"},"license_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License Number"},"subscription_tier":{"type":"string","title":"Subscription Tier"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"subscription_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Status"},"risk_score":{"type":"integer","title":"Risk Score"},"onboarding_complete":{"type":"boolean","title":"Onboarding Complete"},"email_alerts":{"type":"boolean","title":"Email Alerts","default":true},"sms_alerts":{"type":"boolean","title":"Sms Alerts","default":false},"preferred_language":{"type":"string","title":"Preferred Language","default":"en"},"notify_morning_brief_email":{"type":"boolean","title":"Notify Morning Brief Email","default":false},"notify_morning_brief_sms":{"type":"boolean","title":"Notify Morning Brief Sms","default":false},"notify_alerts_email":{"type":"boolean","title":"Notify Alerts Email","default":true},"notify_alerts_sms":{"type":"boolean","title":"Notify Alerts Sms","default":false},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"contacts":{"items":{"$ref":"#/components/schemas/CompanyContactOut"},"type":"array","title":"Contacts","default":[]},"pe_associations":{"items":{"$ref":"#/components/schemas/CompanyPEOut"},"type":"array","title":"Pe Associations","default":[]},"watched_entities":{"items":{"$ref":"#/components/schemas/WatchedEntityOut"},"type":"array","title":"Watched Entities","default":[]},"compliance_items":{"items":{"$ref":"#/components/schemas/ComplianceItemOut"},"type":"array","title":"Compliance Items","default":[]},"violations":{"items":{"$ref":"#/components/schemas/ViolationOut"},"type":"array","title":"Violations","default":[]}},"type":"object","required":["id","name","city","state","trade_type","subscription_tier","risk_score","onboarding_complete"],"title":"CompanyOut","description":"Full company representation including the compliance picture.\n\nReturned by POST /companies/ (creation) and GET /companies/{id}.\nCompliance items and violations are populated by the pipeline;\nthey will be empty lists for a freshly onboarded company.\n\nAlert history is NOT included here — use GET /alerts?company_id= instead,\nwhich supports pagination and filtering."},"CompanyPECreate":{"properties":{"pe_license_number":{"type":"string","title":"Pe License Number"},"pe_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pe First Name"},"pe_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pe Last Name"},"relationship_type":{"type":"string","title":"Relationship Type","default":"primary"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["pe_license_number"],"title":"CompanyPECreate"},"CompanyPEOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"pe_license_number":{"type":"string","title":"Pe License Number"},"pe_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pe First Name"},"pe_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pe Last Name"},"relationship_type":{"type":"string","title":"Relationship Type"},"verified_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verified Date"},"verified_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verified By"},"is_active":{"type":"boolean","title":"Is Active"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","company_id","pe_license_number","relationship_type","is_active"],"title":"CompanyPEOut"},"CompanyUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"dba_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dba Name"},"ein":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ein"},"borough":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Borough"},"address_line1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line1"},"address_line2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"zip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zip"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"employee_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Employee Count"},"trade_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trade Type"},"license_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License Number"},"email_alerts":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Email Alerts"},"sms_alerts":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Sms Alerts"}},"type":"object","title":"CompanyUpdate","description":"PATCH-style update: only supplied fields are written.\n\nNote: subscription_tier, onboarding_complete, and risk_score are\nadmin-only fields and are intentionally excluded from this schema.\nThey are managed via internal admin endpoints (not yet implemented)."},"ComplianceItemOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"category":{"type":"string","title":"Category"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agency"},"reference_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Number"},"expiration_date":{"anyOf":[{"type":"string"},{"type":"string","format":"date"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expiration Date"},"effective_date":{"anyOf":[{"type":"string"},{"type":"string","format":"date"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Effective Date"},"days_until_expiry":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Until Expiry"},"renewal_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Renewal Url"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","company_id","category","name","status"],"title":"ComplianceItemOut"},"DiscoverPermitsRequest":{"properties":{"license_number":{"type":"string","maxLength":50,"minLength":1,"title":"License Number"}},"type":"object","required":["license_number"],"title":"DiscoverPermitsRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LeadCreate":{"properties":{"company_name":{"type":"string","title":"Company Name"},"contact_name":{"type":"string","title":"Contact Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"pain_point":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pain Point"},"source":{"type":"string","title":"Source","default":"landing_page"}},"type":"object","required":["company_name","contact_name","email"],"title":"LeadCreate"},"LeadOut":{"properties":{"company_name":{"type":"string","title":"Company Name"},"contact_name":{"type":"string","title":"Contact Name"},"email":{"type":"string","title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"pain_point":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pain Point"},"source":{"type":"string","title":"Source","default":"landing_page"},"id":{"type":"string","title":"Id"},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["company_name","contact_name","email","id"],"title":"LeadOut"},"NotificationPrefsIn":{"properties":{"preferred_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Language"},"notify_morning_brief_email":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Morning Brief Email"},"notify_morning_brief_sms":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Morning Brief Sms"},"notify_alerts_email":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Alerts Email"},"notify_alerts_sms":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Alerts Sms"}},"type":"object","title":"NotificationPrefsIn","description":"Partial-update schema for PATCH /companies/me/notifications.\n\nAll fields optional so the frontend can send a single-toggle patch\nwithout re-serialising the entire company object."},"OutcomeOut":{"properties":{"id":{"type":"string","title":"Id"},"company_alert_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Alert Id"},"triage_event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Triage Event Id"},"resolved_at":{"type":"string","title":"Resolved At"},"resolution_type":{"type":"string","title":"Resolution Type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"estimated_value_usd":{"type":"integer","title":"Estimated Value Usd"}},"type":"object","required":["id","resolved_at","resolution_type","estimated_value_usd"],"title":"OutcomeOut"},"PortalRequest":{"properties":{"return_url":{"type":"string","title":"Return Url"}},"type":"object","required":["return_url"],"title":"PortalRequest"},"PortalResponse":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"PortalResponse"},"PreferenceCreate":{"properties":{"channel":{"type":"string","title":"Channel"},"alert_types":{"items":{"type":"string"},"type":"array","title":"Alert Types","default":["regulatory_change","expiry_warning","violation","enforcement_trend"]},"min_severity":{"type":"string","title":"Min Severity","default":"low"},"is_enabled":{"type":"boolean","title":"Is Enabled","default":true},"contact_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Id"}},"type":"object","required":["channel"],"title":"PreferenceCreate"},"PreferenceOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"contact_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Id"},"channel":{"type":"string","title":"Channel"},"alert_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Alert Types"},"min_severity":{"type":"string","title":"Min Severity"},"is_enabled":{"type":"boolean","title":"Is Enabled"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["id","company_id","channel","min_severity","is_enabled"],"title":"PreferenceOut"},"PreferenceUpdate":{"properties":{"alert_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Alert Types"},"min_severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Severity"},"is_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Enabled"}},"type":"object","title":"PreferenceUpdate"},"ResolutionIn":{"properties":{"resolution_type":{"type":"string","enum":["renewed","responded","appeared","dismissed","noise","other","completing"],"title":"Resolution Type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"expected_completion_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Expected Completion Date"}},"type":"object","required":["resolution_type"],"title":"ResolutionIn"},"ResolveAddressRequest":{"properties":{"address":{"type":"string","maxLength":200,"minLength":1,"title":"Address"},"borough":{"type":"string","maxLength":30,"minLength":1,"title":"Borough"}},"type":"object","required":["address","borough"],"title":"ResolveAddressRequest"},"ResolveAddressResponse":{"properties":{"bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bin"},"normalized_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Normalized Address"},"borough":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Borough"},"bbl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bbl"},"resolved":{"type":"boolean","title":"Resolved"}},"type":"object","required":["resolved"],"title":"ResolveAddressResponse"},"ResolveTokenIn":{"properties":{"token":{"type":"string","title":"Token","description":"Signed resolution token from the alert email."},"resolution_type":{"type":"string","pattern":"^(renewed|responded|appeared|dismissed|noise|other)$","title":"Resolution Type","description":"Resolution type. Must match the token's signed resolution_type."}},"type":"object","required":["token","resolution_type"],"title":"ResolveTokenIn"},"ResolvedTriageEvent":{"properties":{"event":{"$ref":"#/components/schemas/TriageEvent"},"resolution_type":{"type":"string","title":"Resolution Type"},"resolved_at":{"type":"string","title":"Resolved At"}},"type":"object","required":["event","resolution_type","resolved_at"],"title":"ResolvedTriageEvent","description":"A triage event that's been Mark-Handled within the past 7 days.\n\nWraps a TriageEvent with the resolution metadata so the FE has\neverything it needs to render a row in the ResolvedTail without a\nsecond round-trip. `event` carries the original summary/kind/severity\nsnapshot; `resolution_type` and `resolved_at` come from alert_outcomes."},"SnoozeIn":{"properties":{"days":{"type":"integer","enum":[1,7],"title":"Days","description":"Snooze duration. 1 = next-day, 7 = next-week."}},"type":"object","required":["days"],"title":"SnoozeIn"},"SnoozeOut":{"properties":{"triage_event_id":{"type":"string","title":"Triage Event Id"},"snooze_until":{"type":"string","format":"date-time","title":"Snooze Until"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["triage_event_id","snooze_until","created_at"],"title":"SnoozeOut"},"TeamMemberCreate":{"properties":{"clerk_user_id":{"type":"string","maxLength":255,"minLength":1,"title":"Clerk User Id"},"role":{"type":"string","pattern":"^(admin|viewer)$","title":"Role","default":"viewer"}},"type":"object","required":["clerk_user_id"],"title":"TeamMemberCreate"},"TierUpdate":{"properties":{"tier":{"type":"string","title":"Tier"}},"type":"object","required":["tier"],"title":"TierUpdate"},"TriageBucket":{"type":"string","enum":["unresolved","today","this_week","later"],"title":"TriageBucket"},"TriageEvent":{"properties":{"id":{"type":"string","title":"Id"},"kind":{"$ref":"#/components/schemas/TriageKind"},"attribution":{"type":"string","pattern":"^(owner|site)$","title":"Attribution"},"status":{"$ref":"#/components/schemas/TriageStatus"},"severity":{"$ref":"#/components/schemas/TriageSeverity"},"summary":{"type":"string","title":"Summary"},"bucket":{"anyOf":[{"$ref":"#/components/schemas/TriageBucket"},{"type":"null"}]},"occurred_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred At"},"deadline_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deadline At"},"days_open":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Open"},"days_until":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Until"},"property_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Property Id"},"bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bin"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"},"dollar_context":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Dollar Context"},"reference_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Number"},"trigger_explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trigger Explanation"},"disposition_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disposition Code"},"commitment_state":{"type":"string","enum":["none","active","capped"],"title":"Commitment State","default":"none"},"commitment_expected_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commitment Expected Date"}},"type":"object","required":["id","kind","attribution","status","severity","summary"],"title":"TriageEvent","description":"A single row in the triage feed.\n\n`bucket` is None at construction time; the TriageService assigns it as the\nfinal step of `get_triage()`. Building events with bucket pre-set in tests\nis allowed for direct bucket-rule unit tests."},"TriageKind":{"type":"string","enum":["violation","complaint","permit_expiring","hearing","inspection","license"],"title":"TriageKind"},"TriageResolveOut":{"properties":{"resolved":{"type":"boolean","title":"Resolved"},"id":{"type":"string","title":"Id"},"triage_event_id":{"type":"string","title":"Triage Event Id"},"resolution_type":{"type":"string","title":"Resolution Type"},"resolved_at":{"type":"string","title":"Resolved At"}},"type":"object","required":["resolved","id","triage_event_id","resolution_type","resolved_at"],"title":"TriageResolveOut","description":"Response shape for POST /alerts/triage/{event_id}/resolve.\n\nMirrors OutcomeOut's relevant fields but always returns triage_event_id\n(the legacy /alerts/{id}/resolve route always returns company_alert_id)."},"TriageResponse":{"properties":{"events":{"items":{"$ref":"#/components/schemas/TriageEvent"},"type":"array","title":"Events"},"counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Counts"},"resolved":{"items":{"$ref":"#/components/schemas/ResolvedTriageEvent"},"type":"array","title":"Resolved","default":[]}},"type":"object","required":["events","counts"],"title":"TriageResponse","description":"Top-level response shape for GET /alerts/triage."},"TriageSeverity":{"type":"string","enum":["red","amber","green"],"title":"TriageSeverity"},"TriageStatus":{"type":"string","enum":["unresolved","upcoming","past"],"title":"TriageStatus"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ViolationOut":{"properties":{"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"violation_type":{"type":"string","title":"Violation Type"},"source_agency":{"type":"string","title":"Source Agency"},"reference_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Number"},"description":{"type":"string","title":"Description"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"violation_date":{"anyOf":[{"type":"string"},{"type":"string","format":"date"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Violation Date"},"status":{"type":"string","title":"Status"},"penalty_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Penalty Amount"},"hearing_date":{"anyOf":[{"type":"string"},{"type":"string","format":"date"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Hearing Date"},"risk_severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Risk Severity"},"suggested_actions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Actions"}},"type":"object","required":["id","company_id","violation_type","source_agency","description","status"],"title":"ViolationOut"},"WatchedEntityCreate":{"properties":{"entity_name":{"type":"string","title":"Entity Name"},"entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"},"dob_bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dob Bin"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["entity_name"],"title":"WatchedEntityCreate"},"WatchedEntityOut":{"properties":{"entity_name":{"type":"string","title":"Entity Name"},"entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"},"dob_bin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dob Bin"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"id":{"type":"string","title":"Id"},"company_id":{"type":"string","title":"Company Id"},"created_at":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["entity_name","id","company_id"],"title":"WatchedEntityOut"},"WebhookCreate":{"properties":{"url":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Url"},"event_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Event Types"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["url"],"title":"WebhookCreate"}}}}