Skip to content

Commit 062be03

Browse files
feat(pieces): add Kapso WhatsApp integration (activepieces#11195)
1 parent 9e5943e commit 062be03

28 files changed

+1617
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"extends": [
3+
"../../../../.eslintrc.base.json"
4+
],
5+
"ignorePatterns": [
6+
"!**/*"
7+
],
8+
"overrides": [
9+
{
10+
"files": [
11+
"*.ts",
12+
"*.tsx",
13+
"*.js",
14+
"*.jsx"
15+
],
16+
"rules": {}
17+
},
18+
{
19+
"files": [
20+
"*.ts",
21+
"*.tsx"
22+
],
23+
"rules": {}
24+
},
25+
{
26+
"files": [
27+
"*.js",
28+
"*.jsx"
29+
],
30+
"rules": {}
31+
}
32+
]
33+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# pieces-kapso
2+
3+
This library was generated with [Nx](https://nx.dev).
4+
5+
## Building
6+
7+
Run `nx build pieces-kapso` to build the library.

packages/pieces/community/kapso/bun.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "@activepieces/piece-kapso",
3+
"version": "0.0.1",
4+
"type": "commonjs",
5+
"main": "./src/index.js",
6+
"types": "./src/index.d.ts",
7+
"dependencies": {
8+
"@kapso/whatsapp-cloud-api": "^0.1.1",
9+
"tslib": "^2.3.0"
10+
}
11+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"name": "pieces-kapso",
3+
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "packages/pieces/community/kapso/src",
5+
"projectType": "library",
6+
"release": {
7+
"version": {
8+
"manifestRootsToUpdate": [
9+
"dist/{projectRoot}"
10+
],
11+
"currentVersionResolver": "git-tag",
12+
"fallbackCurrentVersionResolver": "disk"
13+
}
14+
},
15+
"tags": [],
16+
"targets": {
17+
"build": {
18+
"executor": "@nx/js:tsc",
19+
"outputs": [
20+
"{options.outputPath}"
21+
],
22+
"options": {
23+
"outputPath": "dist/packages/pieces/community/kapso",
24+
"tsConfig": "packages/pieces/community/kapso/tsconfig.lib.json",
25+
"packageJson": "packages/pieces/community/kapso/package.json",
26+
"main": "packages/pieces/community/kapso/src/index.ts",
27+
"assets": [
28+
"packages/pieces/community/kapso/*.md",
29+
{
30+
"input": "packages/pieces/community/kapso/src/i18n",
31+
"output": "./src/i18n",
32+
"glob": "**/!(i18n.json)"
33+
}
34+
],
35+
"buildableProjectDepsInPackageJsonType": "dependencies",
36+
"updateBuildableProjectDepsInPackageJson": true,
37+
"clean": false
38+
},
39+
"dependsOn": [
40+
"prebuild",
41+
"^build"
42+
]
43+
},
44+
"nx-release-publish": {
45+
"options": {
46+
"packageRoot": "dist/{projectRoot}"
47+
}
48+
},
49+
"prebuild": {
50+
"dependsOn": [
51+
"^build"
52+
],
53+
"executor": "nx:run-commands",
54+
"options": {
55+
"cwd": "packages/pieces/community/kapso",
56+
"command": "bun install --no-save --silent"
57+
}
58+
},
59+
"lint": {
60+
"executor": "@nx/eslint:lint",
61+
"outputs": [
62+
"{options.outputFile}"
63+
]
64+
}
65+
}
66+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { createPiece } from '@activepieces/pieces-framework';
2+
import { PieceCategory } from '@activepieces/shared';
3+
import { createCustomApiCallAction } from '@activepieces/pieces-common';
4+
import { kapsoAuth, KAPSO_BASE_URL } from './lib/common';
5+
import { sendTextMessage } from './lib/actions/send-text-message';
6+
import { sendButtons } from './lib/actions/send-buttons';
7+
import { sendList } from './lib/actions/send-list';
8+
import { sendImage } from './lib/actions/send-image';
9+
import { sendVideo } from './lib/actions/send-video';
10+
import { sendAudio } from './lib/actions/send-audio';
11+
import { sendDocument } from './lib/actions/send-document';
12+
import { sendSticker } from './lib/actions/send-sticker';
13+
import { sendLocation } from './lib/actions/send-location';
14+
import { requestLocation } from './lib/actions/request-location';
15+
import { sendContact } from './lib/actions/send-contact';
16+
import { sendReaction } from './lib/actions/send-reaction';
17+
import { markAsRead } from './lib/actions/mark-as-read';
18+
import { sendTemplate } from './lib/actions/send-template';
19+
import { newMessage } from './lib/triggers/new-message';
20+
import { messageStatusUpdate } from './lib/triggers/message-status-update';
21+
22+
export const kapso = createPiece({
23+
displayName: 'Kapso',
24+
description: 'Send and receive WhatsApp messages, media, templates, and more using the Kapso WhatsApp API.',
25+
auth: kapsoAuth,
26+
minimumSupportedRelease: '0.36.1',
27+
logoUrl: 'https://cdn.activepieces.com/pieces/kapso.png',
28+
categories: [PieceCategory.COMMUNICATION],
29+
authors: ['onyedikachi-david'],
30+
actions: [
31+
sendTextMessage,
32+
sendButtons,
33+
sendList,
34+
sendImage,
35+
sendVideo,
36+
sendAudio,
37+
sendDocument,
38+
sendSticker,
39+
sendLocation,
40+
requestLocation,
41+
sendContact,
42+
sendReaction,
43+
markAsRead,
44+
sendTemplate,
45+
createCustomApiCallAction({
46+
auth: kapsoAuth,
47+
baseUrl: () => KAPSO_BASE_URL,
48+
authMapping: async (auth) => {
49+
return {
50+
'X-API-Key': auth.secret_text,
51+
};
52+
},
53+
}),
54+
],
55+
triggers: [newMessage, messageStatusUpdate],
56+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { createAction, Property } from '@activepieces/pieces-framework';
2+
import { kapsoAuth } from '../common';
3+
import { makeClient } from '../common';
4+
import { phoneNumberIdDropdown } from '../common/props';
5+
6+
export const markAsRead = createAction({
7+
auth: kapsoAuth,
8+
name: 'mark_as_read',
9+
displayName: 'Mark Message as Read',
10+
description: 'Mark a WhatsApp message as read.',
11+
props: {
12+
phoneNumberId: phoneNumberIdDropdown,
13+
messageId: Property.ShortText({
14+
displayName: 'Message ID',
15+
description: 'The ID of the message to mark as read.',
16+
required: true,
17+
}),
18+
},
19+
async run(context) {
20+
const { phoneNumberId, messageId } = context.propsValue;
21+
const client = makeClient(context.auth.secret_text);
22+
23+
const response = await client.messages.markRead({
24+
phoneNumberId,
25+
messageId,
26+
});
27+
28+
return response;
29+
},
30+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { createAction, Property } from '@activepieces/pieces-framework';
2+
import { kapsoAuth } from '../common';
3+
import { makeClient } from '../common';
4+
import { phoneNumberIdDropdown } from '../common/props';
5+
6+
export const requestLocation = createAction({
7+
auth: kapsoAuth,
8+
name: 'request_user_location',
9+
displayName: 'Request User Location',
10+
description: 'Send a location request message to a WhatsApp user.',
11+
props: {
12+
phoneNumberId: phoneNumberIdDropdown,
13+
to: Property.ShortText({
14+
displayName: 'Recipient Phone Number',
15+
description:
16+
'The recipient\'s phone number in international format (e.g. 15551234567).',
17+
required: true,
18+
}),
19+
bodyText: Property.LongText({
20+
displayName: 'Body Text',
21+
description: 'The message body displayed with the location request.',
22+
required: true,
23+
}),
24+
},
25+
async run(context) {
26+
const { phoneNumberId, to, bodyText } = context.propsValue;
27+
const client = makeClient(context.auth.secret_text);
28+
29+
const response = await client.messages.sendInteractiveLocationRequest({
30+
phoneNumberId,
31+
to,
32+
bodyText,
33+
parameters: {
34+
requestMessage: bodyText,
35+
},
36+
});
37+
38+
return response;
39+
},
40+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createAction, Property } from '@activepieces/pieces-framework';
2+
import { kapsoAuth } from '../common';
3+
import { makeClient } from '../common';
4+
import { phoneNumberIdDropdown } from '../common/props';
5+
6+
export const sendAudio = createAction({
7+
auth: kapsoAuth,
8+
name: 'send_audio',
9+
displayName: 'Send Audio',
10+
description: 'Send an audio message via WhatsApp.',
11+
props: {
12+
phoneNumberId: phoneNumberIdDropdown,
13+
to: Property.ShortText({
14+
displayName: 'Recipient Phone Number',
15+
description:
16+
'The recipient\'s phone number in international format (e.g. 15551234567).',
17+
required: true,
18+
}),
19+
audioUrl: Property.ShortText({
20+
displayName: 'Audio URL',
21+
description: 'Public URL of the audio file to send.',
22+
required: false,
23+
}),
24+
audioId: Property.ShortText({
25+
displayName: 'Audio Media ID',
26+
description: 'Media ID of a previously uploaded audio. Use either URL or Media ID.',
27+
required: false,
28+
}),
29+
},
30+
async run(context) {
31+
const { phoneNumberId, to, audioUrl, audioId } = context.propsValue;
32+
const client = makeClient(context.auth.secret_text);
33+
34+
const response = await client.messages.sendAudio({
35+
phoneNumberId,
36+
to,
37+
audio: {
38+
link: audioUrl ?? undefined,
39+
id: audioId ?? undefined,
40+
},
41+
});
42+
43+
return response;
44+
},
45+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { createAction, Property } from '@activepieces/pieces-framework';
2+
import { kapsoAuth } from '../common';
3+
import { makeClient } from '../common';
4+
import { phoneNumberIdDropdown } from '../common/props';
5+
6+
export const sendButtons = createAction({
7+
auth: kapsoAuth,
8+
name: 'send_buttons',
9+
displayName: 'Send Button Message',
10+
description: 'Send an interactive button message via WhatsApp (up to 3 buttons).',
11+
props: {
12+
phoneNumberId: phoneNumberIdDropdown,
13+
to: Property.ShortText({
14+
displayName: 'Recipient Phone Number',
15+
description:
16+
'The recipient\'s phone number in international format (e.g. 15551234567).',
17+
required: true,
18+
}),
19+
bodyText: Property.LongText({
20+
displayName: 'Body Text',
21+
description: 'The message body displayed above the buttons.',
22+
required: true,
23+
}),
24+
buttons: Property.Array({
25+
displayName: 'Buttons',
26+
description:
27+
'Up to 3 buttons. Each button needs an ID and a title (max 20 characters).',
28+
required: true,
29+
properties: {
30+
id: Property.ShortText({
31+
displayName: 'Button ID',
32+
description: 'A unique identifier for this button (returned when the user taps it).',
33+
required: true,
34+
}),
35+
title: Property.ShortText({
36+
displayName: 'Button Title',
37+
description: 'The text displayed on the button (max 20 characters).',
38+
required: true,
39+
}),
40+
},
41+
}),
42+
footerText: Property.ShortText({
43+
displayName: 'Footer Text',
44+
description: 'Optional footer text displayed below the buttons.',
45+
required: false,
46+
}),
47+
},
48+
async run(context) {
49+
const { phoneNumberId, to, bodyText, buttons, footerText } =
50+
context.propsValue;
51+
const client = makeClient(context.auth.secret_text);
52+
53+
const response = await client.messages.sendInteractiveButtons({
54+
phoneNumberId,
55+
to,
56+
bodyText,
57+
buttons: (buttons as { id: string; title: string }[]).map((b) => ({
58+
id: b.id,
59+
title: b.title,
60+
})),
61+
footerText: footerText ?? undefined,
62+
});
63+
64+
return response;
65+
},
66+
});

0 commit comments

Comments
 (0)