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,115 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const createContact = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'create_contact',
|
||||
displayName: 'Create Contact',
|
||||
description: 'Create a new contact.',
|
||||
props: {
|
||||
is_organization: Property.Checkbox({
|
||||
displayName: 'Is Organization',
|
||||
description: 'Check this box if the contact is an organization.',
|
||||
required: true,
|
||||
defaultValue: false,
|
||||
}),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Organization Name',
|
||||
description: 'The name of the organization. Required if "Is Organization" is checked.',
|
||||
required: false,
|
||||
}),
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
description: 'The last name of the individual. Required if "Is Organization" is not checked.',
|
||||
required: false,
|
||||
}),
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "The contact's primary email address.",
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: "The contact's phone number.",
|
||||
required: false,
|
||||
}),
|
||||
mobile: Property.ShortText({
|
||||
displayName: 'Mobile Phone',
|
||||
description: "The contact's mobile phone number.",
|
||||
required: false,
|
||||
}),
|
||||
tags: zendeskSellCommon.tags('contact'),
|
||||
address: Property.Json({
|
||||
displayName: 'Address',
|
||||
description: 'An object containing address details (e.g., {"line1": "2726 Smith Street", "city": "Hyannis", "country": "US"}).',
|
||||
required: false,
|
||||
defaultValue: {
|
||||
"line1": "",
|
||||
"city": "",
|
||||
"postal_code": "",
|
||||
"state": "",
|
||||
"country": ""
|
||||
}
|
||||
}),
|
||||
custom_fields: Property.Json({
|
||||
displayName: 'Custom Fields',
|
||||
description: 'A key-value object for any custom fields (e.g., {"referral_website": "http://www.example.com"}).',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
}),
|
||||
other_fields: Property.Json({
|
||||
displayName: 'Other Fields',
|
||||
description: 'Enter additional fields as a JSON object (e.g., {"title": "CEO", "website": "http://example.com"}).',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
})
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { is_organization, name, last_name, other_fields, ...otherProps } = propsValue;
|
||||
|
||||
|
||||
if (is_organization && !name) {
|
||||
throw new Error('Organization Name is required when "Is Organization" is checked.');
|
||||
}
|
||||
if (!is_organization && !last_name) {
|
||||
throw new Error('Last Name is required for an individual contact.');
|
||||
}
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
is_organization,
|
||||
...otherProps,
|
||||
...(other_fields || {}),
|
||||
};
|
||||
|
||||
if (is_organization) {
|
||||
rawBody['name'] = name;
|
||||
} else {
|
||||
rawBody['last_name'] = last_name;
|
||||
}
|
||||
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.POST,
|
||||
'v2/contacts',
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const createDeal = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'create_deal',
|
||||
displayName: 'Create Deal',
|
||||
description: 'Create a new deal under an existing contact.',
|
||||
props: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Deal Name',
|
||||
required: true,
|
||||
}),
|
||||
contact_id: zendeskSellCommon.contact(true),
|
||||
value: Property.ShortText({
|
||||
displayName: 'Value',
|
||||
description: 'The monetary value of the deal (e.g., 15000).',
|
||||
required: false,
|
||||
}),
|
||||
currency: Property.ShortText({
|
||||
displayName: 'Currency',
|
||||
description: '3-character currency code (e.g., USD).',
|
||||
required: false,
|
||||
}),
|
||||
pipeline_id: zendeskSellCommon.pipeline(false),
|
||||
stage_id: zendeskSellCommon.stage(false),
|
||||
owner_id: zendeskSellCommon.owner(),
|
||||
source_id: zendeskSellCommon.leadSource(),
|
||||
hot: Property.Checkbox({
|
||||
displayName: 'Hot Deal?',
|
||||
description: 'Check this box to mark the deal as "hot".',
|
||||
required: false,
|
||||
}),
|
||||
tags: zendeskSellCommon.tags('deal'), // Optional Tags
|
||||
custom_fields: Property.Json({
|
||||
displayName: 'Custom Fields',
|
||||
description: 'A key-value object for any custom fields.',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { pipeline_id, ...otherProps } = propsValue;
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
...otherProps,
|
||||
};
|
||||
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.POST,
|
||||
'v2/deals',
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const createLead = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'create_lead',
|
||||
displayName: 'Create Lead',
|
||||
description: 'Create a new lead record.',
|
||||
props: {
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
description: "The lead's last name. Required if Organization Name is empty.",
|
||||
required: false,
|
||||
}),
|
||||
organization_name: Property.ShortText({
|
||||
displayName: 'Organization Name',
|
||||
description: "The lead's organization name. Required if Last Name is empty.",
|
||||
required: false,
|
||||
}),
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
owner_id: zendeskSellCommon.owner(),
|
||||
source_id: zendeskSellCommon.leadSource(),
|
||||
status: Property.ShortText({
|
||||
displayName: 'Status',
|
||||
description: 'The current status of the lead (e.g., "New").',
|
||||
required: false,
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
description: "The lead's job title.",
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "The lead's email address.",
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: "The lead's phone number.",
|
||||
required: false,
|
||||
}),
|
||||
mobile: Property.ShortText({
|
||||
displayName: 'Mobile Phone',
|
||||
description: "The lead's mobile phone number.",
|
||||
required: false,
|
||||
}),
|
||||
tags: zendeskSellCommon.tags('lead'),
|
||||
address: Property.Json({
|
||||
displayName: 'Address',
|
||||
description: 'An object containing address details (e.g., {"line1": "123 Main St", "city": "Anytown"}).',
|
||||
required: false,
|
||||
defaultValue: {
|
||||
"line1": "",
|
||||
"city": "",
|
||||
"postal_code": "",
|
||||
"state": "",
|
||||
"country": ""
|
||||
}
|
||||
}),
|
||||
custom_fields: Property.Json({
|
||||
displayName: 'Custom Fields',
|
||||
description: 'A key-value object for any custom fields (e.g., {"known_via": "tom"}).',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
}),
|
||||
other_fields: Property.Json({
|
||||
displayName: 'Other Fields',
|
||||
description: 'Enter additional fields as a JSON object (e.g., {"description": "I know him via Tom", "website": "http://example.com"}).',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
})
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { last_name, organization_name, other_fields, ...otherProps } = propsValue;
|
||||
|
||||
|
||||
if (!last_name && !organization_name) {
|
||||
throw new Error('Either Last Name or Organization Name is required to create a lead.');
|
||||
}
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
last_name,
|
||||
organization_name,
|
||||
...otherProps,
|
||||
...(other_fields || {}),
|
||||
};
|
||||
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.POST,
|
||||
'v2/leads',
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
import { Property, createAction, DynamicPropsValue } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const createNote = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'create_note',
|
||||
displayName: 'Create Note',
|
||||
description: 'Add a note to a deal, lead, or contact.',
|
||||
props: {
|
||||
resource_type: Property.StaticDropdown({
|
||||
displayName: 'Resource Type',
|
||||
description: 'The type of resource to attach the note to.',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Lead', value: 'lead' },
|
||||
{ label: 'Contact', value: 'contact' },
|
||||
{ label: 'Deal', value: 'deal' },
|
||||
]
|
||||
}
|
||||
}),
|
||||
dynamic_resource_id: Property.DynamicProperties({
|
||||
auth: zendeskSellAuth,
|
||||
displayName: 'Resource ID',
|
||||
description: 'Select the specific resource to attach the note to.',
|
||||
required: true,
|
||||
refreshers: ['resource_type'],
|
||||
props: async (context) => {
|
||||
const resourceType = context['resource_type'] as unknown as string | undefined;
|
||||
const fields: DynamicPropsValue = {};
|
||||
|
||||
if (!resourceType) return {};
|
||||
|
||||
switch (resourceType) {
|
||||
case 'lead':
|
||||
fields['resource_id'] = zendeskSellCommon.lead(true);
|
||||
break;
|
||||
case 'contact':
|
||||
fields['resource_id'] = zendeskSellCommon.contact(true);
|
||||
break;
|
||||
case 'deal':
|
||||
fields['resource_id'] = zendeskSellCommon.deal(true);
|
||||
break;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Content',
|
||||
description: 'The content of the note.',
|
||||
required: true,
|
||||
}),
|
||||
is_important: Property.Checkbox({
|
||||
displayName: 'Important',
|
||||
description: 'Mark the note as important (starred).',
|
||||
required: false,
|
||||
}),
|
||||
type: Property.StaticDropdown({
|
||||
displayName: 'Visibility',
|
||||
description: 'Define the note\'s visibility.',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Regular (Default)', value: 'regular' },
|
||||
{ label: 'Restricted (Creator only)', value: 'restricted' },
|
||||
]
|
||||
}
|
||||
}),
|
||||
tags: Property.Array({
|
||||
displayName: 'Tags',
|
||||
description: 'An array of tags to add to the note (e.g., ["premium", "follow-up"]).',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { resource_type, dynamic_resource_id, ...otherProps } = propsValue;
|
||||
|
||||
const resource_id = (dynamic_resource_id as { resource_id: number })?.resource_id;
|
||||
|
||||
if (!resource_id) {
|
||||
throw new Error('Resource ID is missing. Please select a resource.');
|
||||
}
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
resource_type,
|
||||
resource_id,
|
||||
...otherProps,
|
||||
};
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
|
||||
if (key === 'is_important' && value === false) {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.POST,
|
||||
'v2/notes',
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
export const findCompany = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'find_company',
|
||||
displayName: 'Find Company',
|
||||
description: 'Finds a company (organization contact) by name, email, or phone.',
|
||||
props: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Company Name',
|
||||
description: "The exact name of the company to find.",
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "The company's primary email address.",
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: "The company's primary phone number.",
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { name, email, phone } = propsValue;
|
||||
|
||||
|
||||
const params: Record<string, string> = {
|
||||
is_organization: 'true'
|
||||
};
|
||||
|
||||
|
||||
if (name) params['name'] = name as string;
|
||||
if (email) params['email'] = email as string;
|
||||
if (phone) params['phone'] = phone as string;
|
||||
|
||||
|
||||
if (Object.keys(params).length === 1) {
|
||||
throw new Error('Please provide at least one search field (Company Name, Email, or Phone).');
|
||||
}
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
'v2/contacts',
|
||||
auth,
|
||||
undefined,
|
||||
params
|
||||
);
|
||||
|
||||
const items = (response.body as { items: Record<string, unknown>[] })?.items;
|
||||
|
||||
if (items && items.length > 0) {
|
||||
|
||||
return items[0];
|
||||
}
|
||||
|
||||
|
||||
return { data: null };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
export const findContact = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'find_contact',
|
||||
displayName: 'Find Contact',
|
||||
description: 'Find a contact by email, name, or other identifier.',
|
||||
props: {
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
required: false,
|
||||
}),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
description: "Filter by the contact's full name or organization name.",
|
||||
required: false,
|
||||
}),
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { email, name, first_name, last_name, phone } = propsValue;
|
||||
|
||||
const params: Record<string, string> = {};
|
||||
if (email) params['email'] = email as string;
|
||||
if (name) params['name'] = name as string;
|
||||
if (first_name) params['first_name'] = first_name as string;
|
||||
if (last_name) params['last_name'] = last_name as string;
|
||||
if (phone) params['phone'] = phone as string;
|
||||
|
||||
if (Object.keys(params).length === 0) {
|
||||
throw new Error('Please provide at least one search field (Email, Name, etc.).');
|
||||
}
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
'v2/contacts',
|
||||
auth,
|
||||
undefined,
|
||||
params
|
||||
);
|
||||
|
||||
const items = (response.body as { items: Record<string, unknown>[] })?.items;
|
||||
|
||||
if (items && items.length > 0) {
|
||||
return items[0];
|
||||
}
|
||||
|
||||
|
||||
return { data: null };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
|
||||
export const findDeal = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'find_deal',
|
||||
displayName: 'Find Deal',
|
||||
description: 'Look up a deal by ID or name.',
|
||||
props: {
|
||||
deal_id: Property.Number({
|
||||
displayName: 'Deal ID',
|
||||
description: 'Find a deal by its unique ID. (Prioritized over Name)',
|
||||
required: false,
|
||||
}),
|
||||
deal_name: Property.ShortText({
|
||||
displayName: 'Deal Name',
|
||||
description: 'Find a deal by its exact name. (Used if Deal ID is not provided)',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { deal_id, deal_name } = propsValue;
|
||||
|
||||
if (!deal_id && !deal_name) {
|
||||
throw new Error('Please provide a Deal ID or a Deal Name to find.');
|
||||
}
|
||||
|
||||
|
||||
if (deal_id) {
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
`v2/deals/${deal_id}`,
|
||||
auth
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
|
||||
if (deal_name) {
|
||||
const requestBody = {
|
||||
"items": [
|
||||
{
|
||||
"data": {
|
||||
"query": {
|
||||
"filter": {
|
||||
"filter": {
|
||||
"attribute": { "name": "name" },
|
||||
"parameter": { "eq": deal_name }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"per_page": 1
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.POST,
|
||||
'v3/deals/search',
|
||||
auth,
|
||||
requestBody
|
||||
);
|
||||
|
||||
const searchResponse = response.body as { items: { data: Record<string, unknown> }[] };
|
||||
|
||||
if (searchResponse.items && searchResponse.items.length > 0) {
|
||||
return { data: searchResponse.items[0].data };
|
||||
} else {
|
||||
return { data: null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return { data: null };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const findLead = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'find_lead',
|
||||
displayName: 'Find Lead',
|
||||
description: 'Find a lead by one or more fields.',
|
||||
props: {
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
required: false,
|
||||
}),
|
||||
organization_name: Property.ShortText({
|
||||
displayName: 'Organization Name',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
required: false,
|
||||
}),
|
||||
status: Property.ShortText({
|
||||
displayName: 'Status',
|
||||
description: 'Filter by lead status (e.g., "New").',
|
||||
required: false,
|
||||
}),
|
||||
source_id: zendeskSellCommon.leadSource(),
|
||||
owner_id: zendeskSellCommon.owner(),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
|
||||
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
|
||||
for (const [key, value] of Object.entries(propsValue)) {
|
||||
if (key !== 'auth' && value !== undefined && value !== null && value !== '') {
|
||||
params[key] = value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Object.keys(params).length === 0) {
|
||||
throw new Error('Please provide at least one search field (Email, Name, Status, etc.).');
|
||||
}
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
'v2/leads',
|
||||
auth,
|
||||
undefined,
|
||||
params
|
||||
);
|
||||
|
||||
|
||||
const items = (response.body as { items: Record<string, unknown>[] })?.items;
|
||||
|
||||
if (items && items.length > 0) {
|
||||
return items[0];
|
||||
}
|
||||
|
||||
|
||||
return { data: null };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
export const findUser = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'find_user',
|
||||
displayName: 'Find User',
|
||||
description: 'Finds a user by ID, email, name, or status.',
|
||||
props: {
|
||||
user_id: Property.Number({
|
||||
displayName: 'User ID',
|
||||
description: 'Find a user by their unique ID. (Prioritized over other fields)',
|
||||
required: false,
|
||||
}),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
description: "Find a user by their full name.",
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "Find a user by their email address.",
|
||||
required: false,
|
||||
}),
|
||||
role: Property.StaticDropdown({
|
||||
displayName: 'Role',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'User', value: 'user' },
|
||||
{ label: 'Admin', value: 'admin' },
|
||||
]
|
||||
}
|
||||
}),
|
||||
status: Property.StaticDropdown({
|
||||
displayName: 'Status',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Active', value: 'active' },
|
||||
{ label: 'Inactive', value: 'inactive' },
|
||||
]
|
||||
}
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { user_id, name, email, role, status } = propsValue;
|
||||
|
||||
|
||||
if (user_id) {
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
`v2/users/${user_id}`,
|
||||
auth
|
||||
);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
const params: Record<string, string> = {};
|
||||
if (name) params['name'] = name as string;
|
||||
if (email) params['email'] = email as string;
|
||||
if (role) params['role'] = role as string;
|
||||
if (status) params['status'] = status as string;
|
||||
|
||||
|
||||
if (Object.keys(params).length === 0) {
|
||||
throw new Error('Please provide a User ID or at least one other search field (Name, Email, etc.).');
|
||||
}
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.GET,
|
||||
'v2/users',
|
||||
auth,
|
||||
undefined,
|
||||
params
|
||||
);
|
||||
|
||||
|
||||
const items = (response.body as { items: Record<string, unknown>[] })?.items;
|
||||
|
||||
if (items && items.length > 0) {
|
||||
return items[0];
|
||||
}
|
||||
|
||||
|
||||
return { data: null };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const updateContact = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'update_contact',
|
||||
displayName: 'Update Contact',
|
||||
description: 'Update fields of an existing contact.',
|
||||
props: {
|
||||
contact_id: zendeskSellCommon.contact(true),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Organization Name',
|
||||
description: "The organization's name (only used for organizational contacts).",
|
||||
required: false,
|
||||
}),
|
||||
first_name: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
description: "The contact's first name (only used for individual contacts).",
|
||||
required: false,
|
||||
}),
|
||||
last_name: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
description: "The contact's last name (only used for individual contacts).",
|
||||
required: false,
|
||||
}),
|
||||
owner_id: zendeskSellCommon.owner(),
|
||||
customer_status: Property.StaticDropdown({
|
||||
displayName: 'Customer Status',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'None', value: 'none' },
|
||||
{ label: 'Current', value: 'current' },
|
||||
{ label: 'Past', value: 'past' },
|
||||
]
|
||||
}
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: "The contact's primary email address.",
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: "The contact's phone number.",
|
||||
required: false,
|
||||
}),
|
||||
tags: zendeskSellCommon.tags('contact'),
|
||||
address: Property.Json({
|
||||
displayName: 'Address',
|
||||
description: 'An object containing address details (e.g., {"line1": "2726 Smith Street", "city": "Hyannis", "country": "US"}).',
|
||||
required: false,
|
||||
}),
|
||||
custom_fields: Property.Json({
|
||||
displayName: 'Custom Fields',
|
||||
description: 'A key-value object for any custom fields (e.g., {"referral_website": "http://www.example.com"}).',
|
||||
required: false,
|
||||
}),
|
||||
other_fields: Property.Json({
|
||||
displayName: 'Other Fields',
|
||||
description: 'Enter additional fields as a JSON object (e.g., {"title": "CEO", "website": "http://example.com"}).',
|
||||
required: false
|
||||
})
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
const { contact_id, other_fields, ...otherProps } = propsValue;
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
...otherProps,
|
||||
...(other_fields || {}),
|
||||
};
|
||||
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.PUT,
|
||||
`v2/contacts/${contact_id}`,
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
|
||||
export const updateDeal = createAction({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'update_deal',
|
||||
displayName: 'Update Deal',
|
||||
description: 'Update fields of an existing deal.',
|
||||
props: {
|
||||
deal_id: zendeskSellCommon.deal(true),
|
||||
|
||||
name: Property.ShortText({
|
||||
displayName: 'Deal Name',
|
||||
required: false,
|
||||
}),
|
||||
contact_id: zendeskSellCommon.contact(false),
|
||||
value: Property.Number({
|
||||
displayName: 'Value (Amount)',
|
||||
description: 'The monetary value of the deal (e.g., 1500).',
|
||||
required: false,
|
||||
}),
|
||||
currency: Property.ShortText({
|
||||
displayName: 'Currency',
|
||||
description: '3-character currency code (e.g., USD).',
|
||||
required: false,
|
||||
}),
|
||||
estimated_close_date: Property.ShortText({
|
||||
displayName: 'Estimated Close Date',
|
||||
description: 'The expected close date in YYYY-MM-DD format.',
|
||||
required: false,
|
||||
}),
|
||||
hot: Property.Checkbox({
|
||||
displayName: 'Hot Deal?',
|
||||
description: 'Check this box to mark the deal as "hot".',
|
||||
required: false,
|
||||
}),
|
||||
|
||||
pipeline_id: zendeskSellCommon.pipeline(false),
|
||||
stage_id: zendeskSellCommon.stage(false),
|
||||
owner_id: zendeskSellCommon.owner(),
|
||||
source_id: zendeskSellCommon.leadSource(),
|
||||
tags: zendeskSellCommon.tags('deal'),
|
||||
|
||||
custom_fields: Property.Json({
|
||||
displayName: 'Custom Fields',
|
||||
description: 'A key-value object for any custom fields.',
|
||||
required: false,
|
||||
defaultValue: {}
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { auth, propsValue } = context;
|
||||
|
||||
|
||||
const { deal_id, pipeline_id, ...otherProps } = propsValue;
|
||||
|
||||
const rawBody: Record<string, unknown> = {
|
||||
...otherProps,
|
||||
};
|
||||
|
||||
const cleanedBody = Object.entries(rawBody).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
|
||||
|
||||
if (Object.keys(cleanedBody).length === 0) {
|
||||
throw new Error("No fields were provided to update. Please fill at least one field.");
|
||||
}
|
||||
|
||||
const response = await callZendeskApi(
|
||||
HttpMethod.PUT,
|
||||
`v2/deals/${deal_id}`,
|
||||
auth,
|
||||
{ data: cleanedBody }
|
||||
);
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { PieceAuth, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod, AuthenticationType } from '@activepieces/pieces-common';
|
||||
|
||||
export type ZendeskSellAuth = {
|
||||
email: string;
|
||||
api_token: string;
|
||||
}
|
||||
|
||||
const ZENDESK_SELL_API_URL = 'https://api.getbase.com';
|
||||
|
||||
export const zendeskSellAuth = PieceAuth.CustomAuth({
|
||||
description: `
|
||||
To get your API token:
|
||||
1. Log in to your Zendesk Sell account.
|
||||
2. Go to **Settings > Integrations > APIs**.
|
||||
3. If no token is active, click **Add API Token**.
|
||||
4. Copy the **API Token**.
|
||||
|
||||
You also need your login email.
|
||||
`,
|
||||
required: true,
|
||||
props: {
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email Address',
|
||||
description: 'Your Zendesk login email address.',
|
||||
required: true,
|
||||
}),
|
||||
api_token: PieceAuth.SecretText({
|
||||
displayName: 'API Token',
|
||||
description: 'Your Zendesk Sell API Token.',
|
||||
required: true,
|
||||
})
|
||||
},
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${ZENDESK_SELL_API_URL}/v2/users/self`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username: `${auth.email}/token`,
|
||||
password: auth.api_token,
|
||||
},
|
||||
});
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API token or email.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
HttpMessageBody,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from './auth';
|
||||
import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
|
||||
|
||||
|
||||
export const ZENDESK_SELL_API_URL = 'https://api.getbase.com';
|
||||
|
||||
export async function callZendeskApi<T>(
|
||||
method: HttpMethod,
|
||||
endpoint: string,
|
||||
auth: AppConnectionValueForAuthProperty<typeof zendeskSellAuth>,
|
||||
body?: HttpMessageBody,
|
||||
query?: Record<string, string>
|
||||
): Promise<HttpResponse<T>> {
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: method,
|
||||
url: `${ZENDESK_SELL_API_URL}/${endpoint}`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username: `${auth.props.email}/token`,
|
||||
password: auth.props.api_token,
|
||||
},
|
||||
body: body,
|
||||
queryParams: query,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
return httpClient.sendRequest<T>(request);
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth, ZendeskSellAuth } from './auth';
|
||||
import { callZendeskApi } from './client';
|
||||
|
||||
|
||||
export const zendeskSellCommon = {
|
||||
lead: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Lead',
|
||||
required,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/leads', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (error) {
|
||||
return { disabled: true, placeholder: "Error fetching leads.", options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
contact: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Contact',
|
||||
required,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/contacts', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (error) {
|
||||
return { disabled: true, placeholder: "Error fetching contacts.", options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
tags: (resourceType: 'contact' | 'lead' | 'deal') => Property.MultiSelectDropdown({
|
||||
auth: zendeskSellAuth,
|
||||
displayName: 'Tags',
|
||||
description: 'A list of tags to associate with the record.',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { name: string } }[] }>(
|
||||
HttpMethod.GET, `v2/tags?resource_type=${resourceType}`, auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.name })),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching Zendesk Sell tags:", error);
|
||||
return { disabled: true, placeholder: "Error fetching tags.", options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
leadSource: () => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Lead Source',
|
||||
description: 'The source of the lead.',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/lead_sources', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching Zendesk Sell lead sources:", error);
|
||||
return { disabled: true, placeholder: "Error fetching lead sources.", options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
deal: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Deal',
|
||||
required,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) return { disabled: true, placeholder: 'Connect account first', options: [] };
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/deals', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (e) {
|
||||
return { disabled: true, placeholder: 'Error fetching deals', options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
company: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Company',
|
||||
required,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) return { disabled: true, placeholder: 'Connect account first', options: [] };
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/contacts?is_organization=true', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (e) {
|
||||
return { disabled: true, placeholder: 'Error fetching companies', options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
pipeline: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Pipeline',
|
||||
required,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) return { disabled: true, placeholder: 'Connect account first', options: [] };
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/pipelines', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (e) {
|
||||
return { disabled: true, placeholder: 'Error fetching pipelines', options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
stage: (required = true) => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Stage',
|
||||
required,
|
||||
refreshers: ['pipeline_id'],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
const pipelineId = propsValue['pipeline_id'] as number | undefined;
|
||||
|
||||
if (!auth || !pipelineId) {
|
||||
return { disabled: true, placeholder: 'Select a pipeline first', options: [] };
|
||||
}
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, `v2/pipelines/${pipelineId}/stages`, auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (e) {
|
||||
return { disabled: true, placeholder: 'Error fetching stages', options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
owner: () => Property.Dropdown({
|
||||
auth: zendeskSellAuth,
|
||||
|
||||
displayName: 'Owner',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth
|
||||
if (!auth) return { disabled: true, placeholder: 'Connect account first', options: [] };
|
||||
try {
|
||||
const response = await callZendeskApi<{ items: { data: { id: number; name: string } }[] }>(
|
||||
HttpMethod.GET, 'v2/users', auth
|
||||
);
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.items.map(item => ({ label: item.data.name, value: item.data.id })),
|
||||
};
|
||||
} catch (e) {
|
||||
return { disabled: true, placeholder: 'Error fetching users', options: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { zendeskSellCommon } from '../common/props';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
const PREVIOUS_DEAL_STAGES_STORE_KEY = 'dealEntersStage_previous_stages_v2';
|
||||
|
||||
interface ZendeskDealItem {
|
||||
data: ZendeskDeal;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskDeal {
|
||||
id: number;
|
||||
name: string;
|
||||
stage_id: number;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
|
||||
type TriggerPropsValue = {
|
||||
stage_id: number | undefined;
|
||||
pipeline_id: number | undefined;
|
||||
};
|
||||
|
||||
|
||||
type PreviousDealStagesMap = Record<string, number>;
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, TriggerPropsValue> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskDealItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/deals',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'updated_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.updated_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const dealEntersStage = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'deal_enters_stage',
|
||||
displayName: 'Deal Enters New Stage',
|
||||
description: 'Fires when a deal transitions into a specified pipeline stage by polling for updates.',
|
||||
props: {
|
||||
pipeline_id: zendeskSellCommon.pipeline(true),
|
||||
stage_id: zendeskSellCommon.stage(true),
|
||||
},
|
||||
sampleData: {
|
||||
"id": 67890,
|
||||
"name": "New Big Deal",
|
||||
"value": 50000,
|
||||
"stage_id": 2,
|
||||
"contact_id": 54321,
|
||||
"owner_id": 12345,
|
||||
"updated_at": "2025-10-18T10:30:00Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
|
||||
async test(context) {
|
||||
// For test, we need to handle the case where stage_id might be undefined
|
||||
const testDeals = await pollingHelper.test(polling, context) as ZendeskDeal[];
|
||||
const matchingDeal = testDeals.find(deal => deal.stage_id === context.propsValue.stage_id);
|
||||
return [matchingDeal ?? {}];
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
// Initialize custom state for stage tracking
|
||||
await context.store.put<PreviousDealStagesMap>(PREVIOUS_DEAL_STAGES_STORE_KEY, {});
|
||||
console.log(`Initialized store for dealEntersStage`);
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
await context.store.delete(PREVIOUS_DEAL_STAGES_STORE_KEY);
|
||||
console.log(`Cleaned up store for dealEntersStage`);
|
||||
},
|
||||
|
||||
|
||||
async run(context) {
|
||||
const { propsValue, store } = context;
|
||||
const targetStageId = propsValue.stage_id;
|
||||
const previousDealStages = await store.get<PreviousDealStagesMap>(PREVIOUS_DEAL_STAGES_STORE_KEY) ?? {};
|
||||
|
||||
if (!targetStageId) {
|
||||
throw new Error('Stage ID is required for deal enters stage trigger');
|
||||
}
|
||||
|
||||
console.log(`Polling deals for stage transitions to stage ${targetStageId}`);
|
||||
|
||||
// Get all deals using polling helper
|
||||
const deals = await pollingHelper.poll(polling, context) as ZendeskDeal[];
|
||||
const dealsEnteringTargetStage: ZendeskDeal[] = [];
|
||||
const currentDealStages: PreviousDealStagesMap = { ...previousDealStages };
|
||||
|
||||
for (const deal of deals) {
|
||||
const dealIdStr = deal.id.toString();
|
||||
const previousStageId = previousDealStages[dealIdStr];
|
||||
const currentStageId = deal.stage_id;
|
||||
|
||||
if (currentStageId === targetStageId && previousStageId !== undefined && previousStageId !== targetStageId) {
|
||||
console.log(`Deal ${deal.id} entered stage ${targetStageId} (from ${previousStageId})`);
|
||||
dealsEnteringTargetStage.push(deal);
|
||||
}
|
||||
currentDealStages[dealIdStr] = currentStageId;
|
||||
}
|
||||
|
||||
await store.put(PREVIOUS_DEAL_STAGES_STORE_KEY, currentDealStages);
|
||||
|
||||
console.log(`Found ${dealsEnteringTargetStage.length} deals entering stage ${targetStageId}`);
|
||||
return dealsEnteringTargetStage;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
|
||||
interface ZendeskContactItem {
|
||||
data: ZendeskContact;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskContact {
|
||||
id: number;
|
||||
name: string;
|
||||
email?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskContactItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/contacts',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'created_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.created_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newContact = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'new_contact',
|
||||
displayName: 'New Contact',
|
||||
description: 'Fires when a new contact is created in Zendesk Sell (polls for new records).',
|
||||
props: {
|
||||
|
||||
},
|
||||
sampleData: {
|
||||
"id": 2,
|
||||
"creator_id": 1,
|
||||
"owner_id": 1,
|
||||
"is_organization": false,
|
||||
"contact_id": 1,
|
||||
"name": "Mark Johnson",
|
||||
"first_name": "Mark",
|
||||
"last_name": "Johnson",
|
||||
"customer_status": "none",
|
||||
"email": "mark@designservice.com",
|
||||
"phone": "508-778-6516",
|
||||
"created_at": "2014-08-27T16:32:56Z",
|
||||
"updated_at": "2014-08-27T16:32:56Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskDealItem {
|
||||
data: ZendeskDeal;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskDeal {
|
||||
id: number;
|
||||
name: string;
|
||||
contact_id: number;
|
||||
value: string;
|
||||
stage_id: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskDealItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/deals',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'created_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.created_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newDeal = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'new_deal',
|
||||
displayName: 'New Deal',
|
||||
description: 'Fires when a new deal is created (polls for new records).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 1,
|
||||
"creator_id": 1,
|
||||
"owner_id": 1,
|
||||
"contact_id": 1,
|
||||
"name": "Website Redesign",
|
||||
"value": "15000.0",
|
||||
"currency": "USD",
|
||||
"hot": false,
|
||||
"stage_id": 12,
|
||||
"created_at": "2025-10-27T10:30:00Z",
|
||||
"updated_at": "2025-10-27T10:30:00Z",
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskLeadItem {
|
||||
data: ZendeskLead;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskLead {
|
||||
id: number;
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
organization_name?: string;
|
||||
email?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskLeadItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/leads',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'created_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.created_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newLead = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'new_lead',
|
||||
displayName: 'New Lead',
|
||||
description: 'Fires when a new lead is created (polls for new records).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 1,
|
||||
"creator_id": 1,
|
||||
"owner_id": 1,
|
||||
"first_name": "Mark",
|
||||
"last_name": "Johnson",
|
||||
"organization_name": "Design Services Company",
|
||||
"status": "New",
|
||||
"source_id": 10,
|
||||
"email": "mark@example.com",
|
||||
"phone": "508-778-6516",
|
||||
"created_at": "2014-08-27T16:32:56Z",
|
||||
"updated_at": "2014-08-27T16:32:56Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskNoteItem {
|
||||
data: ZendeskNote;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskNote {
|
||||
id: number;
|
||||
creator_id: number;
|
||||
resource_type: string;
|
||||
resource_id: number;
|
||||
content: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskNoteItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/notes',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'created_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.created_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newNote = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'new_note',
|
||||
displayName: 'New Note',
|
||||
description: 'Fires when a new note is added to a record (lead, contact, deal) (polls for new records).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 1,
|
||||
"creator_id": 1,
|
||||
"resource_type": "lead",
|
||||
"resource_id": 1,
|
||||
"content": "Highly important.",
|
||||
"is_important": true,
|
||||
"created_at": "2014-08-27T16:32:56Z",
|
||||
"updated_at": "2014-08-27T17:32:56Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskContactItem {
|
||||
data: ZendeskContact;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskContact {
|
||||
id: number;
|
||||
name: string;
|
||||
email?: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS } ) {
|
||||
const response = await callZendeskApi<{ items: ZendeskContactItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/contacts',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'updated_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.updated_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const updatedContact = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'updated_contact',
|
||||
displayName: 'Updated Contact',
|
||||
description: 'Fires when an existing contact is updated (polls for updates).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 2,
|
||||
"creator_id": 1,
|
||||
"owner_id": 1,
|
||||
"is_organization": false,
|
||||
"contact_id": 1,
|
||||
"name": "Mark Johnson",
|
||||
"first_name": "Mark",
|
||||
"last_name": "Johnson",
|
||||
"customer_status": "current",
|
||||
"email": "mark@designservice.com",
|
||||
"phone": "508-778-6516",
|
||||
"created_at": "2014-08-27T16:32:56Z",
|
||||
"updated_at": "2025-10-18T10:30:00Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskDealItem {
|
||||
data: ZendeskDeal;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskDeal {
|
||||
id: number;
|
||||
name: string;
|
||||
value: string;
|
||||
stage_id: number;
|
||||
contact_id: number;
|
||||
owner_id: number;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskDealItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/deals',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'updated_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.updated_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const updatedDeal = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'updated_deal',
|
||||
displayName: 'Updated Deal',
|
||||
description: 'Fires when an existing deal is modified (polls for updates).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 123,
|
||||
"contact_id": 456,
|
||||
"name": "Updated Deal Name",
|
||||
"value": "25000.0",
|
||||
"currency": "USD",
|
||||
"owner_id": 789,
|
||||
"stage_id": 1,
|
||||
"created_at": "2025-10-20T10:00:00Z",
|
||||
"updated_at": "2025-10-27T01:21:00Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import { zendeskSellAuth } from '../common/auth';
|
||||
import { callZendeskApi } from '../common/client';
|
||||
|
||||
interface ZendeskLeadItem {
|
||||
data: ZendeskLead;
|
||||
meta: { type: string };
|
||||
}
|
||||
interface ZendeskLead {
|
||||
id: number;
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
organization_name?: string;
|
||||
email?: string;
|
||||
status?: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zendeskSellAuth>, Record<string, never>> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const response = await callZendeskApi<{ items: ZendeskLeadItem[] }>(
|
||||
HttpMethod.GET,
|
||||
'v2/leads',
|
||||
auth,
|
||||
undefined,
|
||||
{
|
||||
sort_by: 'updated_at:desc',
|
||||
per_page: lastFetchEpochMS === 0 ? '10' : '100',
|
||||
}
|
||||
);
|
||||
|
||||
return response.body.items.map((item) => ({
|
||||
epochMilliSeconds: new Date(item.data.updated_at).getTime(),
|
||||
data: item.data,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const updatedLead = createTrigger({
|
||||
auth: zendeskSellAuth,
|
||||
name: 'updated_lead',
|
||||
displayName: 'Updated Lead',
|
||||
description: 'Fires when an existing lead record is updated (polls for updates).',
|
||||
props: {},
|
||||
sampleData: {
|
||||
"id": 1,
|
||||
"creator_id": 1,
|
||||
"owner_id": 1,
|
||||
"first_name": "Mark",
|
||||
"last_name": "Johnson",
|
||||
"organization_name": "Design Services Inc.",
|
||||
"status": "Contacted",
|
||||
"source_id": 10,
|
||||
"title": "Senior Designer",
|
||||
"description": "Updated description.",
|
||||
"email": "mark.johnson@example.com",
|
||||
"phone": "508-778-6516",
|
||||
"mobile": "508-778-6517",
|
||||
"created_at": "2024-08-27T16:32:56Z",
|
||||
"updated_at": "2025-10-18T10:25:00Z"
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user