From 13918c046d5cca7dc836f6ff639b271de9b60010 Mon Sep 17 00:00:00 2001
From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com>
Date: Wed, 9 Jul 2025 17:23:48 +0700
Subject: [PATCH] add reauth flow for wa embedded signup
---
.../whatsapp/embedded_controller.rb | 43 +++
.../composables/useWhatsappReauthorization.js | 317 ++++++++++++++++++
.../dashboard/i18n/locale/en/inboxMgmt.json | 21 +-
.../dashboard/settings/inbox/Settings.vue | 8 +
.../inbox/channels/whatsapp/Reauthorize.vue | 38 +++
.../whatsapp/embedded_signup_service.rb | 52 ++-
app/views/api/v1/models/_inbox.json.jbuilder | 1 +
config/routes.rb | 1 +
get_business_account_path.rb | 99 ++++++
9 files changed, 578 insertions(+), 2 deletions(-)
create mode 100644 app/javascript/dashboard/composables/useWhatsappReauthorization.js
create mode 100644 app/javascript/dashboard/routes/dashboard/settings/inbox/channels/whatsapp/Reauthorize.vue
create mode 100755 get_business_account_path.rb
diff --git a/app/controllers/whatsapp/embedded_controller.rb b/app/controllers/whatsapp/embedded_controller.rb
index 625a11f3e..feb582cc2 100644
--- a/app/controllers/whatsapp/embedded_controller.rb
+++ b/app/controllers/whatsapp/embedded_controller.rb
@@ -32,6 +32,28 @@ class Whatsapp::EmbeddedController < ApplicationController
handle_signup_error(e)
end
+ def reauthorize
+ # Reauthorize existing WhatsApp inbox using embedded signup flow
+ validate_authorization_code!
+ return if performed?
+
+ validate_required_parameters!
+ return if performed?
+
+ validate_inbox_id!
+ return if performed?
+
+ channel = process_reauthorization
+ @inbox = channel.inbox
+
+ # Clear reauthorization required flag
+ channel.reauthorized!
+
+ render json: { message: 'WhatsApp channel reauthorized successfully' }, status: :ok
+ rescue StandardError => e
+ handle_signup_error(e)
+ end
+
private
def validate_authorization_code!
@@ -51,6 +73,14 @@ class Whatsapp::EmbeddedController < ApplicationController
}, status: :bad_request
end
+ def validate_inbox_id!
+ return if params[:inbox_id].present?
+
+ render json: {
+ error: 'Missing inbox_id parameter'
+ }, status: :bad_request
+ end
+
def process_signup
service = Whatsapp::EmbeddedSignupService.new(
account: Current.account,
@@ -63,6 +93,19 @@ class Whatsapp::EmbeddedController < ApplicationController
service.perform
end
+ def process_reauthorization
+ service = Whatsapp::EmbeddedSignupService.new(
+ account: Current.account,
+ code: params[:code],
+ business_id: params[:business_id],
+ waba_id: params[:waba_id],
+ phone_number_id: params[:phone_number_id],
+ inbox_id: params[:inbox_id]
+ )
+
+ service.perform_reauthorization
+ end
+
def handle_signup_error(error)
Rails.logger.error("WhatsApp embedded signup processing error: #{error.message}")
Rails.logger.error(error.backtrace.join("\n"))
diff --git a/app/javascript/dashboard/composables/useWhatsappReauthorization.js b/app/javascript/dashboard/composables/useWhatsappReauthorization.js
new file mode 100644
index 000000000..47ca43b18
--- /dev/null
+++ b/app/javascript/dashboard/composables/useWhatsappReauthorization.js
@@ -0,0 +1,317 @@
+import { ref, computed } from 'vue';
+import { useStore } from 'vuex';
+import { useRouter } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+import { useAlert } from 'dashboard/composables';
+import Auth from 'dashboard/api/auth';
+
+export function useWhatsappReauthorization(inboxId) {
+ const store = useStore();
+ const router = useRouter();
+ const { t } = useI18n();
+
+ // State
+ const fbSdkLoaded = ref(false);
+ const isProcessing = ref(false);
+ const processingMessage = ref('');
+ const authCodeReceived = ref(false);
+ const authCode = ref(null);
+ const businessData = ref(null);
+ const isAuthenticating = ref(false);
+
+ // Computed
+ const authHeaders = computed(() => {
+ if (Auth.hasAuthCookie()) {
+ const {
+ 'access-token': accessToken,
+ 'token-type': tokenType,
+ client,
+ expiry,
+ uid,
+ } = Auth.getAuthData();
+ return {
+ 'access-token': accessToken,
+ 'token-type': tokenType,
+ client,
+ expiry,
+ uid,
+ };
+ }
+ return {};
+ });
+
+ const showLoader = computed(
+ () => isAuthenticating.value || isProcessing.value
+ );
+
+ // Error handling
+ const handleReauthorizationError = data => {
+ isProcessing.value = false;
+ authCodeReceived.value = false;
+ isAuthenticating.value = false;
+
+ const errorMessage =
+ data.error ||
+ data.message ||
+ t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.ERROR');
+ useAlert(errorMessage);
+ };
+
+ const handleReauthorizationCancellation = () => {
+ isProcessing.value = false;
+ authCodeReceived.value = false;
+ isAuthenticating.value = false;
+
+ useAlert(t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.CANCELLED'));
+ };
+
+ const handleReauthorizationSuccess = async () => {
+ isProcessing.value = false;
+ isAuthenticating.value = false;
+
+ // Refresh the inbox to update reauthorization status
+ await store.dispatch('inboxes/get');
+ useAlert(t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.SUCCESS'));
+
+ // Reload the page to reflect the changes
+ router.go(0);
+ };
+
+ // Reauthorization flow
+ const completeReauthorizationFlow = async businessDataParam => {
+ if (!authCodeReceived.value || !authCode.value) {
+ handleReauthorizationError({
+ error: t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.AUTH_NOT_COMPLETED'),
+ });
+ return;
+ }
+
+ isProcessing.value = true;
+ processingMessage.value = t(
+ 'INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.PROCESSING'
+ );
+
+ try {
+ // Send reauthorization request
+ const accountId = store.getters.getCurrentAccountId;
+ const response = await fetch('/whatsapp/reauthorize', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-Token': document
+ .querySelector('meta[name="csrf-token"]')
+ ?.getAttribute('content'),
+ ...authHeaders.value,
+ },
+ body: JSON.stringify({
+ account_id: accountId,
+ inbox_id: inboxId,
+ code: authCode.value,
+ business_id: businessDataParam.business_id,
+ waba_id: businessDataParam.waba_id,
+ phone_number_id: businessDataParam.phone_number_id,
+ }),
+ });
+
+ const responseData = await response.json();
+
+ if (response.ok) {
+ // Clear the stored auth code for security
+ authCode.value = null;
+
+ // Handle synchronous success response
+ handleReauthorizationSuccess();
+ } else {
+ throw new Error(responseData.message || responseData.error);
+ }
+ } catch (error) {
+ handleReauthorizationError({ error: error.message });
+ }
+ };
+
+ const isValidBusinessData = businessDataLocal => {
+ return (
+ businessDataLocal &&
+ (businessDataLocal.business_id || businessDataLocal.businessId) &&
+ (businessDataLocal.waba_id || businessDataLocal.wabaId)
+ );
+ };
+
+ // Message handling
+ const handleEmbeddedSignupData = async data => {
+ // Handle different embedded signup events per Facebook documentation
+ if (data.event === 'FINISH') {
+ // Facebook might send business data in different structures
+ let businessDataLocal = data.data;
+
+ // If data.data doesn't exist, try other possible structures
+ if (!businessDataLocal) {
+ businessDataLocal = data.business_data || data.details || data;
+ }
+
+ // Validate we have the required business information
+ if (isValidBusinessData(businessDataLocal)) {
+ // Normalize the data structure to match our backend expectations
+ const normalizedData = {
+ business_id:
+ businessDataLocal.business_id || businessDataLocal.businessId,
+ waba_id: businessDataLocal.waba_id || businessDataLocal.wabaId,
+ phone_number_id:
+ businessDataLocal.phone_number_id ||
+ businessDataLocal.phoneNumberId ||
+ businessDataLocal.phone_id,
+ };
+
+ // Store business data
+ businessData.value = normalizedData;
+ // Check if we already have auth code and process immediately
+ if (authCodeReceived.value && authCode.value) {
+ await completeReauthorizationFlow(normalizedData);
+ } else {
+ processingMessage.value = t(
+ 'INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.WAITING_FOR_AUTH'
+ );
+ }
+ } else {
+ handleReauthorizationError({
+ error: t(
+ 'INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.INVALID_BUSINESS_DATA'
+ ),
+ });
+ }
+ } else if (data.event === 'CANCEL') {
+ handleReauthorizationCancellation();
+ } else if (data.event === 'error') {
+ handleReauthorizationError({
+ error:
+ data.error_message ||
+ t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.ERROR'),
+ });
+ }
+ };
+
+ const fbLoginCallback = response => {
+ if (response.authResponse && response.authResponse.code) {
+ // Authorization code received from Facebook
+ authCode.value = response.authResponse.code;
+ authCodeReceived.value = true;
+ processingMessage.value = t(
+ 'INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.WAITING_FOR_BUSINESS_INFO'
+ );
+
+ // Check if we already have business data and process immediately
+ if (businessData.value) {
+ completeReauthorizationFlow(businessData.value);
+ }
+ } else if (response.error) {
+ handleReauthorizationError({ error: response.error });
+ } else {
+ isProcessing.value = false;
+ isAuthenticating.value = false;
+ useAlert(t('INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.CANCELLED'));
+ }
+ };
+
+ const handleSignupMessage = event => {
+ // Handle Facebook embedded signup message events
+ try {
+ const originUrl = new URL(event.origin);
+ const allowedHosts = ['facebook.com', 'www.facebook.com'];
+ if (!allowedHosts.includes(originUrl.hostname)) return;
+ } catch (error) {
+ // Invalid origin URL, reject the event
+ return;
+ }
+
+ try {
+ const data = JSON.parse(event.data);
+
+ if (data.type === 'WA_EMBEDDED_SIGNUP') {
+ handleEmbeddedSignupData(data);
+ }
+ } catch (error) {
+ // Handle non-JSON messages silently
+ }
+ };
+
+ // Facebook SDK
+ const loadFacebookSdk = () => {
+ if (window.FB) {
+ fbSdkLoaded.value = true;
+ return;
+ }
+ const script = document.createElement('script');
+ script.src = 'https://connect.facebook.net/en_US/sdk.js';
+ script.async = true;
+ script.defer = true;
+ script.onload = () => {
+ window.FB.init({
+ appId: window.chatwootConfig?.whatsappAppId,
+ status: true,
+ xfbml: true,
+ version: window.chatwootConfig?.whatsappApiVersion || 'v22.0',
+ });
+ fbSdkLoaded.value = true;
+ };
+ document.body.appendChild(script);
+ };
+
+ const launchReauthorization = () => {
+ processingMessage.value = t(
+ 'INBOX_MGMT.SETTINGS.WHATSAPP_REAUTHORIZE.AUTH_PROCESSING'
+ );
+
+ if (!window.FB) {
+ loadFacebookSdk();
+ setTimeout(() => launchReauthorization(), 1000);
+ return;
+ }
+
+ isAuthenticating.value = true;
+
+ // Following Facebook's embedded signup documentation
+ // Using auth_type: 'reauthorize' to force reauthorization
+ window.FB.login(fbLoginCallback, {
+ config_id: window.chatwootConfig?.whatsappConfigurationId,
+ response_type: 'code',
+ override_default_response_type: true,
+ auth_type: 'reauthorize',
+ extras: {
+ setup: {},
+ featureType: '', // Leave empty for default flow
+ sessionInfoVersion: '3',
+ },
+ });
+ };
+
+ // Lifecycle
+ const setupMessageListener = () => {
+ window.addEventListener('message', handleSignupMessage);
+ };
+
+ const cleanupMessageListener = () => {
+ window.removeEventListener('message', handleSignupMessage);
+ };
+
+ // Initialize
+ const initialize = () => {
+ loadFacebookSdk();
+ setupMessageListener();
+ };
+
+ return {
+ // State
+ fbSdkLoaded,
+ isProcessing,
+ processingMessage,
+ isAuthenticating,
+
+ // Computed
+ showLoader,
+
+ // Methods
+ launchReauthorization,
+ initialize,
+ cleanupMessageListener,
+ };
+}
diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
index eb999a0e5..9a986523d 100644
--- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
+++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
@@ -600,7 +600,20 @@
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
- "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
+ "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings",
+ "WHATSAPP_REAUTHORIZE": {
+ "TITLE": "Reauthorize WhatsApp Connection",
+ "DESCRIPTION": "Your WhatsApp Business account needs to be reauthorized to continue receiving messages. Click the button below to reconnect your account.",
+ "AUTH_PROCESSING": "Processing WhatsApp reauthorization...",
+ "WAITING_FOR_BUSINESS_INFO": "Waiting for business information...",
+ "WAITING_FOR_AUTH": "Waiting for authentication...",
+ "PROCESSING": "Updating your WhatsApp configuration...",
+ "SUCCESS": "WhatsApp successfully reauthorized!",
+ "ERROR": "Failed to reauthorize WhatsApp. Please try again.",
+ "CANCELLED": "WhatsApp reauthorization was cancelled.",
+ "AUTH_NOT_COMPLETED": "Authentication not completed. Please try again.",
+ "INVALID_BUSINESS_DATA": "Invalid business data received. Please try again."
+ }
},
"HELP_CENTER": {
"LABEL": "Help Center",
@@ -620,6 +633,12 @@
"MESSAGE_SUCCESS": "Reconnection successful",
"MESSAGE_ERROR": "There was an error, please try again"
},
+ "WHATSAPP_REAUTHORIZE": {
+ "TITLE": "Reauthorize WhatsApp",
+ "SUBTITLE": "Your WhatsApp connection has expired, please reconnect your WhatsApp Business account to continue services",
+ "MESSAGE_SUCCESS": "WhatsApp reconnection successful",
+ "MESSAGE_ERROR": "There was an error reconnecting WhatsApp, please try again"
+ },
"PRE_CHAT_FORM": {
"DESCRIPTION": "Pre chat forms enable you to capture user information before they start conversation with you.",
"SET_FIELDS": "Pre chat form fields",
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue
index a3f60c6d5..783e0b881 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue
@@ -11,6 +11,7 @@ import InstagramReauthorize from './channels/instagram/Reauthorize.vue';
import DuplicateInboxBanner from './channels/instagram/DuplicateInboxBanner.vue';
import MicrosoftReauthorize from './channels/microsoft/Reauthorize.vue';
import GoogleReauthorize from './channels/google/Reauthorize.vue';
+import WhatsappReauthorize from './channels/whatsapp/Reauthorize.vue';
import PreChatFormSettings from './PreChatForm/Settings.vue';
import WeeklyAvailability from './components/WeeklyAvailability.vue';
import GreetingsEditor from 'shared/components/GreetingsEditor.vue';
@@ -45,6 +46,7 @@ export default {
NextButton,
InstagramReauthorize,
DuplicateInboxBanner,
+ WhatsappReauthorize,
Editor,
},
mixins: [inboxMixin],
@@ -231,6 +233,11 @@ export default {
facebookUnauthorized() {
return this.isAFacebookInbox && this.inbox.reauthorization_required;
},
+ whatsappUnauthorized() {
+ return (
+ this.isAWhatsAppCloudChannel && this.inbox.reauthorization_required
+ );
+ },
googleUnauthorized() {
const isLegacyInbox = ['imap.gmail.com', 'imap.google.com'].includes(
this.inbox.imap_address
@@ -410,6 +417,7 @@ export default {
+
+import { onMounted, onBeforeUnmount } from 'vue';
+import InboxReconnectionRequired from '../../components/InboxReconnectionRequired.vue';
+import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
+import { useWhatsappReauthorization } from 'dashboard/composables/useWhatsappReauthorization';
+
+const props = defineProps({
+ inbox: {
+ type: Object,
+ required: true,
+ },
+});
+const {
+ processingMessage,
+ showLoader,
+ launchReauthorization,
+ initialize,
+ cleanupMessageListener,
+} = useWhatsappReauthorization(props.inbox.id);
+
+onMounted(() => {
+ initialize();
+});
+
+onBeforeUnmount(() => {
+ cleanupMessageListener();
+});
+
+
+
+
+
+
+
+
diff --git a/app/services/whatsapp/embedded_signup_service.rb b/app/services/whatsapp/embedded_signup_service.rb
index 95ecfac2b..d99b526dd 100644
--- a/app/services/whatsapp/embedded_signup_service.rb
+++ b/app/services/whatsapp/embedded_signup_service.rb
@@ -1,12 +1,13 @@
class Whatsapp::EmbeddedSignupService
include Rails.application.routes.url_helpers
- def initialize(account:, code:, business_id:, waba_id:, phone_number_id:)
+ def initialize(account:, code:, business_id:, waba_id:, phone_number_id:, inbox_id: nil)
@account = account
@code = code
@business_id = business_id
@waba_id = waba_id
@phone_number_id = phone_number_id
+ @inbox_id = inbox_id
end
def perform
@@ -33,6 +34,43 @@ class Whatsapp::EmbeddedSignupService
raise e
end
+ def perform_reauthorization
+ # Validate required parameters
+ unless @code.present? && @business_id.present? && @waba_id.present? && @phone_number_id.present? && @inbox_id.present?
+ raise ArgumentError, 'Code, business_id, waba_id, phone_number_id, and inbox_id are all required for reauthorization'
+ end
+
+ # Find the existing inbox and channel
+ inbox = @account.inboxes.find_by(id: @inbox_id)
+ raise ActiveRecord::RecordNotFound, 'Inbox not found' unless inbox
+ raise ArgumentError, 'Inbox is not a WhatsApp channel' unless inbox.channel_type == 'Channel::Whatsapp'
+
+ channel = inbox.channel
+ raise ArgumentError, 'Channel is not WhatsApp Cloud provider' unless channel.provider == 'whatsapp_cloud'
+
+ GlobalConfig.clear_cache
+ # Exchange code for new access token
+ access_token = exchange_code_for_token
+
+ # Use the provided business info directly
+ phone_info = fetch_phone_info_via_waba(@waba_id, @phone_number_id, access_token)
+
+ # Validate that the token has access to the provided WABA
+ validate_token_waba_access(access_token, @waba_id)
+
+ # Update the channel with new access token and configuration
+ update_channel_for_reauthorization(channel, phone_info, access_token)
+
+ # Re-register webhook with new token
+ register_phone_number(phone_info[:phone_number_id], access_token)
+ override_waba_webhook(@waba_id, channel, access_token)
+
+ channel
+ rescue StandardError => e
+ Rails.logger.error("[WHATSAPP] Reauthorization failed: #{e.message}")
+ raise e
+ end
+
private
def whatsapp_api_version
@@ -138,6 +176,18 @@ class Whatsapp::EmbeddedSignupService
)
end
+ def update_channel_for_reauthorization(channel, phone_info, access_token)
+ # Update channel with new access token and configuration
+ channel.update!(
+ provider_config: channel.provider_config.merge(
+ 'api_key' => access_token,
+ 'phone_number_id' => phone_info[:phone_number_id],
+ 'business_account_id' => @waba_id,
+ 'reauthorized_at' => Time.current.iso8601
+ )
+ )
+ end
+
def sanitize_phone_number(phone_number)
return phone_number if phone_number.blank?
diff --git a/app/views/api/v1/models/_inbox.json.jbuilder b/app/views/api/v1/models/_inbox.json.jbuilder
index c66a6eb78..8042ee47c 100644
--- a/app/views/api/v1/models/_inbox.json.jbuilder
+++ b/app/views/api/v1/models/_inbox.json.jbuilder
@@ -116,4 +116,5 @@ json.provider resource.channel.try(:provider)
if resource.whatsapp?
json.message_templates resource.channel.try(:message_templates)
json.provider_config resource.channel.try(:provider_config) if Current.account_user&.administrator?
+ json.reauthorization_required resource.channel.try(:reauthorization_required?)
end
diff --git a/config/routes.rb b/config/routes.rb
index 75119414c..578e15e71 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -486,6 +486,7 @@ Rails.application.routes.draw do
get 'signup', to: 'embedded#new'
get 'signup/callback', to: 'embedded#callback'
post 'embedded_signup', to: 'embedded#embedded_signup'
+ post 'reauthorize', to: 'embedded#reauthorize'
end
namespace :twitter do
diff --git a/get_business_account_path.rb b/get_business_account_path.rb
new file mode 100755
index 000000000..aef6ed500
--- /dev/null
+++ b/get_business_account_path.rb
@@ -0,0 +1,99 @@
+#!/usr/bin/env ruby
+
+# Script to get business account path for a specific inbox ID
+# Usage: ruby get_business_account_path.rb
+
+# Set the inbox ID to query
+INBOX_ID = 1090
+
+# Load Rails environment (assuming this script is run from the Rails app root)
+require_relative 'config/environment'
+
+def get_business_account_path(inbox_id)
+ # Find the inbox by ID
+ inbox = Inbox.find(inbox_id)
+
+ # Check if this is a WhatsApp inbox
+ unless inbox.whatsapp?
+ puts "Error: Inbox #{inbox_id} is not a WhatsApp inbox. Channel type: #{inbox.channel_type}"
+ return nil
+ end
+
+ # Get the WhatsApp channel
+ whatsapp_channel = inbox.channel
+
+ # Check if it's a WhatsApp Cloud provider
+ unless whatsapp_channel.provider == 'whatsapp_cloud'
+ puts "Error: Inbox #{inbox_id} is not using WhatsApp Cloud provider. Provider: #{whatsapp_channel.provider}"
+ return nil
+ end
+
+ # Get the business_account_id and api_key from provider_config
+ business_account_id = whatsapp_channel.provider_config['business_account_id']
+ api_key = whatsapp_channel.provider_config['api_key']
+
+ if business_account_id.blank?
+ puts "Error: No business_account_id found in provider_config for inbox #{inbox_id}"
+ return nil
+ end
+
+ if api_key.blank?
+ puts "Error: No api_key (access token) found in provider_config for inbox #{inbox_id}"
+ return nil
+ end
+
+ # Construct the business account path (following the pattern from WhatsappCloudService)
+ api_base_path = ENV.fetch('WHATSAPP_CLOUD_BASE_URL', 'https://graph.facebook.com')
+ business_account_path = "#{api_base_path}/v14.0/#{business_account_id}"
+
+ return {
+ inbox_id: inbox_id,
+ inbox_name: inbox.name,
+ business_account_id: business_account_id,
+ business_account_path: business_account_path,
+ provider: whatsapp_channel.provider,
+ phone_number: whatsapp_channel.phone_number,
+ api_key: api_key,
+ access_token: api_key # alias for clarity
+ }
+
+rescue ActiveRecord::RecordNotFound
+ puts "Error: Inbox with ID #{inbox_id} not found"
+ return nil
+rescue StandardError => e
+ puts "Error: #{e.message}"
+ puts e.backtrace.first(5).join("\n") if ENV['DEBUG']
+ return nil
+end
+
+# Main execution
+puts "Getting business account path for inbox ID: #{INBOX_ID}"
+puts '=' * 50
+
+result = get_business_account_path(INBOX_ID)
+
+if result
+ puts 'Success! Found WhatsApp Business Account details:'
+ puts
+ puts "Inbox ID: #{result[:inbox_id]}"
+ puts "Inbox Name: #{result[:inbox_name]}"
+ puts "Phone Number: #{result[:phone_number]}"
+ puts "Provider: #{result[:provider]}"
+ puts "Business Account ID: #{result[:business_account_id]}"
+ puts
+ puts 'Business Account Path:'
+ puts result[:business_account_path]
+ puts
+ puts 'Access Token (API Key):'
+ puts result[:access_token]
+ puts
+ puts 'Complete API Endpoint Examples:'
+ puts "• Message Templates: #{result[:business_account_path]}/message_templates?access_token=#{result[:access_token]}"
+ puts "• Phone Numbers: #{result[:business_account_path]}/phone_numbers?access_token=#{result[:access_token]}"
+ puts
+ puts 'Authorization Header Format:'
+ puts "Authorization: Bearer #{result[:access_token]}"
+else
+ puts "Failed to get business account path for inbox ID #{INBOX_ID}"
+ exit 1
+end
\ No newline at end of file