Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,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;
},
});

View File

@@ -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;
},
});

View File

@@ -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;
},
});

View File

@@ -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;
},
});

View File

@@ -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 };
},
});

View File

@@ -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 };
},
});

View File

@@ -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 };
},
});

View File

@@ -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 };
},
});

View File

@@ -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 };
},
});

View File

@@ -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;
},
});

View File

@@ -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;
},
});