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,231 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { avomaCommon } from '../common';
|
||||
|
||||
export const createCall = createAction({
|
||||
auth: avomaCommon.avomaAuth,
|
||||
name: 'create_call',
|
||||
displayName: 'Create Call',
|
||||
description: 'Creates a new call in Avoma',
|
||||
props: {
|
||||
external_id: Property.ShortText({
|
||||
displayName: 'External ID',
|
||||
description: 'Unique id of the call from the dialer system like hubspot, twilio, zoom, etc.',
|
||||
required: true
|
||||
}),
|
||||
user_email: Property.ShortText({
|
||||
displayName: 'User Email',
|
||||
description: 'Email of the user who made or received the call. This should be an Avoma user\'s email.',
|
||||
required: true
|
||||
}),
|
||||
source: Property.StaticDropdown({
|
||||
displayName: 'Source',
|
||||
description: 'Source of the call',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Zoom', value: 'zoom' },
|
||||
{ label: 'Zoom Phone', value: 'zoomphone' },
|
||||
{ label: 'Twilio', value: 'twilio' },
|
||||
{ label: 'PhoneBurner', value: 'phoneburner' },
|
||||
{ label: 'RingCentral', value: 'ringcentral' },
|
||||
{ label: 'Aircall', value: 'aircall' },
|
||||
{ label: 'HubSpot', value: 'hubspot' },
|
||||
{ label: 'Other', value: 'other' }
|
||||
]
|
||||
}
|
||||
}),
|
||||
direction: Property.StaticDropdown({
|
||||
displayName: 'Direction',
|
||||
description: 'Direction of the call',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Inbound', value: 'Inbound' },
|
||||
{ label: 'Outbound', value: 'Outbound' }
|
||||
]
|
||||
}
|
||||
}),
|
||||
start_at: Property.DateTime({
|
||||
displayName: 'Start Time',
|
||||
description: 'Start time of the call',
|
||||
required: true
|
||||
}),
|
||||
frm: Property.ShortText({
|
||||
displayName: 'From Phone Number',
|
||||
description: 'Phone number from which call was made (e.g., +11234567890)',
|
||||
required: true
|
||||
}),
|
||||
to: Property.ShortText({
|
||||
displayName: 'To Phone Number',
|
||||
description: 'Phone number to which call was made (e.g., +12234567890)',
|
||||
required: true
|
||||
}),
|
||||
recording_url: Property.LongText({
|
||||
displayName: 'Recording URL',
|
||||
description: 'URL of the recording of the call. This should be a public URL that Avoma can access.',
|
||||
required: true
|
||||
}),
|
||||
participants: Property.Array({
|
||||
displayName: 'Participants',
|
||||
description: 'List of participants in the call. First entry should be the prospect/lead.',
|
||||
required: true,
|
||||
properties: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
description: 'Name of the participant',
|
||||
required: true
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: 'Email of the participant',
|
||||
required: true
|
||||
}),
|
||||
crm_id: Property.ShortText({
|
||||
displayName: 'CRM Record ID',
|
||||
description: 'CRM record ID for this participant (optional)',
|
||||
required: false
|
||||
}),
|
||||
crm_type: Property.ShortText({
|
||||
displayName: 'CRM Record Type',
|
||||
description: 'Type of CRM record (e.g., contact, lead, opportunity)',
|
||||
required: false
|
||||
}),
|
||||
crm_system: Property.ShortText({
|
||||
displayName: 'CRM System',
|
||||
description: 'CRM system name (e.g., hubspot, salesforce)',
|
||||
required: false
|
||||
})
|
||||
}
|
||||
}),
|
||||
end_at: Property.DateTime({
|
||||
displayName: 'End Time',
|
||||
description: 'End time of the call',
|
||||
required: false
|
||||
}),
|
||||
frm_name: Property.ShortText({
|
||||
displayName: 'From Name',
|
||||
description: 'Name of the caller who made the call',
|
||||
required: false
|
||||
}),
|
||||
to_name: Property.ShortText({
|
||||
displayName: 'To Name',
|
||||
description: 'Name of the person to whom call was made',
|
||||
required: false
|
||||
}),
|
||||
answered: Property.Checkbox({
|
||||
displayName: 'Answered',
|
||||
description: 'Whether the call was answered',
|
||||
required: false
|
||||
}),
|
||||
is_voicemail: Property.Checkbox({
|
||||
displayName: 'Is Voicemail',
|
||||
description: 'Indicates if the call is a voicemail',
|
||||
required: false,
|
||||
defaultValue: false
|
||||
}),
|
||||
additional_details: Property.LongText({
|
||||
displayName: 'Additional Details',
|
||||
description: 'Additional details of the call (JSON object as string)',
|
||||
required: false
|
||||
})
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
|
||||
const participants = propsValue.participants?.map((participant: any) => {
|
||||
const participantData: any = {
|
||||
email: participant.email,
|
||||
name: participant.name
|
||||
};
|
||||
|
||||
if (participant.crm_id && participant.crm_type && participant.crm_system) {
|
||||
participantData.associations = [{
|
||||
id: participant.crm_id,
|
||||
type: participant.crm_type,
|
||||
system: participant.crm_system
|
||||
}];
|
||||
}
|
||||
|
||||
return participantData;
|
||||
}) || [];
|
||||
|
||||
const requestBody: any = {
|
||||
external_id: propsValue.external_id,
|
||||
user_email: propsValue.user_email,
|
||||
source: propsValue.source,
|
||||
direction: propsValue.direction,
|
||||
start_at: propsValue.start_at,
|
||||
frm: propsValue.frm,
|
||||
to: propsValue.to,
|
||||
recording_url: propsValue.recording_url,
|
||||
participants: participants
|
||||
};
|
||||
|
||||
if (propsValue.end_at) {
|
||||
requestBody.end_at = propsValue.end_at;
|
||||
}
|
||||
if (propsValue.frm_name) {
|
||||
requestBody.frm_name = propsValue.frm_name;
|
||||
}
|
||||
if (propsValue.to_name) {
|
||||
requestBody.to_name = propsValue.to_name;
|
||||
}
|
||||
if (propsValue.answered !== undefined) {
|
||||
requestBody.answered = propsValue.answered;
|
||||
}
|
||||
if (propsValue.is_voicemail !== undefined) {
|
||||
requestBody.is_voicemail = propsValue.is_voicemail;
|
||||
}
|
||||
if (propsValue.additional_details) {
|
||||
try {
|
||||
requestBody.additional_details = JSON.parse(propsValue.additional_details);
|
||||
} catch (e) {
|
||||
requestBody.additional_details = propsValue.additional_details;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: 'https://api.avoma.com/v1/calls/',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: requestBody
|
||||
});
|
||||
|
||||
if (response.status === 400) {
|
||||
const errorDetails = response.body;
|
||||
let errorMessage = 'Bad request: ';
|
||||
|
||||
if (typeof errorDetails === 'object') {
|
||||
const fieldErrors = Object.entries(errorDetails)
|
||||
.map(([field, errors]) => `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}`)
|
||||
.join('; ');
|
||||
errorMessage += fieldErrors;
|
||||
} else {
|
||||
errorMessage += JSON.stringify(errorDetails) || 'Invalid input data';
|
||||
}
|
||||
|
||||
if (errorMessage.includes('external_id') && errorMessage.includes('source')) {
|
||||
errorMessage += '. This may be due to a duplicate call (same external_id and source already exists)';
|
||||
} else if (errorMessage.includes('user_email')) {
|
||||
errorMessage += '. Check that the user exists, is active, belongs to your organization, and has dialer permissions';
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (response.status >= 400) {
|
||||
throw new Error(`API error (${response.status}): ${JSON.stringify(response.body) || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to create call: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { avomaCommon } from '../common';
|
||||
|
||||
export const getMeetingRecording = createAction({
|
||||
auth: avomaCommon.avomaAuth,
|
||||
name: 'get_meeting_recording',
|
||||
displayName: 'Get Meeting Recording',
|
||||
description: 'Returns video and audio recording URLs for a given meeting',
|
||||
props: {
|
||||
meeting_uuid: avomaCommon.meetingDropdown
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
|
||||
const meetingUuid = propsValue.meeting_uuid;
|
||||
|
||||
if (!meetingUuid) {
|
||||
throw new Error('Please select a meeting from the dropdown');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `https://api.avoma.com/v1/recordings/?meeting_uuid=${meetingUuid}`,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
success: true,
|
||||
status: 'available',
|
||||
meeting_uuid: response.body.meeting_uuid,
|
||||
recording_uuid: response.body.uuid,
|
||||
audio_url: response.body.audio_url,
|
||||
video_url: response.body.video_url,
|
||||
valid_till: response.body.valid_till,
|
||||
urls_expire_in_days: 5
|
||||
};
|
||||
} else if (response.status === 202) {
|
||||
return {
|
||||
success: true,
|
||||
status: 'processing',
|
||||
meeting_uuid: response.body.meeting_uuid,
|
||||
recording_uuid: response.body.uuid,
|
||||
message: response.body.message || 'Recording is being processed and not yet available',
|
||||
note: 'Check audio_ready and video_ready parameters in the meeting details to verify recording status'
|
||||
};
|
||||
} else if (response.status === 403) {
|
||||
throw new Error(`Permission denied: ${response.body.detail || 'You do not have permission to access this recording'}`);
|
||||
} else if (response.status === 404) {
|
||||
throw new Error(`Recording not found: ${response.body.detail || 'No recording exists for this meeting'}`);
|
||||
} else if (response.status === 429) {
|
||||
throw new Error(`Rate limit exceeded: ${response.body.detail || 'Too many requests. Please try again later'}`);
|
||||
} else if (response.status >= 400) {
|
||||
throw new Error(`API error (${response.status}): ${JSON.stringify(response.body) || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: 'unknown',
|
||||
meeting_uuid: meetingUuid,
|
||||
error: 'Unexpected response from API'
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to retrieve meeting recording for UUID ${meetingUuid}: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { avomaCommon } from '../common';
|
||||
|
||||
export const getMeetingTranscription = createAction({
|
||||
auth: avomaCommon.avomaAuth,
|
||||
name: 'get_meeting_transcription',
|
||||
displayName: 'Get Meeting Transcription',
|
||||
description: 'Returns transcription with speakers, timestamps, and VTT file URL',
|
||||
props: {
|
||||
transcription_uuid: avomaCommon.transcriptionDropdown
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
|
||||
const transcriptionUuid = propsValue.transcription_uuid;
|
||||
|
||||
if (!transcriptionUuid) {
|
||||
throw new Error('Please select a transcription from the dropdown');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `https://api.avoma.com/v1/transcriptions/${transcriptionUuid}`,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${auth}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
const errorDetail = response.body?.detail || 'Transcription not found';
|
||||
throw new Error(`Transcription not found: ${errorDetail}`);
|
||||
} else if (response.status >= 400) {
|
||||
const errorDetail = response.body?.detail || JSON.stringify(response.body) || 'Unknown error';
|
||||
throw new Error(`API error (${response.status}): ${errorDetail}`);
|
||||
}
|
||||
|
||||
const transcription = response.body;
|
||||
return {
|
||||
success: true,
|
||||
meeting_uuid: transcription.meeting_uuid,
|
||||
transcription_uuid: transcription.uuid,
|
||||
transcription_vtt_url: transcription.transcription_vtt_url,
|
||||
speakers: transcription.speakers || [],
|
||||
transcript: transcription.transcript || [],
|
||||
transcript_paragraphs_count: transcription.transcript?.length || 0,
|
||||
speakers_count: transcription.speakers?.length || 0,
|
||||
note: 'Use transcription_vtt_url to download the VTT subtitle file for the meeting'
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to retrieve transcription: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export { createCall } from './create-call';
|
||||
export { getMeetingRecording } from './get-meeting-recording';
|
||||
export { getMeetingTranscription } from './get-meeting-transcription';
|
||||
@@ -0,0 +1,155 @@
|
||||
import { PieceAuth, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
const avomaAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description:
|
||||
'Your Avoma API Key (Bearer token). Generate it from your Avoma API Integration settings: https://help.avoma.com/api-integration-for-avoma',
|
||||
required: true
|
||||
});
|
||||
export const avomaCommon = {
|
||||
avomaAuth: avomaAuth,
|
||||
meetingDropdown: Property.Dropdown({
|
||||
auth: avomaAuth,
|
||||
displayName: 'Meeting',
|
||||
description: 'Select a meeting from your Avoma account',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your Avoma account first',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const toDate = new Date().toISOString();
|
||||
const fromDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `https://api.avoma.com/v1/meetings/?page_size=100&from_date=${encodeURIComponent(fromDate)}&to_date=${encodeURIComponent(toDate)}`,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const meetings = response.body?.results || response.body?.data || response.body || [];
|
||||
|
||||
if (!Array.isArray(meetings)) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'No meetings found or unexpected response format',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: meetings.map((meeting: any) => {
|
||||
const subject = meeting.subject || meeting.title || 'Untitled Meeting';
|
||||
const startTime = meeting.start_time || meeting.startTime || meeting.created_at;
|
||||
const dateStr = startTime ? new Date(startTime).toLocaleDateString() : 'Unknown date';
|
||||
const uuid = meeting.uuid || meeting.id;
|
||||
|
||||
return {
|
||||
label: `${subject} - ${dateStr}`,
|
||||
value: uuid
|
||||
};
|
||||
})
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching meetings:', error);
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load meetings. Please check your API key.',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
transcriptionDropdown: Property.Dropdown({
|
||||
auth: avomaAuth,
|
||||
displayName: 'Transcription',
|
||||
description: 'Select a transcription from your Avoma meetings',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your Avoma account first',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const toDate = new Date().toISOString();
|
||||
const fromDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `https://api.avoma.com/v1/transcriptions/?page_size=100&from_date=${encodeURIComponent(fromDate)}&to_date=${encodeURIComponent(toDate)}`,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
let transcriptions = [];
|
||||
if (response.body?.results) {
|
||||
transcriptions = response.body.results;
|
||||
} else if (Array.isArray(response.body)) {
|
||||
transcriptions = response.body;
|
||||
} else if (response.body && typeof response.body === 'object') {
|
||||
transcriptions = [response.body];
|
||||
}
|
||||
|
||||
if (!Array.isArray(transcriptions)) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Unexpected response format from API',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: transcriptions.map((transcription: any) => {
|
||||
const transcriptionUuid = transcription.uuid;
|
||||
const speakersCount = transcription.speakers?.length || 0;
|
||||
const transcriptLength = transcription.transcript?.length || 0;
|
||||
|
||||
return {
|
||||
label: `Transcription ${transcriptionUuid.substring(0, 8)}... - ${speakersCount} speakers, ${transcriptLength} paragraphs`,
|
||||
value: transcriptionUuid
|
||||
};
|
||||
})
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching transcriptions:', error);
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load transcriptions. Please check your API key.',
|
||||
options: []
|
||||
};
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
meetingUuidProperty: Property.ShortText({
|
||||
displayName: 'Meeting UUID',
|
||||
description: 'Enter the meeting UUID directly, or use the dropdown below to select from your meetings',
|
||||
required: false
|
||||
}),
|
||||
|
||||
transcriptionUuidProperty: Property.ShortText({
|
||||
displayName: 'Transcription UUID',
|
||||
description: 'Enter the transcription UUID directly, or use the dropdown below to select from available transcriptions',
|
||||
required: false
|
||||
})
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export { newNote } from './new-note';
|
||||
export { newMeetingScheduled } from './new-meeting-scheduled';
|
||||
export { meetingRescheduled } from './meeting-rescheduled';
|
||||
export { meetingCancelled } from './meeting-cancelled';
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const meetingCancelled = createTrigger({
|
||||
name: 'meeting_cancelled',
|
||||
displayName: 'Meeting Cancelled',
|
||||
description: 'Triggers when a meeting booked via the scheduling page is cancelled',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {
|
||||
setupInstructions: Property.MarkDown({
|
||||
value: `
|
||||
**Quick Setup:**
|
||||
|
||||
1. In Avoma: **Settings > Integrations > Webhooks**
|
||||
2. **Webhook URL:** \`{{webhookUrl}}\`
|
||||
3. **Event Type:** Select **"MEETING_BOOKED_VIA_SCHEDULER_CANCELED"**
|
||||
4. **HTTP Method:** POST
|
||||
5. **Content Type:** application/json
|
||||
|
||||
**Note:** Requires admin permissions in Avoma.
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
booker_email: 'client@example.com',
|
||||
cancel_reason: 'Schedule conflict - need to reschedule for next week',
|
||||
conference_link: 'https://zoom.us/j/123456789',
|
||||
created: '2019-08-24T14:15:22Z',
|
||||
event_end_time: '2019-08-24T15:15:22Z',
|
||||
event_start_time: '2019-08-24T14:15:22Z',
|
||||
event_type: 'MEETING_BOOKED_VIA_SCHEDULER_CANCELED',
|
||||
invitee_details: {
|
||||
email: 'client@example.com',
|
||||
locale: 'en-US',
|
||||
name: 'John Client',
|
||||
tz: 'America/New_York'
|
||||
},
|
||||
invitee_responses: [
|
||||
{
|
||||
question: 'What would you like to discuss?',
|
||||
response: 'Product demo and pricing discussion'
|
||||
},
|
||||
{
|
||||
question: 'Company size?',
|
||||
response: '50-100 employees'
|
||||
}
|
||||
],
|
||||
meeting_uuid: '65fb768c-30b9-4a9a-999f-5dab85e66635',
|
||||
modified: '2019-08-24T16:30:22Z',
|
||||
organizer_email: 'sales@company.com',
|
||||
organizer_timezone: 'America/New_York',
|
||||
purpose: 'Sales Demo',
|
||||
scheduling_page_link: 'https://meet.avoma.com/sales-demo',
|
||||
subject: 'Product Demo - John Client (Cancelled)',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
|
||||
},
|
||||
async onEnable(context) {
|
||||
// Manual setup - no programmatic registration needed
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
// Manual setup - users manage webhooks in Avoma UI
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const meetingRescheduled = createTrigger({
|
||||
name: 'meeting_rescheduled',
|
||||
displayName: 'Meeting Rescheduled',
|
||||
description: 'Triggers when a scheduled meeting is rescheduled',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {
|
||||
setupInstructions: Property.MarkDown({
|
||||
value: `
|
||||
**Quick Setup:**
|
||||
|
||||
1. In Avoma: **Settings > Integrations > Webhooks**
|
||||
2. **Webhook URL:** \`{{webhookUrl}}\`
|
||||
3. **Event Type:** Select **"MEETING_BOOKED_VIA_SCHEDULER_RESCHEDULED"**
|
||||
4. **HTTP Method:** POST
|
||||
5. **Content Type:** application/json
|
||||
|
||||
**Note:** Requires admin permissions in Avoma.
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
booker_email: 'client@example.com',
|
||||
cancel_reason: null,
|
||||
conference_link: 'https://zoom.us/j/123456789',
|
||||
created: '2019-08-24T14:15:22Z',
|
||||
event_end_time: '2019-08-25T15:15:22Z',
|
||||
event_start_time: '2019-08-25T14:15:22Z',
|
||||
event_type: 'MEETING_BOOKED_VIA_SCHEDULER_RESCHEDULED',
|
||||
invitee_details: {
|
||||
email: 'client@example.com',
|
||||
locale: 'en-US',
|
||||
name: 'John Client',
|
||||
tz: 'America/New_York'
|
||||
},
|
||||
invitee_responses: [
|
||||
{
|
||||
question: 'What would you like to discuss?',
|
||||
response: 'Product demo and pricing discussion'
|
||||
},
|
||||
{
|
||||
question: 'Company size?',
|
||||
response: '50-100 employees'
|
||||
}
|
||||
],
|
||||
meeting_uuid: '65fb768c-30b9-4a9a-999f-5dab85e66635',
|
||||
modified: '2019-08-24T16:30:22Z',
|
||||
organizer_email: 'sales@company.com',
|
||||
organizer_timezone: 'America/New_York',
|
||||
purpose: 'Sales Demo',
|
||||
scheduling_page_link: 'https://meet.avoma.com/sales-demo',
|
||||
subject: 'Product Demo - John Client (Rescheduled)',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
|
||||
},
|
||||
async onEnable(context) {
|
||||
// Manual setup - no programmatic registration needed
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
// Manual setup - users manage webhooks in Avoma UI
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const newMeetingScheduled = createTrigger({
|
||||
name: 'new_meeting_scheduled',
|
||||
displayName: 'New Meeting Scheduled',
|
||||
description: 'Triggers when a meeting is booked via one of your Avoma scheduling pages',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {
|
||||
setupInstructions: Property.MarkDown({
|
||||
value: `
|
||||
**Quick Setup:**
|
||||
|
||||
1. In Avoma: **Settings > Integrations > Webhooks**
|
||||
2. **Webhook URL:** \`{{webhookUrl}}\`
|
||||
3. **Event Type:** Select **"MEETING_BOOKED_VIA_SCHEDULER"**
|
||||
4. **HTTP Method:** POST
|
||||
5. **Content Type:** application/json
|
||||
|
||||
**Note:** Requires admin permissions in Avoma.
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
booker_email: 'client@example.com',
|
||||
cancel_reason: null,
|
||||
conference_link: 'https://zoom.us/j/123456789',
|
||||
created: '2019-08-24T14:15:22Z',
|
||||
event_end_time: '2019-08-24T15:15:22Z',
|
||||
event_start_time: '2019-08-24T14:15:22Z',
|
||||
event_type: 'MEETING_BOOKED_VIA_SCHEDULER',
|
||||
invitee_details: {
|
||||
email: 'client@example.com',
|
||||
locale: 'en-US',
|
||||
name: 'John Client',
|
||||
tz: 'America/New_York'
|
||||
},
|
||||
invitee_responses: [
|
||||
{
|
||||
question: 'What would you like to discuss?',
|
||||
response: 'Product demo and pricing discussion'
|
||||
},
|
||||
{
|
||||
question: 'Company size?',
|
||||
response: '50-100 employees'
|
||||
}
|
||||
],
|
||||
meeting_uuid: '65fb768c-30b9-4a9a-999f-5dab85e66635',
|
||||
modified: '2019-08-24T14:15:22Z',
|
||||
organizer_email: 'sales@company.com',
|
||||
organizer_timezone: 'America/New_York',
|
||||
purpose: 'Sales Demo',
|
||||
scheduling_page_link: 'https://meet.avoma.com/sales-demo',
|
||||
subject: 'Product Demo - John Client',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
|
||||
},
|
||||
async onEnable(context) {
|
||||
// Manual setup - no programmatic registration needed
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
// Manual setup - users manage webhooks in Avoma UI
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const newNote = createTrigger({
|
||||
name: 'new_note',
|
||||
displayName: 'New Note',
|
||||
description:
|
||||
'Triggers when notes are successfully generated for meetings or calls',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {
|
||||
setupInstructions: Property.MarkDown({
|
||||
value: `
|
||||
**Quick Setup:**
|
||||
|
||||
1. In Avoma: **Settings > Integrations > Webhooks**
|
||||
2. **Webhook URL:** \`{{webhookUrl}}\`
|
||||
3. **Event Type:** Select **"AINOTE"**
|
||||
4. **HTTP Method:** POST
|
||||
5. **Content Type:** application/json
|
||||
|
||||
**Note:** Requires admin permissions in Avoma.
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
action_items: [
|
||||
{
|
||||
action_item: 'Follow up with client on project timeline',
|
||||
company: 'Avoma',
|
||||
email: 'john.doe@avoma.com',
|
||||
name: 'John Doe'
|
||||
}
|
||||
],
|
||||
ai_notes: '<h2>Participants</h2><ul><li><p>Avoma: John Doe</p></li></ul>',
|
||||
ai_notes_txt: 'Participants: Avoma: John Doe',
|
||||
attendees: [
|
||||
{
|
||||
email: 'user@example.com',
|
||||
name: 'John Doe',
|
||||
response_status: 'accepted',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
|
||||
}
|
||||
],
|
||||
audio_ready: true,
|
||||
audio_url: 'http://example.com',
|
||||
created: '2019-08-24T14:15:22Z',
|
||||
duration: 3600,
|
||||
end_at: '2019-08-24T14:15:22Z',
|
||||
event_type: 'AINOTE',
|
||||
is_call: true,
|
||||
is_internal: false,
|
||||
meeting_url:
|
||||
'https://app.avoma.com/meeting/aa380fc2-725d-4ef8-909c-c595c0e62bcd',
|
||||
modified: '2019-08-24T14:15:22Z',
|
||||
notes_ready: true,
|
||||
organizer_email: 'user@example.com',
|
||||
organizer_name: 'John Doe',
|
||||
privacy: 'private',
|
||||
processing_status: 'completed',
|
||||
insights: {
|
||||
filler_wpm: [],
|
||||
longest_monologue: {},
|
||||
patience: [],
|
||||
sentiment: {},
|
||||
speaker_mapping: {},
|
||||
talk_stats: {},
|
||||
wpm: []
|
||||
},
|
||||
purpose: {
|
||||
label: 'Sales Call',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
|
||||
},
|
||||
recording_uuid: '3e256a03-2cdd-4fe9-823b-2b61bb25d916',
|
||||
start_at: '2019-08-24T14:15:22Z',
|
||||
state: 'completed',
|
||||
subject: 'Weekly Team Meeting',
|
||||
transcript_ready: true,
|
||||
transcription_uuid: '4753c6bf-25a6-45a1-8d86-0af7c8bde615',
|
||||
transcription_vtt_url: 'http://example.com',
|
||||
uuid: '095be615-a8ad-4c33-8e9c-c7612fbf6c9f',
|
||||
video_ready: true,
|
||||
video_url: 'http://example.com'
|
||||
},
|
||||
async onEnable(context) {
|
||||
// Manual setup - no programmatic registration needed
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
// Manual setup - users manage webhooks in Avoma UI
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user