whatsapp

Using Whatsapp Business API, I am not able to subscribe WABA to webhooks


I have been verified as Tech Provider for Whatsapp. I have implemented the embedded signup flow for Whats app and doing the following thing:

  1. Exchange the token with system user access token
  2. Get WABA ID (via Graph API)
  3. Get Phone Number ID (via Graph API)
  4. Register Phone Number (via Graph API)
  5. Subscribing For Webhook Notifications (via Graph API)

All other requests work fine except the last one, subscribing for Webhook Notifications. It gives the following exception:

Unsupported post request. Object with ID '475530585635833' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api

Has any body experienced the same? Any workaround/solution?

Here is the code:

This is the sequence in which the requests are made:

// 1. Obtain exchanged token
const exchangedToken = await this.exchangeFacebookCode(code);console.log("exchangedToken:", exchangedToken);
// 2. Obtain WABA ID
const wabaId = await this.fetchWABA(exchangedToken);
console.log("wabaId:", wabaId);
// 3. Obtain Phone Number ID
const number = await this.fetchPhoneNumber(exchangedToken, wabaId);
console.log("number:", number);
// 4. Register Phone Number
await this.registerPhoneNumber(exchangedToken, number.id);
// 5. Subscribe to Webhook
await this.subscribeToWebhook(exchangedToken, wabaId);
return { id: number.id, number: number.display_phone_number};

These are the method implementation

private async exchangeFacebookCode(code: string): Promise<string> {
const appId = "**********";
const appSecret = "**********";
try {
const response = await firstValueFrom(this.httpService.get(`https://graph.facebook.com/v12.0/oauth/access_token?client_id=${appId}&client_secret=${appSecret}&code=${code}`));
            console.log(JSON.stringify(response.data));
            const { access_token: token } = response.data;
            return token;
        } catch (e) {
            console.log("error:", e);
            return undefined;
        }
    }

    private async fetchWABA(token: string): Promise<string> {
        try {
            const observable = this.httpService.get(`https://graph.facebook.com/v21.0/debug_token?input_token=${token}`, {
                headers: {
                    "Authorization": `Bearer ${token}`
                }
            });
            const response = await lastValueFrom(observable);
            const { data } = response.data;
            console.log("WABA response:", JSON.stringify(response.data));
            const { granular_scopes: scopes } = data;
            const scope = (scopes as any[]).find(scope => scope.scope === "whatsapp_business_management");
            return scope.target_ids[0];
        } catch (e) {
            console.log("error:", e);
            return undefined;
        }
    }

    private async fetchPhoneNumber(token: string, wabaId: string): Promise<any> {
        try {
            const observable = this.httpService.get(`https://graph.facebook.com/v21.0/${wabaId}/phone_numbers?access_token=${token}`);
            const response = await lastValueFrom(observable);
            console.log("PhoneNumber ID response:", response.data);
            const { data } = response.data;
            const phoneNumber = data as any[];
            return phoneNumber && phoneNumber.length > 0 && phoneNumber[0];
        } catch (e) {
            console.log("Error during fetch phone number:", e.response.data);
        }
    }

    private async registerPhoneNumber(token: string, phoneNumberId: string): Promise<void> {
        try {
            const observable = this.httpService.post(`https://graph.facebook.com/v21.0/${phoneNumberId}/register`, {
                messaging_product: "whatsapp",
                pin: "123456"
            }, {
                headers: {
                    "Authorization": `Bearer ${token}`,
                }
            });
            const response = await lastValueFrom(observable);
            console.log("Register response:", response.data);
        } catch (e) {
            console.log("Error during phone registration:", e);
        }
    }

    private async subscribeToWebhook(token: string, wabaId: string): Promise<void> {
        try {
            const observable = this.httpService.post(`https://graph.facebook.com/v21.0/${wabaId}/subscribed_apps`, {
                headers: {
                    "Authorization": `Bearer ${token}`
                }
            });
            const response = await lastValueFrom(observable);
            console.log("Subscription response:", response.data);
        } catch (e) {
            console.log("Error during webhook subscription:", e.response.data);
        }
    }

Solution

  • Finally, I was able to fix it. I was trying to pass the token in headers whereas it was required to be pass as a query parameter

    private async subscribeToWebhook(token: string, wabaId: string): Promise<void> {
        try {
            const observable = this.httpService.post(`https://graph.facebook.com/v21.0/${wabaId}/subscribed_apps?token=${token}`);
            const response = await lastValueFrom(observable);
            console.log("Subscription response:", response.data);
        } catch (e) {
            console.log("Error during webhook subscription:", e.response.data);
        }
    }