fix: Subscribe app to WABA before overriding webhook callback URL (#13279)
#### Problem
Meta requires the app to be subscribed to the WABA before
`override_callback_uri` can be used. The current implementation tries to
use `override_callback_uri` directly, which fails with:
> Error 100: "Before override the current callback uri, your app must be
subscribed to receive messages for WhatsApp Business Account"
This causes embedded signup to fail silently, the inbox appears
connected but never receives messages.
#### Solution
Split `subscribe_waba_webhook` into two sequential API calls:
```ruby
def subscribe_waba_webhook(waba_id, callback_url, verify_token)
# Step 1: Subscribe app to WABA first (required before override)
subscribe_app_to_waba(waba_id)
# Step 2: Override callback URL for this specific WABA
override_waba_callback(waba_id, callback_url, verify_token)
end
```
#### References
- Subscribe app to WABA's webhooks: https://www.postman.com/meta/whatsapp-business-platform/request/ju40fld/subscribe-app-to-waba-s-webhooks
- Override Callback URL (Embedded Signup): https://www.postman.com/meta/whatsapp-business-platform/request/l6a09ow/override-callback-url
Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
@@ -61,6 +61,25 @@ class Whatsapp::FacebookApiClient
|
||||
end
|
||||
|
||||
def subscribe_waba_webhook(waba_id, callback_url, verify_token)
|
||||
# Step 1: Subscribe app to WABA first (required before override)
|
||||
# Meta requires the app to be subscribed before using override_callback_uri
|
||||
# See: https://github.com/chatwoot/chatwoot/issues/13097
|
||||
subscribe_app_to_waba(waba_id)
|
||||
|
||||
# Step 2: Override callback URL for this specific WABA
|
||||
override_waba_callback(waba_id, callback_url, verify_token)
|
||||
end
|
||||
|
||||
def subscribe_app_to_waba(waba_id)
|
||||
response = HTTParty.post(
|
||||
"#{BASE_URI}/#{@api_version}/#{waba_id}/subscribed_apps",
|
||||
headers: request_headers
|
||||
)
|
||||
|
||||
handle_response(response, 'App subscription to WABA failed')
|
||||
end
|
||||
|
||||
def override_waba_callback(waba_id, callback_url, verify_token)
|
||||
response = HTTParty.post(
|
||||
"#{BASE_URI}/#{@api_version}/#{waba_id}/subscribed_apps",
|
||||
headers: request_headers,
|
||||
@@ -71,7 +90,7 @@ class Whatsapp::FacebookApiClient
|
||||
}.to_json
|
||||
)
|
||||
|
||||
handle_response(response, 'Webhook subscription failed')
|
||||
handle_response(response, 'Webhook callback override failed')
|
||||
end
|
||||
|
||||
def unsubscribe_waba_webhook(waba_id)
|
||||
|
||||
@@ -161,6 +161,18 @@ describe Whatsapp::FacebookApiClient do
|
||||
|
||||
context 'when successful' do
|
||||
before do
|
||||
# Step 1: Subscribe app to WABA (no body)
|
||||
stub_request(:post, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps")
|
||||
.with(
|
||||
headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' }
|
||||
)
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: { success: true }.to_json,
|
||||
headers: { 'Content-Type' => 'application/json' }
|
||||
)
|
||||
|
||||
# Step 2: Override callback URL (with body)
|
||||
stub_request(:post, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps")
|
||||
.with(
|
||||
headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' },
|
||||
@@ -180,19 +192,45 @@ describe Whatsapp::FacebookApiClient do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when failed' do
|
||||
context 'when app subscription fails' do
|
||||
before do
|
||||
stub_request(:post, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps")
|
||||
.with(
|
||||
headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' }
|
||||
)
|
||||
.to_return(status: 400, body: { error: 'App subscription to WABA failed' }.to_json)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { api_client.subscribe_waba_webhook(waba_id, callback_url, verify_token) }.to raise_error(/App subscription to WABA failed/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when callback override fails' do
|
||||
before do
|
||||
# Step 1 succeeds
|
||||
stub_request(:post, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps")
|
||||
.with(
|
||||
headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' }
|
||||
)
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: { success: true }.to_json,
|
||||
headers: { 'Content-Type' => 'application/json' }
|
||||
)
|
||||
|
||||
# Step 2 fails
|
||||
stub_request(:post, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps")
|
||||
.with(
|
||||
headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' },
|
||||
body: { override_callback_uri: callback_url, verify_token: verify_token,
|
||||
subscribed_fields: %w[messages smb_message_echoes] }.to_json
|
||||
)
|
||||
.to_return(status: 400, body: { error: 'Webhook subscription failed' }.to_json)
|
||||
.to_return(status: 400, body: { error: 'Webhook callback override failed' }.to_json)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { api_client.subscribe_waba_webhook(waba_id, callback_url, verify_token) }.to raise_error(/Webhook subscription failed/)
|
||||
expect { api_client.subscribe_waba_webhook(waba_id, callback_url, verify_token) }.to raise_error(/Webhook callback override failed/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user