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,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: [] };
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
Reference in New Issue
Block a user