diff --git a/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb b/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb index 14fd5cee3..b83723f84 100644 --- a/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/whatsapp_calls_controller.rb @@ -123,7 +123,7 @@ class Api::V1::Accounts::WhatsappCallsController < Api::V1::Accounts::BaseContro next end - sent = provider_service.send_call_permission_request(@conversation.contact.phone_number.delete('+')) + sent = send_permission_request_safely if sent record_permission_request_wamid(sent) status = 'permission_requested' @@ -142,6 +142,15 @@ class Api::V1::Accounts::WhatsappCallsController < Api::V1::Accounts::BaseContro last_requested.present? && Time.zone.parse(last_requested) > PERMISSION_REQUEST_THROTTLE.ago end + # Treat transport errors the same as a falsy provider return so the action renders 422 + # rather than letting Faraday/HTTParty exceptions bubble up as 500s. + def send_permission_request_safely + provider_service.send_call_permission_request(@conversation.contact.phone_number.delete('+')) + rescue StandardError => e + Rails.logger.warn "[WHATSAPP CALL] permission_request failed: #{e.class} #{e.message}" + nil + end + # Record the wamid so the reply webhook can match context.id back to this conversation. def record_permission_request_wamid(sent) attrs = (@conversation.additional_attributes || {}).merge( diff --git a/spec/enterprise/controllers/api/v1/accounts/whatsapp_calls_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/whatsapp_calls_controller_spec.rb index f86d5745c..bfae8d64d 100644 --- a/spec/enterprise/controllers/api/v1/accounts/whatsapp_calls_controller_spec.rb +++ b/spec/enterprise/controllers/api/v1/accounts/whatsapp_calls_controller_spec.rb @@ -118,6 +118,18 @@ RSpec.describe 'WhatsApp Calls API', type: :request do expect(attrs['call_permission_request_message_id']).to eq('wamid.req_xyz') end + it 'returns permission_request_failed when send_call_permission_request raises a transport error' do + allow(provider_service).to receive(:initiate_call).and_raise(Voice::CallErrors::NoCallPermission) + allow(provider_service).to receive(:send_call_permission_request).and_raise(Faraday::TimeoutError) + + post "/api/v1/accounts/#{account.id}/whatsapp_calls/initiate", + params: { conversation_id: initiate_conversation.display_id, sdp_offer: 'sdp_offer' }, + headers: agent.create_new_auth_token + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.parsed_body['error']).to eq(I18n.t('errors.whatsapp.calls.permission_request_failed')) + end + it 'returns 422 when sdp_offer is missing' do post "/api/v1/accounts/#{account.id}/whatsapp_calls/initiate", params: { conversation_id: initiate_conversation.display_id },