Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../.eslintrc.base.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-bolna
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-bolna` to build the library.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@activepieces/piece-bolna",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.d.ts",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-bolna",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/bolna/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
],
|
||||
"currentVersionResolver": "git-tag",
|
||||
"fallbackCurrentVersionResolver": "disk"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/bolna",
|
||||
"tsConfig": "packages/pieces/community/bolna/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/bolna/package.json",
|
||||
"main": "packages/pieces/community/bolna/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/bolna/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/bolna/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"prebuild",
|
||||
"^build"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"prebuild": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/bolna",
|
||||
"command": "bun install --no-save --silent"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"\nTo get your API Key:\n\n1. Login to the dashboard at https://platform.bolna.ai\n2. Navigate to Developers tab from the left menu bar after login\n3. Click the button Generate a new API Key to generate a key\n4. Get your API Key\n": "\nTo get your API Key:\n\n1. Login to the dashboard at https://platform.bolna.ai\n2. Navigate to Developers tab from the left menu bar after login\n3. Click the button Generate a new API Key to generate a key\n4. Get your API Key\n",
|
||||
"Make Phone Call": "Make Phone Call",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Initiate an outbound phone call from a Bolna Voice AI agent to a recipient.": "Initiate an outbound phone call from a Bolna Voice AI agent to a recipient.",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"Agent": "Agent",
|
||||
"Recipient Phone Number": "Recipient Phone Number",
|
||||
"From Phone Number": "From Phone Number",
|
||||
"Scheduled At": "Scheduled At",
|
||||
"User Data": "User Data",
|
||||
"Method": "Method",
|
||||
"Headers": "Headers",
|
||||
"Query Parameters": "Query Parameters",
|
||||
"Body": "Body",
|
||||
"Response is Binary ?": "Response is Binary ?",
|
||||
"No Error on Failure": "No Error on Failure",
|
||||
"Timeout (in seconds)": "Timeout (in seconds)",
|
||||
"Select the Bolna Voice AI agent": "Select the Bolna Voice AI agent",
|
||||
"Phone number of the recipient with country code (E.164 format, e.g., +10123456789)": "Phone number of the recipient with country code (E.164 format, e.g., +10123456789)",
|
||||
"Phone number of the sender with country code (E.164 format, e.g., +19876543007). Optional.": "Phone number of the sender with country code (E.164 format, e.g., +19876543007). Optional.",
|
||||
"The scheduled date and time in ISO 8601 format with time zone (e.g., 2025-08-21T10:35:00Z). Leave empty to call immediately.": "The scheduled date and time in ISO 8601 format with time zone (e.g., 2025-08-21T10:35:00Z). Leave empty to call immediately.",
|
||||
"Additional user dynamic variables as defined in the agent prompt (JSON object)": "Additional user dynamic variables as defined in the agent prompt (JSON object)",
|
||||
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
|
||||
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"Call Completion Report": "Call Completion Report",
|
||||
"Triggers when Bolna call report it is completed": "Triggers when Bolna call report it is completed",
|
||||
"Markdown": "Markdown",
|
||||
"## Bolna AI Webhook Setup\n To use this trigger, you need to manually set up a webhook in your Bolna AI account:\n \n 1. Login to your Bolna AI account.\n 2. Navigate to **Agent Setup** tab on the left navigation menu.\n 3. Go to **Analytics** .\n 4. Add to the **Push all execution data to webhook** and specify the following URL:\n ```text\n {{webhookUrl}}\n ```\n 5. Click Save Ag": "## Bolna AI Webhook Setup\n To use this trigger, you need to manually set up a webhook in your Bolna AI account:\n \n 1. Login to your Bolna AI account.\n 2. Navigate to **Agent Setup** tab on the left navigation menu.\n 3. Go to **Analytics** .\n 4. Add to the **Push all execution data to webhook** and specify the following URL:\n ```text\n {{webhookUrl}}\n ```\n 5. Click Save Agent.\n "
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { bolnaaiAuth } from './lib/common/auth';
|
||||
import { makePhoneCall } from './lib/actions/make-phone-call';
|
||||
import { callCompletionReport } from './lib/triggers/call-completion-report';
|
||||
import { createCustomApiCallAction } from '@activepieces/pieces-common';
|
||||
|
||||
export const bolna = createPiece({
|
||||
displayName: 'Bolna AI',
|
||||
auth: bolnaaiAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/bolna.png',
|
||||
authors: ['sanket-a11y'],
|
||||
actions: [
|
||||
makePhoneCall,
|
||||
createCustomApiCallAction({
|
||||
auth: bolnaaiAuth,
|
||||
baseUrl: () => 'https://api.bolna.ai',
|
||||
authMapping: async (auth) => ({
|
||||
Authorization: `Bearer ${auth.secret_text}`,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
triggers: [callCompletionReport],
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { bolnaaiAuth } from '../common/auth';
|
||||
import { makeRequest } from '../common/client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { agentId } from '../common/props';
|
||||
|
||||
export const makePhoneCall = createAction({
|
||||
auth: bolnaaiAuth,
|
||||
name: 'makePhoneCall',
|
||||
displayName: 'Make Phone Call',
|
||||
description:
|
||||
'Initiate an outbound phone call from a Bolna Voice AI agent to a recipient.',
|
||||
props: {
|
||||
agentId: agentId,
|
||||
recipientPhoneNumber: Property.ShortText({
|
||||
displayName: 'Recipient Phone Number',
|
||||
description:
|
||||
'Phone number of the recipient with country code (E.164 format, e.g., +10123456789)',
|
||||
required: true,
|
||||
}),
|
||||
fromPhoneNumber: Property.ShortText({
|
||||
displayName: 'From Phone Number',
|
||||
description:
|
||||
'Phone number of the sender with country code (E.164 format, e.g., +19876543007). Optional.',
|
||||
required: false,
|
||||
}),
|
||||
scheduledAt: Property.ShortText({
|
||||
displayName: 'Scheduled At',
|
||||
description:
|
||||
'The scheduled date and time in ISO 8601 format with time zone (e.g., 2025-08-21T10:35:00Z). Leave empty to call immediately.',
|
||||
required: false,
|
||||
}),
|
||||
userData: Property.Json({
|
||||
displayName: 'User Data',
|
||||
description:
|
||||
'Additional user dynamic variables as defined in the agent prompt (JSON object)',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth.secret_text;
|
||||
const payload: Record<string, unknown> = {
|
||||
agent_id: context.propsValue.agentId,
|
||||
recipient_phone_number: context.propsValue.recipientPhoneNumber,
|
||||
};
|
||||
|
||||
if (context.propsValue.fromPhoneNumber) {
|
||||
payload['from_phone_number'] = context.propsValue.fromPhoneNumber;
|
||||
}
|
||||
|
||||
if (context.propsValue.scheduledAt) {
|
||||
payload['scheduled_at'] = context.propsValue.scheduledAt;
|
||||
}
|
||||
|
||||
if (context.propsValue.userData) {
|
||||
payload['user_data'] = context.propsValue.userData;
|
||||
}
|
||||
|
||||
const response = await makeRequest(auth, HttpMethod.POST, '/call', payload);
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { makeRequest } from './client';
|
||||
|
||||
export const bolnaaiAuth = PieceAuth.SecretText({
|
||||
displayName: 'Bolna AI API Key',
|
||||
description: `
|
||||
To get your API Key:
|
||||
|
||||
1. Login to the dashboard at https://platform.bolna.ai
|
||||
2. Navigate to Developers tab from the left menu bar after login
|
||||
3. Click the button Generate a new API Key to generate a key
|
||||
4. Get your API Key
|
||||
`,
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
if (auth) {
|
||||
try {
|
||||
await makeRequest(auth, HttpMethod.GET, '/agent/all');
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid Api Key',
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid Api Key',
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
|
||||
export const BASE_URL = ` https://api.bolna.ai`;
|
||||
|
||||
export async function makeRequest(
|
||||
api_key: string,
|
||||
method: HttpMethod,
|
||||
path: string,
|
||||
body?: unknown
|
||||
) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${api_key}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
});
|
||||
return response.body;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Unexpected error: ${error.message || String(error)}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { makeRequest } from './client';
|
||||
import { bolnaaiAuth } from './auth';
|
||||
|
||||
export const agentId = Property.Dropdown({
|
||||
displayName: 'Agent',
|
||||
description: 'Select the Bolna Voice AI agent',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
auth: bolnaaiAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
auth.secret_text,
|
||||
HttpMethod.GET,
|
||||
'/agent/all'
|
||||
);
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.map((agent: any) => ({
|
||||
label: agent.agent_name,
|
||||
value: agent.id,
|
||||
})),
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
createTrigger,
|
||||
Property,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { bolnaaiAuth } from '../common/auth';
|
||||
export const callCompletionReport = createTrigger({
|
||||
auth: bolnaaiAuth,
|
||||
name: 'callCompletionReport',
|
||||
displayName: 'Call Completion Report',
|
||||
description: 'Triggers when Bolna call report it is completed',
|
||||
props: {
|
||||
markdown: Property.MarkDown({
|
||||
value: `## Bolna AI Webhook Setup
|
||||
To use this trigger, you need to manually set up a webhook in your Bolna AI account:
|
||||
|
||||
1. Login to your Bolna AI account.
|
||||
2. Navigate to **Agent Setup** tab on the left navigation menu.
|
||||
3. Go to **Analytics** .
|
||||
4. Add to the **Push all execution data to webhook** and specify the following URL:
|
||||
\`\`\`text
|
||||
{{webhookUrl}}
|
||||
\`\`\`
|
||||
5. Click Save Agent.
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
id: '7e8391e5-dd-4d3b-ddd-dfe255c71848',
|
||||
agent_id: '5a12b25a-dddd-4e77-90a5-9b4fd4577e44',
|
||||
batch_id: null,
|
||||
created_at: '2025-11-19T08:48:27.193399',
|
||||
updated_at: '2025-11-19T08:49:25.219095',
|
||||
scheduled_at: '2025-11-19T08:48:27.193376',
|
||||
answered_by_voice_mail: null,
|
||||
conversation_duration: 24.2,
|
||||
total_cost: 3.54,
|
||||
transcript:
|
||||
'assistant: Hello from Bolna\nuser: hello\nassistant: Hello! Am I speaking with you? Is this a good time to talk? How can I assist you today?\n',
|
||||
usage_breakdown: {
|
||||
llmModel: { 'azure/gpt-4.1-mini': { input: 1397, output: 23 } },
|
||||
llmTokens: 0,
|
||||
synthesizer_model: 'eleven_turbo_v2_5',
|
||||
transcriber_model: 'nova-3',
|
||||
llm_usage_breakdown: {
|
||||
hangup: null,
|
||||
analytics: null,
|
||||
extraction: null,
|
||||
conversation: {
|
||||
input: 1397,
|
||||
model: 'azure/gpt-4.1-mini',
|
||||
output: 23,
|
||||
provider: 'azure',
|
||||
provider_connected: false,
|
||||
},
|
||||
summarization: null,
|
||||
},
|
||||
synthesizer_provider: 'elevenlabs',
|
||||
transcriber_duration: 0,
|
||||
transcriber_provider: 'deepgram',
|
||||
synthesizer_characters: 111,
|
||||
synthesizer_usage_breakdown: {
|
||||
provider_connected: false,
|
||||
welcome_message_cache: true,
|
||||
conversation_characters: 111,
|
||||
welcome_message_characters: 0,
|
||||
},
|
||||
transcriber_usage_breakdown: {
|
||||
provider_connected: false,
|
||||
transcriber_duration: 0,
|
||||
},
|
||||
},
|
||||
cost_breakdown: {
|
||||
llm: 0.06,
|
||||
network: 0.375,
|
||||
platform: 2.0,
|
||||
synthesizer: 1.11,
|
||||
transcriber: 0.0,
|
||||
llm_breakdown: {
|
||||
hangup: 0,
|
||||
analytics: 0,
|
||||
extraction: 0,
|
||||
conversation: 0.06,
|
||||
summarization: 0,
|
||||
},
|
||||
transfer_cost: 0.0,
|
||||
synthesizer_breakdown: { conversation: 1.11, welcome_message: 0 },
|
||||
transcriber_breakdown: { analytics: 0, conversation: 0.0 },
|
||||
},
|
||||
extracted_data: null,
|
||||
summary: null,
|
||||
error_message: null,
|
||||
status: 'completed',
|
||||
agent_extraction: null,
|
||||
workflow_retries: null,
|
||||
rescheduled_at: null,
|
||||
custom_extractions: null,
|
||||
campaign_id: null,
|
||||
smart_status: null,
|
||||
user_number: '+9199999999',
|
||||
agent_number: '+916565656565',
|
||||
telephony_data: {
|
||||
duration: '24',
|
||||
to_number: '+9199999999',
|
||||
from_number: '+916565656565',
|
||||
recording_url:
|
||||
'https://bolna-recordings-india.s3.ap-south-1.amazonaws.com/plivo/e3v16015b-vvvv12ef-42fd-898c-52cevvv62058v8cd.mp3',
|
||||
hosted_telephony: true,
|
||||
provider_call_id: 'e316c015b-12ef-4c2fd-c898c-52ce620ccc588cd',
|
||||
call_type: 'outbound',
|
||||
provider: 'plivo',
|
||||
hangup_by: 'Callee',
|
||||
hangup_reason: 'Call recipient hungup',
|
||||
hangup_provider_code: 4000,
|
||||
},
|
||||
transfer_call_data: null,
|
||||
context_details: {
|
||||
recipient_data: null,
|
||||
recipient_phone_number: '+9199999990',
|
||||
},
|
||||
batch_run_details: null,
|
||||
provider: 'plivo',
|
||||
},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable(context) {
|
||||
// implement webhook creation logic
|
||||
},
|
||||
async onDisable(context) {
|
||||
// implement webhook deletion logic
|
||||
},
|
||||
async run(context) {
|
||||
const payload = context.payload.body as any;
|
||||
|
||||
if (payload.status != 'completed') {
|
||||
return [];
|
||||
}
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user