Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

n8n-nodes-whatsapp-buttons

Package Overview
Dependencies
Maintainers
0
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

n8n-nodes-whatsapp-buttons - npm Package Compare versions

Comparing version 0.1.6 to 0.2.0

dist/nodes/WhatsApp/GenericFunctions.d.ts

1

dist/credentials/WhatsAppButtonsApi.credentials.d.ts

@@ -5,5 +5,4 @@ import { ICredentialType, INodeProperties } from "n8n-workflow";

displayName: string;
icon: string;
documentationUrl: string;
properties: INodeProperties[];
}

@@ -8,3 +8,2 @@ "use strict";

this.displayName = "WhatsAppButtons API";
this.icon = "file:whatsappbuttons.svg";
this.documentationUrl = "https://docs.n8n.io/integrations/creating-nodes/build/declarative-style-node/";

@@ -20,4 +19,4 @@ this.properties = [

{
displayName: "Phone Number ID",
name: "phoneNumberID",
displayName: "Business Account ID",
name: "businessAccountID",
type: "string",

@@ -24,0 +23,0 @@ typeOptions: { password: false },

@@ -1,10 +0,14 @@

import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
export declare type SectionArray = Array<{
import type { ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from "n8n-workflow";
import { IExecuteFunctions } from "n8n-workflow";
export type ParameterArray = Array<{
parameterValue: string;
}>;
export type SectionArray = Array<{
sectionTitle: string;
buttonInSection: MidButtonArray;
}>;
export declare type MidButtonArray = {
export type MidButtonArray = {
buttons: ButtonArray;
};
export declare type ButtonArray = Array<{
export type ButtonArray = Array<{
buttonTitle: string;

@@ -15,3 +19,9 @@ buttonDescription: string;

description: INodeTypeDescription;
methods: {
loadOptions: {
getPhoneNumbers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
getTemplates(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
};
};
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
}

@@ -8,2 +8,5 @@ "use strict";

const axios_1 = __importDefault(require("axios"));
const WhatsAppTemplateBuilder_1 = require("./WhatsAppTemplateBuilder");
const n8n_workflow_1 = require("n8n-workflow");
const baseURL = "https://graph.facebook.com/v20.0";
class WhatsAppButtons {

@@ -13,7 +16,7 @@ constructor() {

displayName: "WhatsApp Buttons",
name: 'whatsAppButtons',
name: "whatsAppButtons",
icon: "file:whatsappbuttons.svg",
group: ["transform"],
version: 1,
subtitle: "0.1.6",
subtitle: "0.2.0",
description: "Send Message With Buttons",

@@ -45,2 +48,10 @@ defaults: {

},
{
name: "Template",
value: "template",
},
{
name: "Message",
value: "message",
},
],

@@ -68,5 +79,37 @@ default: "interactive",

required: true,
displayOptions: {
show: {
action: ["interactive", "listButtons", "message"],
},
},
description: "Enter the message to be sent",
},
{
displayName: "Sender Phone Number (or ID)",
name: "senderPhoneDynamicOption",
type: "options",
required: true,
default: "",
description: "The ID of the business account's phone number from which the message will be sent from",
typeOptions: {
loadOptionsMethod: "getPhoneNumbers",
},
},
{
displayName: "Templates",
name: "templates",
type: "options",
default: "",
placeholder: "Select Template To Send",
description: "Pull and Select a template to send",
typeOptions: {
loadOptionsMethod: "getTemplates",
},
displayOptions: {
show: {
action: ["template"],
},
},
},
{
displayName: "Recipient Phone Number",

@@ -105,12 +148,5 @@ name: "phoneNumber",

},
description: 'Enter the image URL',
description: "Enter the image URL",
},
{
displayName: "Footer",
name: "footer",
type: "string",
default: "",
description: "Will be presented at the bottom of the message",
},
{
displayName: "Max 3 Buttons",

@@ -215,123 +251,284 @@ name: "plainButton",

},
{
displayName: "Template Parameter List",
name: "templateParameterList",
placeholder: "Add Parameter",
type: "fixedCollection",
description: "Each template has a number of parameters shown as {{1}}, for every parameter add a text to replace it with",
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
action: ["template"],
},
},
default: {},
options: [
{
name: "parameters",
displayName: "Parameters",
values: [
{
displayName: "Parameter Value",
name: "parameterValue",
type: "string",
default: "",
description: "Value to replace the template parameter (e.g., {{1}}, {{2}})",
},
],
},
],
},
{
displayName: "Should Use Footer",
name: "footerToggle",
type: "boolean",
default: false,
description: "Whether to add a footer message",
},
{
displayName: "Footer",
name: "footer",
type: "string",
default: "",
description: "Will be presented at the bottom of the message",
displayOptions: {
show: {
footerToggle: [true],
},
},
},
{
displayName: "Should Use Proxy URL",
name: "proxyUrlToggle",
type: "boolean",
default: false,
description: "Whether to add a proxy URL that send the request to it instead of whatsapp servers",
},
{
displayName: "Proxy URL",
name: "proxyUrl",
type: "string",
default: "",
description: "Use this proxy to send the message to this URL instead of sending it to WhatsApp servers, meaning by using this value the you will be responsible for delivering the message",
displayOptions: {
show: {
proxyUrlToggle: [true],
},
},
},
],
};
this.methods = {
loadOptions: {
async getPhoneNumbers() {
const credentials = await this.getCredentials("whatsAppButtonsApi");
const response = await axios_1.default.get(`${baseURL}/${credentials.businessAccountID}/phone_numbers`, {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
const phoneNumbers = response.data.data;
if (phoneNumbers.length === 0) {
return [
{
name: "No Phone Numbers Available",
value: "",
},
];
}
return phoneNumbers.map((option) => ({
name: `${option.display_phone_number} - ${option.verified_name}`,
value: JSON.stringify(option),
}));
},
async getTemplates() {
const credentials = await this.getCredentials("whatsAppButtonsApi");
const response = await axios_1.default.get(`${baseURL}/${credentials.businessAccountID}/message_templates`, {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
const templates = response.data.data;
if (templates.length === 0) {
return [
{
name: "No Templates Available",
value: "",
},
];
}
return templates.map((option) => ({
name: option.name,
value: JSON.stringify(option),
}));
},
},
};
}
async execute() {
const baseURL = "https://graph.facebook.com/v17.0";
const action = this.getNodeParameter("action", 0);
const message = this.getNodeParameter("message", 0);
const phoneNumber = this.getNodeParameter("phoneNumber", 0);
const whatsappPhoneNumberIdString = this.getNodeParameter("senderPhoneDynamicOption", 0);
const whatsappPhoneNumber = JSON.parse(whatsappPhoneNumberIdString);
const proxyUrl = this.getNodeParameter("proxyUrl", 0, "");
const proxyUrlToggle = this.getNodeParameter("proxyUrlToggle", 0, false);
const credentials = await this.getCredentials("whatsAppButtonsApi");
const headerAction = this.getNodeParameter("headerAction", 0);
const footer = this.getNodeParameter("footer", 0, "");
const headerImageURL = this.getNodeParameter("headerImageURL", 0, "");
const credentials = await this.getCredentials("whatsAppButtonsApi");
let responseData;
let request;
let message = "";
const builder = new WhatsAppTemplateBuilder_1.WhatsAppTemplateBuilder();
const url = proxyUrl !== ""
? proxyUrl
: `${baseURL}/${whatsappPhoneNumber.id}/messages`;
const shouldUseProxyURL = proxyUrl !== "" && proxyUrlToggle;
try {
switch (action) {
case "message":
message = this.getNodeParameter("message", 0);
const handleSendingMessageRequest = async (url, phoneNumber, fromPhoneId, headerAction, headerImageURL, footer, messageText, credentials) => {
const templateBuilder = builder
.setRecipient(phoneNumber)
.setSender(fromPhoneId)
.setPlainMessage(messageText);
let json = {};
if (shouldUseProxyURL) {
json = {
body: templateBuilder.build(),
};
}
else {
json = templateBuilder.build();
}
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
};
responseData = (await handleSendingMessageRequest(url, phoneNumber, whatsappPhoneNumber.id, headerAction, headerImageURL, footer, message, credentials)).data;
break;
case "interactive":
console.log("interactive tapped");
message = this.getNodeParameter("message", 0);
const buttonFields = this.getNodeParameter("plainButton.fieldValues", 0, "");
request = handleInteractiveButtonsRequest(`${baseURL}/${credentials.phoneNumberID}/messages`, message, phoneNumber, headerAction, headerImageURL, footer, buttonFields, credentials);
responseData = (await request).data;
const handleInteractiveButtonsRequest = async (url, message, phoneNumber, fromPhoneId, headerAction, headerImageURL, footer, queryParameters, credentials) => {
const templateBuilder = builder
.setRecipient(phoneNumber)
.setSender(fromPhoneId)
.addInteractiveButton(message, queryParameters.map((parameter, index) => {
return {
id: `button_${index.toString()}`,
title: parameter.buttonTitle,
};
}));
let json = {};
if (shouldUseProxyURL) {
json = {
body: templateBuilder.build(),
};
}
else {
json = templateBuilder.build();
}
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
};
responseData = (await handleInteractiveButtonsRequest(url, message, phoneNumber, whatsappPhoneNumber.id, headerAction, headerImageURL, footer, buttonFields, credentials)).data;
break;
case "listButtons":
console.log("listButtons tapped");
message = this.getNodeParameter("message", 0);
const buttonFieldsWithDescription = this.getNodeParameter("buttonWithDescription.section", 0, "");
const listTitle = this.getNodeParameter("listTitle", 0);
request = handleListButtonsRequest(`${baseURL}/${credentials.phoneNumberID}/messages`, message, phoneNumber, headerAction, headerImageURL, footer, listTitle, buttonFieldsWithDescription, credentials);
responseData = (await request).data;
const handleListButtonsRequest = async (url, message, phoneNumber, fromPhoneId, headerAction, headerImageURL, footer, listTitle, sections, credentials) => {
let sectionsDict = [];
sections.forEach((section) => {
const buttons = section.buttonInSection.buttons.map((button, index) => {
return {
id: `button_${index.toString()}`,
title: button.buttonTitle,
description: button.buttonDescription,
};
});
sectionsDict.push({
title: section.sectionTitle,
rows: buttons,
});
});
const templateBuilder = builder
.setRecipient(phoneNumber)
.setSender(fromPhoneId)
.addInteractiveList(message, listTitle, sectionsDict, headerImageURL === "" ? null : headerImageURL, footer === "" ? null : footer);
let json = {};
if (shouldUseProxyURL) {
json = {
body: templateBuilder.build(),
};
}
else {
json = templateBuilder.build();
}
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
};
responseData = (await handleListButtonsRequest(url, message, phoneNumber, whatsappPhoneNumber.id, headerAction, headerImageURL, footer, listTitle, buttonFieldsWithDescription, credentials)).data;
break;
case "template":
const selectedTemplateNode = this.getNodeParameter("templates", 0);
const selectedTemplate = JSON.parse(selectedTemplateNode);
const parameters = this.getNodeParameter("templateParameterList.parameters", 0, "");
const handleSendingTemplateRequest = async (url, phoneNumber, fromPhoneId, headerAction, headerImageURL, footer, template, credentials, parameters) => {
const templateBuilder = builder
.setRecipient(phoneNumber)
.setSender(fromPhoneId)
.setTemplateName(template.name, template.language);
if (parameters && Array.isArray(parameters)) {
templateBuilder.addTemplateBodyParameter();
parameters.forEach((parameter) => {
templateBuilder.addTemplateBodyTextParameter(parameter.parameterValue);
});
}
if (headerAction === "image" && headerImageURL !== "") {
templateBuilder.addTemplateHeaderParameter();
templateBuilder.addTemplateHeaderImageParameter(headerImageURL);
}
let json = {};
if (shouldUseProxyURL) {
json = {
body: templateBuilder.build(),
templateSchema: template,
};
}
else {
json = templateBuilder.build();
}
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json",
},
});
};
responseData = (await handleSendingTemplateRequest(url, phoneNumber, whatsappPhoneNumber.id, headerAction, headerImageURL, footer, selectedTemplate, credentials, parameters)).data;
break;
}
const outputData = [{ json: responseData }];
return this.prepareOutputData(outputData);
return this.prepareOutputData([{ json: responseData }]);
}
catch (error) {
console.error(`Error making ${action} request to WhatsAppButtons API:`, error.message);
throw error;
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
}
function buildBaseJSON(phoneNumber, message, headerImageURL, footer) {
const json = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: "",
type: "interactive",
interactive: {
type: "",
body: {
text: "",
},
action: {},
},
};
json.to = phoneNumber;
json.interactive.body.text = message;
if (headerAction === "image") {
json.interactive.header = {
type: "image",
image: {
link: headerImageURL,
},
};
}
if (footer.length > 0) {
json.interactive.footer = {
text: footer,
};
}
return json;
}
function handleInteractiveButtonsRequest(url, message, phoneNumber, headerAction, headerImageURL, footer, queryParameters, credentials) {
const json = buildBaseJSON(phoneNumber, message, headerImageURL, footer);
json.interactive.type = 'button';
if (queryParameters.length > 0) {
let buttons = [];
queryParameters.forEach((button, index) => {
buttons.push({
type: "reply",
reply: {
id: `button_${index.toString()}`,
title: button.buttonTitle,
},
});
});
json.interactive.action.buttons = buttons;
}
console.log(JSON.stringify(json));
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json"
},
});
}
function handleListButtonsRequest(url, message, phoneNumber, headerAction, headerImageURL, footer, listTitle, sections, credentials) {
const json = buildBaseJSON(phoneNumber, message, headerImageURL, footer);
json.interactive.type = 'list';
let sectionsDict = [];
sections.forEach((section) => {
const buttons = section.buttonInSection.buttons.map((button, index) => {
return {
id: `button_${index.toString()}`,
title: button.buttonTitle,
description: button.buttonDescription
};
});
sectionsDict.push({
title: section.sectionTitle,
rows: buttons
});
});
json.interactive.action = {
button: listTitle,
sections: sectionsDict
};
console.log(JSON.stringify(json));
return axios_1.default.post(url, JSON.stringify(json), {
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
"Content-Type": "application/json"
},
});
}
}

@@ -338,0 +535,0 @@ }

{
"name": "n8n-nodes-whatsapp-buttons",
"version": "0.1.6",
"version": "0.2.0",
"description": "Encapsulate WhatsApp Business API for sending messages with actions",

@@ -18,4 +18,10 @@ "keywords": [

},
"engines": {
"node": ">=18.10",
"pnpm": ">=9.1"
},
"packageManager": "pnpm@9.1.4",
"main": "index.js",
"scripts": {
"preinstall": "npx only-allow pnpm",
"build": "tsc && gulp build:icons",

@@ -26,3 +32,3 @@ "dev": "tsc --watch",

"lintfix": "eslint nodes credentials package.json --fix",
"prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials package.json"
"prepublishOnly": "pnpm build && pnpm lint -c .eslintrc.prepublish.js nodes credentials package.json"
},

@@ -42,14 +48,16 @@ "files": [

"devDependencies": {
"@types/express": "^4.17.6",
"@types/request-promise-native": "~1.0.15",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"eslint": "^8.55.0",
"eslint-plugin-n8n-nodes-base": "*",
"@types/node": "^22.5.4",
"@typescript-eslint/parser": "^7.15.0",
"axios": "^1.7.7",
"eslint": "^8.56.0",
"eslint-plugin-n8n-nodes-base": "^1.16.1",
"gulp": "^4.0.2",
"n8n-core": "*",
"n8n-workflow": "*",
"prettier": "^2.7.1",
"typescript": "~4.8.4"
}
"prettier": "^3.3.2",
"typescript": "^5.5.3"
},
"peerDependencies": {
"n8n-workflow": "*"
},
"dependencies": {}
}
{
"name": "n8n-nodes-whatsapp-buttons",
"version": "0.1.6",
"version": "0.2.0",
"description": "Encapsulate WhatsApp Business API for sending messages with actions",

@@ -18,4 +18,10 @@ "keywords": [

},
"engines": {
"node": ">=18.10",
"pnpm": ">=9.1"
},
"packageManager": "pnpm@9.1.4",
"main": "index.js",
"scripts": {
"preinstall": "npx only-allow pnpm",
"build": "tsc && gulp build:icons",

@@ -26,3 +32,3 @@ "dev": "tsc --watch",

"lintfix": "eslint nodes credentials package.json --fix",
"prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials package.json"
"prepublishOnly": "pnpm build && pnpm lint -c .eslintrc.prepublish.js nodes credentials package.json"
},

@@ -42,14 +48,17 @@ "files": [

"devDependencies": {
"@types/express": "^4.17.6",
"@types/request-promise-native": "~1.0.15",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"eslint": "^8.55.0",
"eslint-plugin-n8n-nodes-base": "*",
"@types/node": "^22.5.4",
"@typescript-eslint/parser": "^7.15.0",
"axios": "^1.7.7",
"eslint": "^8.56.0",
"eslint-plugin-n8n-nodes-base": "^1.16.1",
"gulp": "^4.0.2",
"n8n-core": "*",
"n8n-workflow": "*",
"prettier": "^2.7.1",
"typescript": "~4.8.4"
"prettier": "^3.3.2",
"typescript": "^5.5.3"
},
"peerDependencies": {
"n8n-workflow": "*"
},
"dependencies": {
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc