I have been verified as Tech Provider for Whatsapp. I have implemented the embedded signup flow for Whats app and doing the following thing:
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);
}
}
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);
}
}