This gates API-token access and outgoing account webhooks behind the `api_and_webhooks` account feature introduced in #14972. On Chatwoot Cloud, Hacker accounts lose token-authenticated account API access and account webhook delivery, while paid accounts retain them through the billing-plan feature reconcile. Community and self-hosted installations continue to work without any upgrade-time interruption. ## What changed - Added `Account#api_and_webhooks_enabled?` as the single backend kill switch. Core returns enabled; the Enterprise override consults the account flag on Chatwoot Cloud and remains enabled off-Cloud. - Account-scoped v1 and v2 requests authenticated with a user or agent-bot API token now return `403 Forbidden` when the feature is disabled. Invalid tokens still return 401, and dashboard session requests are unaffected. - Profile responses return an empty access token when none of the user's accounts has access. The stored token is preserved, and the profile UI disables its token controls with paid-plan copy on Cloud. - Account webhook delivery stops when the feature is disabled. Webhook CRUD remains available to session-authenticated dashboard requests, API-inbox webhooks continue to be delivered, and the Cloud dashboard shows a webhook paywall instead of the webhook list. - Removed the database backfill migration. Existing paid Cloud accounts should be enabled with the one-off script below before enforcement is deployed. ## Existing paid-account rollout Run this as an ad-hoc Rails runner script on Chatwoot Cloud. It intentionally targets only the Startups, Business, and Enterprise plans and does not add `api_and_webhooks` to `manually_managed_features`, so future billing reconciles remain authoritative. ```rb paid_plan_names = %w[Startups Business Enterprise] accounts = Account.where("custom_attributes ->> 'plan_name' IN (?)", paid_plan_names) total = accounts.count enabled = 0 skipped = 0 puts "Enabling api_and_webhooks for #{total} paid account(s)..." accounts.find_each(batch_size: 500).with_index(1) do |account, processed| if account.feature_enabled?('api_and_webhooks') skipped += 1 else account.enable_features!('api_and_webhooks') enabled += 1 end puts "Processed #{processed}/#{total}..." if (processed % 1000).zero? end puts "Done! Enabled: #{enabled}, Skipped: #{skipped}, Total: #{total}" ``` For example, save the snippet outside the repository as `enable_api_and_webhooks.rb`, then run: ```sh bundle exec rails runner /path/to/enable_api_and_webhooks.rb ``` ## How to test - On Cloud, use a Hacker account and confirm token-authenticated requests to account-scoped v1 and v2 endpoints return 403, while the same dashboard actions continue to work through session authentication. - Confirm profile access-token controls are disabled with paid-plan copy when all accounts are ineligible, and remain available when at least one account has the feature. - Confirm the Webhooks settings page shows the billing paywall for a Cloud account without the feature; admins get the billing action and agents get the existing ask-an-admin message. - Confirm outgoing account webhooks stop for an ineligible Cloud account while API-inbox webhooks still deliver. - Confirm community and self-hosted installations retain API and webhook behavior after upgrading, even when an existing account does not have the stored feature bit. ### Screenshots ## Cloud <img width="2590" height="642" alt="CleanShot 2026-07-15 at 15 13 14@2x" src="https://github.com/user-attachments/assets/431a7bd8-1742-4e7a-b312-d3ad92015f9b" /> <img width="2152" height="994" alt="CleanShot 2026-07-15 at 15 14 37@2x" src="https://github.com/user-attachments/assets/475dda48-d1c5-4be5-a3c3-7a96b9713724" /> --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
67 lines
2.3 KiB
JavaScript
67 lines
2.3 KiB
JavaScript
export const FEATURE_FLAGS = {
|
|
AGENT_BOTS: 'agent_bots',
|
|
AGENT_MANAGEMENT: 'agent_management',
|
|
ASSIGNMENT_V2: 'assignment_v2',
|
|
ADVANCED_ASSIGNMENT: 'advanced_assignment',
|
|
AUTO_RESOLVE_CONVERSATIONS: 'auto_resolve_conversations',
|
|
AUTOMATIONS: 'automations',
|
|
CAMPAIGNS: 'campaigns',
|
|
WHATSAPP_CAMPAIGNS: 'whatsapp_campaign',
|
|
WHATSAPP_MANUAL_TRANSFER: 'whatsapp_manual_transfer',
|
|
CANNED_RESPONSES: 'canned_responses',
|
|
CRM: 'crm',
|
|
CUSTOM_ATTRIBUTES: 'custom_attributes',
|
|
DATA_IMPORT: 'data_import',
|
|
API_AND_WEBHOOKS: 'api_and_webhooks',
|
|
INBOX_MANAGEMENT: 'inbox_management',
|
|
INTEGRATIONS: 'integrations',
|
|
LABELS: 'labels',
|
|
MACROS: 'macros',
|
|
HELP_CENTER: 'help_center',
|
|
REPORTS: 'reports',
|
|
TEAM_MANAGEMENT: 'team_management',
|
|
VOICE_RECORDER: 'voice_recorder',
|
|
AUDIT_LOGS: 'audit_logs',
|
|
INBOX_VIEW: 'inbox_view',
|
|
SLA: 'sla',
|
|
CHANNEL_EMAIL: 'channel_email',
|
|
CHANNEL_FACEBOOK: 'channel_facebook',
|
|
CHANNEL_WEBSITE: 'channel_website',
|
|
CUSTOM_REPLY_DOMAIN: 'custom_reply_domain',
|
|
CUSTOM_REPLY_EMAIL: 'custom_reply_email',
|
|
DISABLE_BRANDING: 'disable_branding',
|
|
EMAIL_CONTINUITY_ON_API_CHANNEL: 'email_continuity_on_api_channel',
|
|
INBOUND_EMAILS: 'inbound_emails',
|
|
IP_LOOKUP: 'ip_lookup',
|
|
LINEAR: 'linear_integration',
|
|
CAPTAIN: 'captain_integration',
|
|
CUSTOM_ROLES: 'custom_roles',
|
|
CHATWOOT_V4: 'chatwoot_v4',
|
|
CHANNEL_INSTAGRAM: 'channel_instagram',
|
|
CHANNEL_TIKTOK: 'channel_tiktok',
|
|
CHANNEL_VOICE: 'channel_voice',
|
|
CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
|
|
CAPTAIN_CUSTOM_TOOLS: 'custom_tools',
|
|
CAPTAIN_V2: 'captain_integration_v2',
|
|
CAPTAIN_TASKS: 'captain_tasks',
|
|
CAPTAIN_DOCUMENT_AUTO_SYNC: 'captain_document_auto_sync',
|
|
SAML: 'saml',
|
|
COMPANIES: 'companies',
|
|
ADVANCED_SEARCH: 'advanced_search',
|
|
CONVERSATION_REQUIRED_ATTRIBUTES: 'conversation_required_attributes',
|
|
CONVERSATION_UNREAD_COUNTS: 'conversation_unread_counts',
|
|
UNREAD_COUNT_FOR_FILTERS: 'unread_count_for_filters',
|
|
};
|
|
|
|
export const PREMIUM_FEATURES = [
|
|
FEATURE_FLAGS.SLA,
|
|
FEATURE_FLAGS.CAPTAIN,
|
|
FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS,
|
|
FEATURE_FLAGS.CUSTOM_ROLES,
|
|
FEATURE_FLAGS.AUDIT_LOGS,
|
|
FEATURE_FLAGS.HELP_CENTER,
|
|
FEATURE_FLAGS.SAML,
|
|
FEATURE_FLAGS.CONVERSATION_REQUIRED_ATTRIBUTES,
|
|
FEATURE_FLAGS.ADVANCED_ASSIGNMENT,
|
|
];
|