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:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,48 @@
import { createPiece } from '@activepieces/pieces-framework';
import { oncehubAuth } from './lib/common/auth';
import { PieceCategory } from '@activepieces/shared';
import { findContact } from './lib/actions/find-contact';
import { createContact } from './lib/actions/create-contact';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { bookingCanceled } from './lib/triggers/booking-canceled';
import { bookingCanceledThenRescheduled } from './lib/triggers/booking-canceled-then-rescheduled';
import { bookingCompleted } from './lib/triggers/booking-completed';
import { bookingNoshow } from './lib/triggers/booking-no-show';
import { bookingRescheduled } from './lib/triggers/booking-rescheduled';
import { bookingScheduled } from './lib/triggers/booking-scheduled';
import { conversationAbandoned } from './lib/triggers/conversation-abandoned';
import { conversationClosed } from './lib/triggers/conversation-closed';
import { conversationStarted } from './lib/triggers/conversation-started';
export const oncehub = createPiece({
displayName: 'Oncehub',
auth: oncehubAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/oncehub.png',
categories: [PieceCategory.SALES_AND_CRM],
description:
'Build meaningful on-brand scheduling experiences with OnceHubs online appointment booking software',
authors: ['sanket-a11y'],
actions: [
findContact,
createContact,
createCustomApiCallAction({
auth: oncehubAuth,
baseUrl: () => `https://api.oncehub.com/v2`,
authMapping: async (auth) => ({
'API-Key': `${auth.secret_text}`,
}),
}),
],
triggers: [
bookingCanceledThenRescheduled,
bookingCanceled,
bookingCompleted,
bookingNoshow,
bookingRescheduled,
bookingScheduled,
conversationAbandoned,
conversationClosed,
conversationStarted,
],
});

View File

@@ -0,0 +1,160 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const createContact = createAction({
auth: oncehubAuth,
name: 'createContact',
displayName: 'Create Contact',
description:
'Create a new contact in Oncehub. Either email or mobile_phone is required.',
props: {
first_name: Property.ShortText({
displayName: 'First Name',
description: 'First name of the contact',
required: true,
}),
last_name: Property.ShortText({
displayName: 'Last Name',
description: 'Last name of the contact',
required: true,
}),
email: Property.ShortText({
displayName: 'Email',
description:
'Email address of the contact (at least email or mobile_phone required)',
required: false,
}),
mobile_phone: Property.ShortText({
displayName: 'Mobile Phone',
description:
'Mobile phone number in E.164 format (at least email or mobile_phone required)',
required: false,
}),
phone: Property.ShortText({
displayName: 'Phone',
description: 'Phone number in E.164 format',
required: false,
}),
company: Property.ShortText({
displayName: 'Company',
description: 'Company name',
required: false,
}),
job_title: Property.ShortText({
displayName: 'Job Title',
description: 'Job title of the contact',
required: false,
}),
street_address: Property.ShortText({
displayName: 'Street Address',
description: 'Street address',
required: false,
}),
city: Property.ShortText({
displayName: 'City',
description: 'City of the contact',
required: false,
}),
state: Property.ShortText({
displayName: 'State',
description: 'State or province',
required: false,
}),
post_code: Property.ShortText({
displayName: 'Postal Code',
description: 'Postal code',
required: false,
}),
country: Property.ShortText({
displayName: 'Country',
description: 'Country of the contact',
required: false,
}),
company_size: Property.ShortText({
displayName: 'Company Size',
description: "Size of the contact's company",
required: false,
}),
employees: Property.Number({
displayName: 'Employees',
description: 'Number of employees',
required: false,
}),
salutation: Property.ShortText({
displayName: 'Salutation',
description: 'Salutation (e.g., Mr., Ms., Dr.)',
required: false,
}),
status: Property.StaticDropdown({
displayName: 'Status',
description: 'Status of the contact',
required: false,
options: {
disabled: false,
options: [
{ label: 'Qualified', value: 'Qualified' },
{ label: 'Sales qualified', value: 'Sales qualified' },
{ label: 'Marketing qualified', value: 'Marketing qualified' },
{ label: 'Disqualified', value: 'Disqualified' },
],
},
}),
},
async run(context) {
const {
first_name,
last_name,
email,
mobile_phone,
phone,
company,
job_title,
street_address,
city,
state,
post_code,
country,
company_size,
employees,
salutation,
status,
} = context.propsValue;
const api_key = context.auth.secret_text;
if (!email && !mobile_phone) {
throw new Error('Either email or mobile_phone is required');
}
const body: any = {
first_name,
last_name,
};
if (email) body.email = email;
if (mobile_phone) body.mobile_phone = mobile_phone;
if (phone) body.phone = phone;
if (company) body.company = company;
if (job_title) body.job_title = job_title;
if (street_address) body.street_address = street_address;
if (city) body.city = city;
if (state) body.state = state;
if (post_code) body.post_code = post_code;
if (country) body.country = country;
if (company_size) body.company_size = company_size;
if (employees !== undefined) body.employees = employees;
if (salutation) body.salutation = salutation;
if (status) body.status = status;
const response = await makeRequest(
api_key,
HttpMethod.POST,
'/contacts',
body
);
return response;
},
});

View File

@@ -0,0 +1,36 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const findContact = createAction({
auth: oncehubAuth,
name: 'findContact',
displayName: 'Find Contact',
description: 'Search for contacts in Oncehub by various criteria',
props: {
email: Property.ShortText({
displayName: 'Email',
description: 'Filter contacts by email address',
required: true,
}),
},
async run(context) {
const { email } = context.propsValue;
const api_key = context.auth.secret_text;
const params = new URLSearchParams();
if (email) {
params.append('email', email);
}
const queryString = params.toString();
const path = `/contacts${queryString ? `?${queryString}` : ''}`;
const response = await makeRequest(api_key, HttpMethod.GET, path);
return response;
},
});

View File

@@ -0,0 +1,22 @@
import { PieceAuth } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
export const oncehubAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: 'Oncehub API Key',
required: true,
validate: async ({ auth }) => {
try {
console.log('auth', auth);
await makeRequest(auth, HttpMethod.GET, '/test');
return { valid: true };
} catch (error) {
return {
valid: false,
error: 'Invalid API credentials',
};
}
},
});

View File

@@ -0,0 +1,25 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = `https://api.oncehub.com/v2`;
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: {
'API-Key': `${api_key}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}

View File

@@ -0,0 +1,110 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const bookingCanceledThenRescheduled = createTrigger({
auth: oncehubAuth,
name: 'bookingCanceledThenRescheduled',
displayName: 'Booking Canceled Then Rescheduled',
description:
'Triggered when Customer cancels a booking and then reschedules on a different booking page.',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'booking.canceled_then_rescheduled',
api_version: 'v2',
data: {
object: 'booking',
id: 'BKNG-J4FR05BKEWEX',
tracking_id: 'D36E0002',
subject: 'Live demo',
status: 'scheduled',
in_trash: false,
creation_time: '2020-03-22T09:48:48Z',
starting_time: '2020-03-22T04:30:00Z',
customer_timezone: 'America/New_York',
last_updated_time: '2020-03-22T09:48:48Z',
'...': '[Additional Properties Truncated]',
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
conversation: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: 'CTC-9QEG09XXYN',
owner: 'USR-GNSBE50D6A',
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
cancel_reschedule_url: 'https://oncehub.com/m/BKNG-3KM0HY2BF9SL',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking Canceled Then Rescheduled Webhook - ${new Date().getTime()}`,
events: ['booking.canceled_then_rescheduled'],
});
await context.store.put('webhookId_canceled_then_rescheduled', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get(
'webhookId_canceled_then_rescheduled'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_canceled_then_rescheduled');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,108 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const bookingCanceled = createTrigger({
auth: oncehubAuth,
name: 'bookingCanceled',
displayName: 'Booking Canceled',
description: 'Triggered when User or Customer cancels a booking',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'booking.canceled',
api_version: 'v2',
data: {
object: 'booking',
id: 'BKNG-J4FR05BKEWEX',
tracking_id: 'D36E0002',
subject: 'Live demo',
status: 'scheduled',
in_trash: false,
creation_time: '2020-03-22T09:48:48Z',
starting_time: '2020-03-22T04:30:00Z',
customer_timezone: 'America/New_York',
last_updated_time: '2020-03-22T09:48:48Z',
'...': '[Additional Properties Truncated]',
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
conversation: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: 'CTC-9QEG09XXYN',
owner: 'USR-GNSBE50D6A',
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
cancel_reschedule_url: 'https://oncehub.com/m/BKNG-3KM0HY2BF9SL',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking Canceled Webhook - ${new Date().getTime()}`,
events: ['booking.canceled'],
});
await context.store.put('webhookId_bookingCanceled', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_bookingCanceled'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_bookingCanceled');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,41 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { on } from 'events';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const bookingCompleted = createTrigger({
auth: oncehubAuth,
name: 'bookingCompleted',
displayName: 'Booking Completed',
description: 'Triggered when booking end time has passed.',
props: {},
sampleData: {},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking Completed Webhook - ${new Date().getTime()}`,
events: ['booking.completed'],
});
await context.store.put('webhookId_bookingCompleted', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_bookingCompleted'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_bookingCompleted');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,109 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
import { oncehubAuth } from '../common/auth';
export const bookingNoshow = createTrigger({
auth: oncehubAuth,
name: 'bookingNoshow',
displayName: 'Booking No-Show',
description: 'Triggered when User sets the completed booking to No-show',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'booking.no_show',
api_version: 'v2',
data: {
object: 'booking',
id: 'BKNG-J4FR05BKEWEX',
tracking_id: 'D36E0002',
subject: 'Live demo',
status: 'scheduled',
in_trash: false,
creation_time: '2020-03-22T09:48:48Z',
starting_time: '2020-03-22T04:30:00Z',
customer_timezone: 'America/New_York',
last_updated_time: '2020-03-22T09:48:48Z',
'...': '[Additional Properties Truncated]',
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
conversation: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: 'CTC-9QEG09XXYN',
owner: 'USR-GNSBE50D6A',
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
cancel_reschedule_url: 'https://oncehub.com/m/BKNG-3KM0HY2BF9SL',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking No-Show Webhook - ${new Date().getTime()}`,
events: ['booking.no_show'],
});
await context.store.put('webhookId_bookingNoshow', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_bookingNoshow'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_bookingNoshow');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,110 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const bookingRescheduled = createTrigger({
auth: oncehubAuth,
name: 'bookingRescheduled',
displayName: 'Booking Rescheduled',
description:
'Triggered when Customer reschedules a booking on the same booking page and Customer reschedules a booking following a request from the User to reschedule',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'booking.rescheduled',
api_version: 'v2',
data: {
object: 'booking',
id: 'BKNG-J4FR05BKEWEX',
tracking_id: 'D36E0002',
subject: 'Live demo',
status: 'scheduled',
in_trash: false,
creation_time: '2020-03-22T09:48:48Z',
starting_time: '2020-03-22T04:30:00Z',
customer_timezone: 'America/New_York',
last_updated_time: '2020-03-22T09:48:48Z',
'...': '[Additional Properties Truncated]',
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
conversation: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: 'CTC-9QEG09XXYN',
owner: 'USR-GNSBE50D6A',
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
cancel_reschedule_url: 'https://oncehub.com/m/BKNG-3KM0HY2BF9SL',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking Rescheduled Webhook - ${new Date().getTime()}`,
events: ['booking.rescheduled'],
});
await context.store.put('webhookId_bookingRescheduled', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_bookingRescheduled'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_bookingRescheduled');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,110 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const bookingScheduled = createTrigger({
auth: oncehubAuth,
name: 'bookingScheduled',
displayName: 'Booking Scheduled',
description:
'Triggered when Customer schedules a booking and when User approves a booking requested by a Customer',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'booking.scheduled',
api_version: 'v2',
data: {
object: 'booking',
id: 'BKNG-J4FR05BKEWEX',
tracking_id: 'D36E0002',
subject: 'Live demo',
status: 'scheduled',
in_trash: false,
creation_time: '2020-03-22T09:48:48Z',
starting_time: '2020-03-22T04:30:00Z',
customer_timezone: 'America/New_York',
last_updated_time: '2020-03-22T09:48:48Z',
'...': '[Additional Properties Truncated]',
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
conversation: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: 'CTC-9QEG09XXYN',
owner: 'USR-GNSBE50D6A',
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
cancel_reschedule_url: 'https://oncehub.com/m/BKNG-3KM0HY2BF9SL',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `Booking Scheduled Webhook - ${new Date().getTime()}`,
events: ['booking.scheduled'],
});
await context.store.put('webhookId_bookingScheduled', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_bookingScheduled'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_bookingScheduled');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,94 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const conversationAbandoned = createTrigger({
auth: oncehubAuth,
name: 'conversationAbandoned',
displayName: 'Conversation Abandoned',
description:
'Triggered when website visitor stops interacting with a bot for more than 10 minutes.',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'conversation.abandoned',
api_version: 'v2',
data: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `conversation abandoned Webhook - ${new Date().getTime()}`,
events: ['conversation.abandoned'],
});
await context.store.put('webhookId_conversationAbandoned', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_conversationAbandoned'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_conversationAbandoned');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,94 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { oncehubAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const conversationClosed = createTrigger({
auth: oncehubAuth,
name: 'conversationClosed',
displayName: 'Conversation Closed',
description:
'Triggered when: Website visitor reaches the end of the conversation flow and when Website visitor starts a new conversation with a different chatbot',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'conversation.closed',
api_version: 'v2',
data: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `conversation closed Webhook - ${new Date().getTime()}`,
events: ['conversation.closed'],
});
await context.store.put('webhookId_conversationClosed', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_conversationClosed'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_conversationClosed');
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,94 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { makeRequest } from '../common/client';
import { oncehubAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
export const conversationStarted = createTrigger({
auth: oncehubAuth,
name: 'conversationStarted',
displayName: 'Conversation Started',
description:
'Triggered when website visitor starts interacting with a chatbot.',
props: {},
sampleData: {
id: 'EVNT-KN56U3YL7C',
object: 'event',
creation_time: '2020-03-22T09:49:12Z',
type: 'conversation.started',
api_version: 'v2',
data: {
id: 'CVR-022EAEA41C',
object: 'conversation',
creation_time: '2021-07-13T12:28:24Z',
initiated_by: 'contact',
last_updated_time: '2021-07-13T12:33:54Z',
last_interacted_time: '2021-07-13T12:33:54Z',
contact: {
object: 'contact',
id: 'CTC-J4FR05BKEW',
creation_time: '2020-03-22T09:48:48Z',
last_updated_time: '2020-03-22T09:48:48Z',
last_interacted_time: null,
owner: 'USR-FSD423423',
status: 'Qualified',
city: 'New York',
company_size: '50-100',
company: 'Acme Inc',
country: 'United States',
email: 'carrie.customer@gmail.com',
employees: 1,
first_name: 'Carrie',
has_consent: false,
job_title: 'Executive Assistant',
last_name: 'Customer',
mobile_phone: '+12025550195',
phone: '+12025550100',
post_code: '10001',
salutation: 'Ms.',
state: 'New York',
street_address: '123 Main Street',
terms_of_sevice: false,
timezone: 'America/New_York',
custom_fields: [],
},
owner: {
first_name: 'Andrea',
last_name: 'Hartie',
email: 'AndreaHartie@example.com',
role_name: 'Member',
timezone: 'America/Chicago',
teams: ['TM-GCJU8DLBTPY1'],
},
status: 'closed',
bot: 'BOT-62774A40FB',
'...': '[Additional Properties Truncated]',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const api_key = context.auth.secret_text;
const { webhookUrl } = context;
const response = await makeRequest(api_key, HttpMethod.POST, '/webhooks', {
url: webhookUrl,
name: `conversation started Webhook - ${new Date().getTime()}`,
events: ['conversation.started'],
});
await context.store.put('webhookId_conversationStarted', response.id);
},
async onDisable(context) {
const api_key = context.auth.secret_text;
const webhookId = await context.store.get<string>(
'webhookId_conversationStarted'
);
if (webhookId) {
await makeRequest(api_key, HttpMethod.DELETE, `/webhooks/${webhookId}`);
}
await context.store.delete('webhookId_conversationStarted');
},
async run(context) {
return [context.payload.body];
},
});