From ada485ed5c8cc35dbe6330430ca333b4e0df048c Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 23 Oct 2020 09:31:32 +0200 Subject: [PATCH] * :zap: Add company resource to Mautic * :zap: Add company resource * :zap: Small improvement * Tweak descriptions/ labels Added descriptions for resources + fixed a spelling mistake (all just editing "description" fields, nothing else) * :shirt: Fix lint issue Co-authored-by: ricardo Co-authored-by: maxtkacz --- .../nodes/Mautic/CompanyDescription.ts | 387 ++++++++++++++++++ .../nodes/Mautic/ContactCompanyDescription.ts | 75 ++++ .../nodes/Mautic/ContactDescription.ts | 54 +-- .../nodes/Mautic/GenericFunctions.ts | 9 +- .../nodes-base/nodes/Mautic/Mautic.node.ts | 186 ++++++++- .../nodes/Mautic/MauticTrigger.node.ts | 5 +- 6 files changed, 667 insertions(+), 49 deletions(-) create mode 100644 packages/nodes-base/nodes/Mautic/CompanyDescription.ts create mode 100644 packages/nodes-base/nodes/Mautic/ContactCompanyDescription.ts diff --git a/packages/nodes-base/nodes/Mautic/CompanyDescription.ts b/packages/nodes-base/nodes/Mautic/CompanyDescription.ts new file mode 100644 index 0000000000000..4a8ed49440f5c --- /dev/null +++ b/packages/nodes-base/nodes/Mautic/CompanyDescription.ts @@ -0,0 +1,387 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const companyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'company', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new company', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a company', + }, + { + name: 'Get', + value: 'get', + description: 'Get data of a company', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get data of all companies', + }, + { + name: 'Update', + value: 'update', + description: 'Update a company', + }, + ], + default: 'create', + description: 'The operation to perform', + }, +] as INodeProperties[]; + +export const companyFields = [ + + /* -------------------------------------------------------------------------- */ + /* company:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Company Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + default: '', + description: 'The name of the company to create.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Is Published', + name: 'isPublished', + type: 'boolean', + default: false, + }, + { + displayName: 'Overwrite With Blank', + name: 'overwriteWithBlank', + type: 'boolean', + default: false, + description: 'If true, then empty values are set to fields. Otherwise empty values are skipped', + }, + ], + }, + + /* -------------------------------------------------------------------------- */ + /* company:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'companyId', + type: 'string', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'company', + ], + }, + }, + default: '', + description: 'The ID of the company to update.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Company Name', + name: 'name', + type: 'string', + default: '', + description: 'Company name', + }, + { + displayName: 'Is Published', + name: 'isPublished', + type: 'boolean', + default: false, + }, + { + displayName: 'Overwrite With Blank', + name: 'overwriteWithBlank', + type: 'boolean', + default: false, + description: 'If true, then empty values are set to fields. Otherwise empty values are skipped', + }, + ], + }, + + /* -------------------------------------------------------------------------- */ + /* company:get */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'companyId', + type: 'string', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'company', + ], + }, + }, + default: '', + description: 'The ID of the company to return.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'get', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, + + /* -------------------------------------------------------------------------- */ + /* company:getAll */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 30, + }, + default: 30, + description: 'How many results to return.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Order Direction', + name: 'orderByDir', + type: 'options', + options: [ + { + name: 'ASC', + value: 'asc', + }, + { + name: 'DESC', + value: 'desc', + }, + ], + default: '', + description: 'Sort direction: asc or desc.', + }, + { + displayName: 'Order By', + name: 'orderBy', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCompanyFields', + }, + default: '', + description: 'Column to sort by. Can use any column listed in the response.', + }, + { + displayName: 'Search', + name: 'isPublished', + type: 'boolean', + default: '', + description: 'String or search command to filter entities by.', + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* company:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Company ID', + name: 'companyId', + type: 'string', + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'company', + ], + }, + }, + default: '', + description: 'The ID of the company to delete.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'delete', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Mautic/ContactCompanyDescription.ts b/packages/nodes-base/nodes/Mautic/ContactCompanyDescription.ts new file mode 100644 index 0000000000000..6aabd5bc93166 --- /dev/null +++ b/packages/nodes-base/nodes/Mautic/ContactCompanyDescription.ts @@ -0,0 +1,75 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const contactCompanyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'contactCompany', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'add', + description: 'Add contact to a company', + }, + { + name: 'Remove', + value: 'remove', + description: 'Remove a contact from a company', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const contactCompanyFields = [ + + /* -------------------------------------------------------------------------- */ + /* contactCompany:add */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact ID', + name: 'contactId', + type: 'string', + displayOptions: { + show: { + resource: [ + 'contactCompany', + ], + operation: [ + 'add', + 'remove', + ], + }, + }, + default: '', + description: 'The ID of the contact.', + }, + { + displayName: 'Company ID', + name: 'companyId', + type: 'string', + displayOptions: { + show: { + resource: [ + 'contactCompany', + ], + operation: [ + 'add', + 'remove', + ], + }, + }, + default: '', + description: 'The ID of the company.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Mautic/ContactDescription.ts b/packages/nodes-base/nodes/Mautic/ContactDescription.ts index 947c274260799..94888e162be51 100644 --- a/packages/nodes-base/nodes/Mautic/ContactDescription.ts +++ b/packages/nodes-base/nodes/Mautic/ContactDescription.ts @@ -1,4 +1,6 @@ -import { INodeProperties } from 'n8n-workflow'; +import { + INodeProperties, +} from 'n8n-workflow'; export const contactOperations = [ { @@ -19,9 +21,9 @@ export const contactOperations = [ description: 'Create a new contact', }, { - name: 'Update', - value: 'update', - description: 'Update a contact', + name: 'Delete', + value: 'delete', + description: 'Delete a contact', }, { name: 'Get', @@ -34,9 +36,9 @@ export const contactOperations = [ description: 'Get data of all contacts', }, { - name: 'Delete', - value: 'delete', - description: 'Delete a contact', + name: 'Update', + value: 'update', + description: 'Update a contact', }, ], default: 'create', @@ -46,9 +48,9 @@ export const contactOperations = [ export const contactFields = [ -/* -------------------------------------------------------------------------- */ -/* contact:create */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:create */ + /* -------------------------------------------------------------------------- */ { displayName: 'JSON Parameters', name: 'jsonParameters', @@ -450,9 +452,9 @@ export const contactFields = [ ], }, -/* -------------------------------------------------------------------------- */ -/* contact:update */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:update */ + /* -------------------------------------------------------------------------- */ { displayName: 'Contact ID', name: 'contactId', @@ -955,9 +957,9 @@ export const contactFields = [ ], }, -/* -------------------------------------------------------------------------- */ -/* contact:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Contact ID', name: 'contactId', @@ -976,9 +978,9 @@ export const contactFields = [ description: 'Contact ID', }, -/* -------------------------------------------------------------------------- */ -/* contact:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:getAll */ + /* -------------------------------------------------------------------------- */ { displayName: 'Return All', name: 'returnAll', @@ -1021,9 +1023,9 @@ export const contactFields = [ description: 'How many results to return.', }, -/* -------------------------------------------------------------------------- */ -/* contact:delete */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:delete */ + /* -------------------------------------------------------------------------- */ { displayName: 'Contact ID', name: 'contactId', @@ -1042,9 +1044,9 @@ export const contactFields = [ description: 'Contact ID', }, -/* -------------------------------------------------------------------------- */ -/* contact:all */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:all */ + /* -------------------------------------------------------------------------- */ { displayName: 'Options', name: 'options', @@ -1158,7 +1160,7 @@ export const contactFields = [ displayName: 'RAW Data', name: 'rawData', type: 'boolean', - default: false, + default: true, description: `By default only the data of the fields get returned. If this
options gets set the RAW response with all data gets returned.`, }, diff --git a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts index 8a96bb3308af2..9ab48b8dd8f11 100644 --- a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts @@ -1,4 +1,6 @@ -import { OptionsWithUri } from 'request'; +import { + OptionsWithUri, +} from 'request'; import { IExecuteFunctions, @@ -48,11 +50,12 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions if (authenticationMethod === 'credentials') { const credentials = this.getCredentials('mauticApi') as IDataObject; - const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64'); + const base64Key = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64'); options.headers!.Authorization = `Basic ${base64Key}`; options.uri = `${credentials.url}${options.uri}`; + //@ts-ignore returnData = await this.helpers.request(options); } else { @@ -102,7 +105,7 @@ export async function mauticApiRequestAllItems(this: IHookFunctions | IExecuteFu } while ( responseData.total !== undefined && ((query.limit * query.start) - parseInt(responseData.total, 10)) < 0 - ); + ); return returnData; } diff --git a/packages/nodes-base/nodes/Mautic/Mautic.node.ts b/packages/nodes-base/nodes/Mautic/Mautic.node.ts index 8a6bd76e163f7..b024e73c74ad8 100644 --- a/packages/nodes-base/nodes/Mautic/Mautic.node.ts +++ b/packages/nodes-base/nodes/Mautic/Mautic.node.ts @@ -1,6 +1,7 @@ import { IExecuteFunctions, } from 'n8n-core'; + import { IDataObject, ILoadOptionsFunctions, @@ -9,6 +10,7 @@ import { INodeType, INodeTypeDescription, } from 'n8n-workflow'; + import { getErrors, mauticApiRequest, @@ -21,9 +23,19 @@ import { contactOperations, } from './ContactDescription'; +import { + companyFields, + companyOperations, +} from './CompanyDescription'; + +import { + contactCompanyFields, + contactCompanyOperations, +} from './ContactCompanyDescription'; + import { snakeCase, - } from 'change-case'; +} from 'change-case'; export class Mautic implements INodeType { description: INodeTypeDescription = { @@ -86,17 +98,31 @@ export class Mautic implements INodeType { name: 'resource', type: 'options', options: [ + { + name: 'Company', + value: 'company', + description: 'Create or modify a company', + }, { name: 'Contact', value: 'contact', - description: 'Use this endpoint to manipulate and obtain details on Mautic’s contacts.', + description: 'Create & modify contacts', + }, + { + name: 'Contact <> Company', + value: 'contactCompany', + description: 'Add/ remove contacts from a company', }, ], default: 'contact', description: 'Resource to consume.', }, + ...companyOperations, + ...companyFields, ...contactOperations, ...contactFields, + ...contactCompanyOperations, + ...contactCompanyFields, ], }; @@ -110,7 +136,7 @@ export class Mautic implements INodeType { for (const company of companies) { returnData.push({ name: company.fields.all.companyname, - value: company.id, + value: company.fields.all.companyname, }); } return returnData; @@ -141,6 +167,19 @@ export class Mautic implements INodeType { } return returnData; }, + // Get all the available company fields to display them to user so that he can + // select them easily + async getCompanyFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const fields = await mauticApiRequestAllItems.call(this, 'fields', 'GET', '/fields/company'); + for (const field of fields) { + returnData.push({ + name: field.label, + value: field.alias, + }); + } + return returnData; + }, }, }; @@ -156,11 +195,89 @@ export class Mautic implements INodeType { for (let i = 0; i < length; i++) { qs = {}; - const options = this.getNodeParameter('options', i) as IDataObject; + + if (resource === 'company') { + //https://developer.mautic.org/#create-company + if (operation === 'create') { + const name = this.getNodeParameter('name', i) as string; + const simple = this.getNodeParameter('simple', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + const body: IDataObject = { + companyname: name, + }; + Object.assign(body, additionalFields); + responseData = await mauticApiRequest.call(this, 'POST', '/companies/new', body); + responseData = responseData.company; + if (simple === true) { + responseData = responseData.fields.all; + } + } + //https://developer.mautic.org/#edit-company + if (operation === 'update') { + const companyId = this.getNodeParameter('companyId', i) as string; + const simple = this.getNodeParameter('simple', i) as boolean; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + const body: IDataObject = {}; + Object.assign(body, updateFields); + if (body.name) { + body.companyname = body.name; + delete body.name; + } + responseData = await mauticApiRequest.call(this, 'PATCH', `/companies/${companyId}/edit`, body); + responseData = responseData.company; + if (simple === true) { + responseData = responseData.fields.all; + } + } + //https://developer.mautic.org/#get-company + if (operation === 'get') { + const companyId = this.getNodeParameter('companyId', i) as string; + const simple = this.getNodeParameter('simple', i) as boolean; + responseData = await mauticApiRequest.call(this, 'GET', `/companies/${companyId}`); + responseData = responseData.company; + if (simple === true) { + responseData = responseData.fields.all; + } + } + //https://developer.mautic.org/#list-contact-companies + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const simple = this.getNodeParameter('simple', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + qs = Object.assign(qs, additionalFields); + if (returnAll === true) { + responseData = await mauticApiRequestAllItems.call(this, 'companies', 'GET', '/companies', {}, qs); + } else { + qs.limit = this.getNodeParameter('limit', i) as number; + qs.start = 0; + responseData = await mauticApiRequest.call(this, 'GET', '/companies', {}, qs); + if (responseData.errors) { + throw new Error(getErrors(responseData)); + } + responseData = responseData.companies; + responseData = Object.values(responseData); + } + if (simple === true) { + //@ts-ignore + responseData = responseData.map(item => item.fields.all); + } + } + //https://developer.mautic.org/#delete-company + if (operation === 'delete') { + const simple = this.getNodeParameter('simple', i) as boolean; + const companyId = this.getNodeParameter('companyId', i) as string; + responseData = await mauticApiRequest.call(this, 'DELETE', `/companies/${companyId}/delete`); + responseData = responseData.company; + if (simple === true) { + responseData = responseData.fields.all; + } + } + } if (resource === 'contact') { //https://developer.mautic.org/?php#create-contact if (operation === 'create') { + const options = this.getNodeParameter('options', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const jsonActive = this.getNodeParameter('jsonParameters', i) as boolean; let body: IDataObject = {}; @@ -243,12 +360,15 @@ export class Mautic implements INodeType { if (additionalFields.website) { body.website = additionalFields.website as string; } - responseData = await mauticApiRequest.call(this, 'POST', '/contacts/new', body); - responseData = responseData.contact; + responseData = [responseData.contact]; + if (options.rawData === false) { + responseData = responseData.map(item => item.fields.all); + } } //https://developer.mautic.org/?php#edit-contact if (operation === 'update') { + const options = this.getNodeParameter('options', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const contactId = this.getNodeParameter('contactId', i) as string; let body: IDataObject = {}; @@ -343,17 +463,25 @@ export class Mautic implements INodeType { body.website = updateFields.website as string; } responseData = await mauticApiRequest.call(this, 'PATCH', `/contacts/${contactId}/edit`, body); - responseData = responseData.contact; + responseData = [responseData.contact]; + if (options.rawData === false) { + responseData = responseData.map(item => item.fields.all); + } } //https://developer.mautic.org/?php#get-contact if (operation === 'get') { + const options = this.getNodeParameter('options', i) as IDataObject; const contactId = this.getNodeParameter('contactId', i) as string; responseData = await mauticApiRequest.call(this, 'GET', `/contacts/${contactId}`); - responseData = responseData.contact; + responseData = [responseData.contact]; + if (options.rawData === false) { + responseData = responseData.map(item => item.fields.all); + } } //https://developer.mautic.org/?php#list-contacts if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const options = this.getNodeParameter('options', i) as IDataObject; qs = Object.assign(qs, options); if (qs.orderBy) { // For some reason does camelCase get used in the returned data @@ -374,27 +502,49 @@ export class Mautic implements INodeType { responseData = responseData.contacts; responseData = Object.values(responseData); } - + if (options.rawData === false) { + //@ts-ignore + responseData = responseData.map(item => item.fields.all); + } } //https://developer.mautic.org/?php#delete-contact if (operation === 'delete') { + const options = this.getNodeParameter('options', i) as IDataObject; const contactId = this.getNodeParameter('contactId', i) as string; responseData = await mauticApiRequest.call(this, 'DELETE', `/contacts/${contactId}/delete`); - responseData = responseData.contact; + responseData = [responseData.contact]; + if (options.rawData === false) { + responseData = responseData.map(item => item.fields.all); + } } } - if (Array.isArray(responseData)) { - if (options.rawData !== true) { - // @ts-ignore - responseData = responseData.map(item => item.fields.all); + if (resource === 'contactCompany') { + //https://developer.mautic.org/#add-contact-to-a-company + if (operation === 'add') { + const contactId = this.getNodeParameter('contactId', i) as string; + const companyId = this.getNodeParameter('companyId', i) as string; + responseData = await mauticApiRequest.call(this, 'POST', `/companies/${companyId}/contact/${contactId}/add`, {}); + // responseData = responseData.company; + // if (simple === true) { + // responseData = responseData.fields.all; + // } + } + //https://developer.mautic.org/#remove-contact-from-a-company + if (operation === 'remove') { + const contactId = this.getNodeParameter('contactId', i) as string; + const companyId = this.getNodeParameter('companyId', i) as string; + responseData = await mauticApiRequest.call(this, 'POST', `/companies/${companyId}/contact/${contactId}/remove`, {}); + // responseData = responseData.company; + // if (simple === true) { + // responseData = responseData.fields.all; + // } } + } + + if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else { - if (options.rawData !== true) { - // @ts-ignore - responseData = responseData.fields.all; - } returnData.push(responseData as IDataObject); } } diff --git a/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts b/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts index 6e70652476980..b49d7f8bc22dd 100644 --- a/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts +++ b/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts @@ -92,7 +92,8 @@ export class MauticTrigger implements INodeType { loadOptionsMethod: 'getEvents', }, default: [], - }, { + }, + { displayName: 'Events Order', name: 'eventsOrder', type: 'options', @@ -170,7 +171,7 @@ export class MauticTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node'); try { await mauticApiRequest.call(this, 'DELETE', `/hooks/${webhookData.webhookId}/delete`); - } catch(error) { + } catch (error) { return false; } delete webhookData.webhookId;