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,37 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import {
|
||||
contactsDropdown,
|
||||
tagsDropdown,
|
||||
teamsDropdown,
|
||||
workspacesDropdown,
|
||||
} from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
export const applyTagToContact = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'applyTagToContact',
|
||||
displayName: 'Apply Tag to Contact',
|
||||
description: 'Apply a tag to a contact if it doesn’t already exist.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
contactId: contactsDropdown(['auth', 'workspaceId']),
|
||||
tagId: tagsDropdown(['auth', 'workspaceId']),
|
||||
},
|
||||
async run({auth, propsValue}) {
|
||||
const payload = {
|
||||
contacts_applied_tag: {
|
||||
tag_id: propsValue.tagId
|
||||
},
|
||||
};
|
||||
|
||||
const response = await clickfunnelsApiService.createAppliedTag(
|
||||
auth.props,
|
||||
propsValue.contactId as string,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import {
|
||||
contactsDropdown,
|
||||
pipelinesDropdown,
|
||||
pipelineStagesDropdown,
|
||||
teamMembershipsDropdown,
|
||||
teamsDropdown,
|
||||
workspacesDropdown,
|
||||
} from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
export const createOpportunity = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'createOpportunity',
|
||||
displayName: 'Create Opportunity',
|
||||
description:
|
||||
'Create a new opportunity for a contact.',
|
||||
props: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Opportunity Name',
|
||||
description: 'The name or title of the opportunity.',
|
||||
required: true,
|
||||
}),
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
pipelineId: pipelinesDropdown(['auth', 'workspaceId']),
|
||||
pipelineStageId: pipelineStagesDropdown(['auth', 'pipelineId']),
|
||||
contactId: contactsDropdown(['auth', 'workspaceId']),
|
||||
assigneeId: teamMembershipsDropdown(['auth', 'teamId'], false),
|
||||
value: Property.Number({
|
||||
displayName: 'Value',
|
||||
description:
|
||||
'The potential value of this opportunity in the default currency of the workspace',
|
||||
required: false,
|
||||
}),
|
||||
closedAt: Property.DateTime({
|
||||
displayName: 'Close Date',
|
||||
description: 'The expected close date for the opportunity.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const payload = {
|
||||
name: propsValue.name,
|
||||
pipelines_stage_id: propsValue.pipelineStageId,
|
||||
primary_contact_id: propsValue.contactId,
|
||||
...(propsValue.value && {
|
||||
value: propsValue.value,
|
||||
}),
|
||||
...(propsValue.closedAt && {
|
||||
closed_at: new Date(propsValue.closedAt as string).toISOString(),
|
||||
}),
|
||||
assignee_id: propsValue.assigneeId,
|
||||
};
|
||||
|
||||
const response = await clickfunnelsApiService.createOpportunity(
|
||||
auth.props,
|
||||
propsValue.workspaceId as string,
|
||||
{
|
||||
sales_opportunity: payload,
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { contactsDropdown, coursesDropdown, teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
|
||||
export const enrollAContactIntoACourse = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'enrollAContactIntoACourse',
|
||||
displayName: 'Enroll a Contact Into a Course',
|
||||
description: 'Create an enrollment for a contact in a course.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
courseId: coursesDropdown(['auth', 'workspaceId']),
|
||||
contactId: contactsDropdown(['auth', 'workspaceId']),
|
||||
},
|
||||
async run({auth, propsValue}) {
|
||||
const payload = {
|
||||
courses_enrollment: {
|
||||
contact_id: propsValue.contactId
|
||||
},
|
||||
};
|
||||
|
||||
const response = await clickfunnelsApiService.createCourseEnrollment(auth.props, propsValue.courseId as string, payload);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
appliedTagsDropdown,
|
||||
contactsDropdown,
|
||||
teamsDropdown,
|
||||
workspacesDropdown,
|
||||
} from '../common/props';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
export const removeTagFromContact = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'removeTagFromContact',
|
||||
displayName: 'Remove Tag From Contact',
|
||||
description: 'Remove a specific tag from a contact.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
contactId: contactsDropdown(['auth', 'workspaceId']),
|
||||
tagId: appliedTagsDropdown(['auth', 'contactId']),
|
||||
},
|
||||
async run({auth, propsValue}) {
|
||||
await clickfunnelsApiService.removeAppliedTags(auth.props, propsValue.tagId as string);
|
||||
return {
|
||||
message: "Tag removed"
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
export const searchContacts = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'searchContacts',
|
||||
displayName: 'Search Contacts',
|
||||
description: 'Look up contacts by ID or email',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
searchTerm: Property.ShortText({
|
||||
displayName: 'Search Query',
|
||||
description: 'Filter contacts by either email or id',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const response = await clickfunnelsApiService.fetchContactByEmailSearch(
|
||||
auth.props,
|
||||
propsValue.workspaceId as string,
|
||||
propsValue.searchTerm as string
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { multiTagsDropdown, teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
export const updateOrCreateContact = createAction({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'updateOrCreateContact',
|
||||
displayName: 'Update or Create Contact',
|
||||
description:
|
||||
'Searches for a contact by email and updates it, or creates a new one if not found.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
emailAddress: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description:
|
||||
"The contact's email address. This is used to find and (update/create) the contact.",
|
||||
required: true,
|
||||
}),
|
||||
firstName: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
lastName: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
required: false,
|
||||
}),
|
||||
phoneNumber: Property.ShortText({
|
||||
displayName: 'Phone Number',
|
||||
required: false,
|
||||
}),
|
||||
tagIds: multiTagsDropdown(['auth', 'workspaceId']),
|
||||
customAttributes: Property.Object({
|
||||
displayName: 'Custom Attributes',
|
||||
description: 'A key-value object for custom contact data. Keys that are default properties on the Contact resource or variations of it will result in an error. E.g., first_name, First Name, etc. are not valid inputs.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run({auth, propsValue}) {
|
||||
const payload = {
|
||||
contact: {
|
||||
email_address: propsValue.emailAddress,
|
||||
first_name: propsValue.firstName,
|
||||
last_name: propsValue.lastName,
|
||||
phone_number: propsValue.phoneNumber,
|
||||
tag_ids: propsValue.tagIds,
|
||||
custom_attributes: propsValue.customAttributes
|
||||
},
|
||||
};
|
||||
|
||||
const response = await clickfunnelsApiService.upsertContact(auth.props, propsValue.workspaceId as string, payload);
|
||||
|
||||
return response
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { PieceAuth, Property } from "@activepieces/pieces-framework";
|
||||
import { clickfunnelsApiService } from "./requests";
|
||||
|
||||
export const CLICKFUNNELS_BASE_URL = (subdomain: string) => `https://${subdomain}.myclickfunnels.com/api/v2`;
|
||||
|
||||
export const API_ENDPOINTS = {
|
||||
ME: '/me',
|
||||
TEAMS: '/teams',
|
||||
WORKSPACES: '/workspaces',
|
||||
PIPELINES: '/sales/pipelines',
|
||||
CONTACTS: '/contacts',
|
||||
COURSES: '/courses',
|
||||
TAGS: '/tags',
|
||||
};
|
||||
|
||||
export type CLICKFUNNELS_APIKEY_AUTH = {
|
||||
subdomain: string;
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export const clickfunnelsAuth = PieceAuth.CustomAuth({
|
||||
description: 'Enter your ClickFunnels subdomain and API key.',
|
||||
required: true,
|
||||
props: {
|
||||
subdomain: Property.ShortText({
|
||||
displayName: 'Subdomain',
|
||||
description:
|
||||
'Your ClickFunnels subdomain (e.g., if your URL is https://mycompany.myclickfunnels.com, enter "mycompany").',
|
||||
required: true,
|
||||
}),
|
||||
apiKey: PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description:
|
||||
'Your ClickFunnels API key. You can find this in your ClickFunnels account settings.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
await clickfunnelsApiService.fetchCurrentlyLoggedInUser(auth).catch((err) => {
|
||||
throw new Error("something went wrong. Please check your username and API key and try again.")
|
||||
})
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
error: `Connection failed: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,474 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsApiService } from './requests';
|
||||
import { clickfunnelsAuth } from './constants';
|
||||
|
||||
export const teamsDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
displayName: 'Team',
|
||||
description: 'Select the team',
|
||||
required: true,
|
||||
refreshers,
|
||||
auth: clickfunnelsAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await clickfunnelsApiService.fetchTeams(auth.props);
|
||||
|
||||
return {
|
||||
options: response.map((team: any) => ({
|
||||
label: team.name,
|
||||
value: team.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load teams. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const coursesDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Course',
|
||||
description: 'Select a course',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, workspaceId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a workspace first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const courses = await clickfunnelsApiService.fetchCourses(
|
||||
auth.props,
|
||||
workspaceId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: courses.map((course: any) => ({
|
||||
label: course.title,
|
||||
value: course.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load teams. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const teamMembershipsDropdown = (
|
||||
refreshers: string[],
|
||||
required = true
|
||||
) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Assignee',
|
||||
description: 'Select an assignee on your team',
|
||||
required,
|
||||
refreshers,
|
||||
options: async ({ auth, teamId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!teamId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a team first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await clickfunnelsApiService.fetchTeam(auth.props, teamId as string);
|
||||
|
||||
return {
|
||||
options: [
|
||||
{ label: 'Leave Unassigned', value: null },
|
||||
...response.memberships,
|
||||
].map((membership) => {
|
||||
if (membership.label) {
|
||||
return {
|
||||
label: membership.label,
|
||||
value: membership.value,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
label: `${membership.user.first_name} ${membership.user.last_name}`,
|
||||
value: membership.id,
|
||||
};
|
||||
}),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load team members. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const workspacesDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Workspace',
|
||||
description: 'Select the workspace',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, teamId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!teamId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a team first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const workspaces = await clickfunnelsApiService.fetchWorkspaces(
|
||||
auth.props,
|
||||
teamId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: workspaces.map((workspace: any) => ({
|
||||
label: workspace.name,
|
||||
value: workspace.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load workspaces. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const pipelinesDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Pipeline',
|
||||
description: 'Select a pipeline',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, workspaceId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a workspace first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const pipelines = await clickfunnelsApiService.fetchPipelines(
|
||||
auth.props,
|
||||
workspaceId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: pipelines.map((pipeline: any) => ({
|
||||
label: pipeline.name,
|
||||
value: pipeline.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load pipelines. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const pipelineStagesDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Pipeline Stage',
|
||||
description: 'Select a pipeline stage.',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, pipelineId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!pipelineId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a pipeline first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const pipelineStages = await clickfunnelsApiService.fetchPipelineStages(
|
||||
auth.props,
|
||||
pipelineId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: pipelineStages.map((pipelineStage: any) => ({
|
||||
label: pipelineStage.name,
|
||||
value: pipelineStage.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load pipeline stages. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const contactsDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Contact',
|
||||
description: 'Select a contact',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, workspaceId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a workspace first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const contacts = await clickfunnelsApiService.fetchContacts(
|
||||
auth.props,
|
||||
workspaceId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: contacts.map((contact: any) => ({
|
||||
label: (() => {
|
||||
const firstName = contact.first_name || '';
|
||||
const lastName = contact.last_name || '';
|
||||
const fullName = `${firstName} ${lastName}`.trim();
|
||||
return (
|
||||
fullName ||
|
||||
contact.email_address ||
|
||||
contact.phone_number ||
|
||||
'Unknown Contact'
|
||||
);
|
||||
})(),
|
||||
value: contact.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
'Failed to load contacts. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const tagsDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Tag',
|
||||
description: 'Select a tag to apply',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, workspaceId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a workspace first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const tags = await clickfunnelsApiService.fetchTags(auth.props, workspaceId as string);
|
||||
|
||||
return {
|
||||
options: tags.map((tag: any) => ({
|
||||
label: tag.name,
|
||||
value: tag.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Failed to load tags. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
export const multiTagsDropdown = (refreshers: string[]) =>
|
||||
Property.MultiSelectDropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Tag',
|
||||
description: 'Select tags to apply',
|
||||
required: false,
|
||||
refreshers,
|
||||
options: async ({ auth, workspaceId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a workspace first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const tags = await clickfunnelsApiService.fetchTags(auth.props, workspaceId as string);
|
||||
|
||||
return {
|
||||
options: tags.map((tag: any) => ({
|
||||
label: tag.name,
|
||||
value: tag.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Failed to load tags. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const appliedTagsDropdown = (refreshers: string[]) =>
|
||||
Property.Dropdown({
|
||||
auth: clickfunnelsAuth,
|
||||
displayName: 'Tag',
|
||||
description: 'Select a tag',
|
||||
required: true,
|
||||
refreshers,
|
||||
options: async ({ auth, contactId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your ClickFunnels account first',
|
||||
};
|
||||
}
|
||||
|
||||
if (!contactId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please select a contact first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const tags = await clickfunnelsApiService.fetchAppliedTags(
|
||||
auth.props,
|
||||
contactId as string
|
||||
);
|
||||
|
||||
return {
|
||||
options: tags.map((tag: any) => ({
|
||||
label: tag.tag.name,
|
||||
value: tag.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Failed to load tags. Please check your authentication.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,245 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import {
|
||||
API_ENDPOINTS,
|
||||
CLICKFUNNELS_BASE_URL,
|
||||
CLICKFUNNELS_APIKEY_AUTH,
|
||||
} from './constants';
|
||||
|
||||
async function fireHttpRequest<T>({
|
||||
method,
|
||||
auth,
|
||||
path,
|
||||
body,
|
||||
}: {
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH;
|
||||
method: HttpMethod;
|
||||
path: string;
|
||||
body?: unknown;
|
||||
}) {
|
||||
const BASE_URL = CLICKFUNNELS_BASE_URL(auth.subdomain);
|
||||
|
||||
return await httpClient
|
||||
.sendRequest({
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${auth.apiKey}`,
|
||||
},
|
||||
body,
|
||||
})
|
||||
.then((res) => res.body);
|
||||
}
|
||||
|
||||
export const clickfunnelsApiService = {
|
||||
fetchCurrentlyLoggedInUser: async (auth: CLICKFUNNELS_APIKEY_AUTH) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: API_ENDPOINTS.ME,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchTeams: async (auth: CLICKFUNNELS_APIKEY_AUTH) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: API_ENDPOINTS.TEAMS,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchTeam: async (auth: CLICKFUNNELS_APIKEY_AUTH, teamId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.TEAMS}/${teamId}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchWorkspaces: async (auth: CLICKFUNNELS_APIKEY_AUTH, teamId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.TEAMS}/${teamId}${API_ENDPOINTS.WORKSPACES}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchContacts: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.CONTACTS}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchContactByEmailSearch: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string,
|
||||
filterQuery: string
|
||||
) => {
|
||||
const isEmail = filterQuery.includes('@');
|
||||
|
||||
const filterParam = isEmail
|
||||
? `filter[email_address]=${encodeURIComponent(filterQuery)}`
|
||||
: `filter[id]=${encodeURIComponent(filterQuery)}`;
|
||||
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.CONTACTS}?${filterParam}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
upsertContact: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string,
|
||||
payload: any
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.POST,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.CONTACTS}/upsert`,
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchTags: async (auth: CLICKFUNNELS_APIKEY_AUTH, workspaceId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.CONTACTS}${API_ENDPOINTS.TAGS}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchCourses: async (auth: CLICKFUNNELS_APIKEY_AUTH, workspaceId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.COURSES}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
createCourseEnrollment: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
courseId: string,
|
||||
payload: any
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.POST,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.COURSES}/${courseId}/enrollments`,
|
||||
body: payload
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchAppliedTags: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
contactId: string
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.CONTACTS}/${contactId}/applied_tags`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
removeAppliedTags: async (auth: CLICKFUNNELS_APIKEY_AUTH, tagId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.CONTACTS}/applied_tags/${tagId}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchPipelines: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}${API_ENDPOINTS.PIPELINES}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
fetchPipelineStages: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
pipelineId: string
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.GET,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.PIPELINES}/${pipelineId}/stages`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
createOpportunity: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string,
|
||||
payload: any
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.POST,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}/sales/opportunities`,
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
createAppliedTag: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
contactId: string,
|
||||
payload: any
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.POST,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.CONTACTS}/${contactId}/applied_tags`,
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
createWebhook: async (
|
||||
auth: CLICKFUNNELS_APIKEY_AUTH,
|
||||
workspaceId: string,
|
||||
payload: any
|
||||
) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.POST,
|
||||
auth,
|
||||
path: `${API_ENDPOINTS.WORKSPACES}/${workspaceId}/webhooks/outgoing/endpoints`,
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
deleteWebhook: async (auth: CLICKFUNNELS_APIKEY_AUTH, webhookId: string) => {
|
||||
const response = await fireHttpRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
auth,
|
||||
path: `/webhooks/outgoing/endpoints/${webhookId}`,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_contact_completed_course_trigger';
|
||||
const MODULE_NAME = 'Contact Completed Course';
|
||||
|
||||
export const contactCompletedCourse = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'contactCompletedCourse',
|
||||
displayName: MODULE_NAME,
|
||||
description: 'Triggers when a contact completes a course.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['courses/enrollment.course_completed'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_contact_identified_trigger';
|
||||
const MODULE_NAME = 'Contact Identified';
|
||||
|
||||
export const contactIdentified = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'contactIdentified',
|
||||
displayName: MODULE_NAME,
|
||||
description: 'Triggers when a new contact is identified by email/phone.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['contact.identified'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_contact_submitted_form_trigger';
|
||||
const MODULE_NAME = 'Contact Submitted Form';
|
||||
|
||||
export const contactSubmittedForm = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'contactSubmittedForm',
|
||||
displayName: MODULE_NAME,
|
||||
description: 'Triggers each time a contact submits a form (opt-in or order).',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['form_submission.created'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_contact_suspended_from_course_trigger';
|
||||
const MODULE_NAME = 'Contact Suspended';
|
||||
|
||||
export const contactSuspendedFromCourse = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'contactSuspendedFromCourse',
|
||||
displayName: `${MODULE_NAME} From Course`,
|
||||
description: 'Triggers when a contact is suspended from a course.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['courses/enrollment.suspended'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_course_enrollment_created_for_contact_trigger';
|
||||
const MODULE_NAME = 'Course Enrollment Created';
|
||||
|
||||
export const courseEnrollmentCreatedForContact = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'courseEnrollmentCreatedForContact',
|
||||
displayName: `${MODULE_NAME} for contact`,
|
||||
description: 'Triggers when a course enrollment is created for a contact.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['courses/enrollment.created'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_onetime_order_paid_trigger';
|
||||
const MODULE_NAME = 'One-Time Order Paid';
|
||||
|
||||
export const oneTimeOrderPaid = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'OneTimeOrderPaid',
|
||||
displayName: MODULE_NAME,
|
||||
description: 'Triggers when a customer pays a one-time order.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['one-time-order.completed'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_scheduled_appointment_event_created_trigger';
|
||||
const MODULE_NAME = 'Scheduled Appointment Event';
|
||||
|
||||
export const scheduledAppointmentEventCreated = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'scheduledAppointmentEventCreated',
|
||||
displayName: `${MODULE_NAME} Created`,
|
||||
description: 'Triggers when a scheduled appointment event is created.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['appointments/scheduled_event.created'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { clickfunnelsAuth } from '../common/constants';
|
||||
import { teamsDropdown, workspacesDropdown } from '../common/props';
|
||||
import { clickfunnelsApiService } from '../common/requests';
|
||||
|
||||
const CACHE_KEY = 'clickfunnels_subscription_invoice_paid_trigger';
|
||||
const MODULE_NAME = 'Subscription Invoice Paid';
|
||||
|
||||
export const subscriptionInvoicePaid = createTrigger({
|
||||
auth: clickfunnelsAuth,
|
||||
name: 'subscriptionInvoicePaid',
|
||||
displayName: MODULE_NAME,
|
||||
description: 'Triggers when a subscription invoice is paid.',
|
||||
props: {
|
||||
teamId: teamsDropdown(['auth']),
|
||||
workspaceId: workspacesDropdown(['auth', 'teamId']),
|
||||
},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable({ auth, webhookUrl, propsValue: { workspaceId }, store }) {
|
||||
if (!workspaceId) {
|
||||
throw new Error('Workspace ID is required. Please select a workspace.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response: any = await clickfunnelsApiService.createWebhook(
|
||||
auth.props,
|
||||
workspaceId as string,
|
||||
{
|
||||
webhooks_outgoing_endpoint: {
|
||||
url: webhookUrl,
|
||||
name: `ActivePieces ${MODULE_NAME} Webhook - ${Date.now()}`,
|
||||
event_type_ids: ['subscription.invoice.paid'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const webhookId = response.id;
|
||||
|
||||
await store.put(CACHE_KEY, { webhookId });
|
||||
} catch (error) {
|
||||
console.error('Failed to create ClickFunnels webhook:', error);
|
||||
throw new Error(
|
||||
`Failed to create webhook: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable({ auth, store }) {
|
||||
const cachedData = (await store.get(CACHE_KEY)) as any;
|
||||
|
||||
if (cachedData) {
|
||||
await clickfunnelsApiService
|
||||
.deleteWebhook(auth.props, cachedData.webhookId)
|
||||
.then(async () => {
|
||||
await store.delete(CACHE_KEY);
|
||||
});
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user