diff --git a/packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts b/packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts
new file mode 100644
index 000000000..0301bf2c5
--- /dev/null
+++ b/packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts
@@ -0,0 +1,46 @@
+import {
+ ICredentialType,
+ NodePropertyTypes,
+} from 'n8n-workflow';
+
+export class HelpScoutOAuth2Api implements ICredentialType {
+ name = 'helpScoutOAuth2Api';
+ extends = [
+ 'oAuth2Api',
+ ];
+ displayName = 'HelpScout OAuth2 API';
+ properties = [
+ {
+ displayName: 'Authorization URL',
+ name: 'authUrl',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'https://secure.helpscout.net/authentication/authorizeClientApplication',
+ required: true,
+ },
+ {
+ displayName: 'Access Token URL',
+ name: 'accessTokenUrl',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'https://api.helpscout.net/v2/oauth2/token',
+ required: true,
+ },
+ {
+ displayName: 'Scope',
+ name: 'scope',
+ type: 'hidden' as NodePropertyTypes,
+ default: '',
+ },
+ {
+ displayName: 'Auth URI Query Parameters',
+ name: 'authQueryParameters',
+ type: 'hidden' as NodePropertyTypes,
+ default: '',
+ },
+ {
+ displayName: 'Authentication',
+ name: 'authentication',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'body',
+ },
+ ];
+}
diff --git a/packages/nodes-base/nodes/HelpScout/ConversationDescription.ts b/packages/nodes-base/nodes/HelpScout/ConversationDescription.ts
new file mode 100644
index 000000000..5d882ac80
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/ConversationDescription.ts
@@ -0,0 +1,598 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const conversationOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a new conversation',
+ },
+ {
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a conversation',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a conversation',
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all conversations',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const conversationFields = [
+/* -------------------------------------------------------------------------- */
+/* conversation:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Mailbox',
+ name: 'mailboxId',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getMailboxes',
+ },
+ required: true,
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ default: '',
+ description: 'ID of a mailbox where the conversation is being created',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ required: true,
+ options: [
+ {
+ name: 'Active',
+ value: 'active',
+ },
+ {
+ name: 'Closed',
+ value: 'closed',
+ },
+ {
+ name: 'Pending',
+ value: 'pending',
+ },
+ ],
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ default: '',
+ description: 'Conversation status',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'string',
+ required: true,
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ default: '',
+ description: `Conversation’s subject`,
+ },
+ {
+ displayName: 'Type',
+ name: 'type',
+ required: true,
+ type: 'options',
+ options: [
+ {
+ name: 'Chat',
+ value: 'chat',
+ },
+ {
+ name: 'Email',
+ value: 'email',
+ },
+ {
+ name: 'Phone',
+ value: 'phone',
+ },
+ ],
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ default: '',
+ description: 'Conversation type',
+ },
+ {
+ displayName: 'Resolve Data',
+ name: 'resolveData',
+ type: 'boolean',
+ default: true,
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ description: 'By default the response only contain the ID to resource
. If this option gets activated it
will resolve the data automatically.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Assign To',
+ name: 'assignTo',
+ type: 'number',
+ default: 0,
+ description: 'The Help Scout user assigned to the conversation.',
+ },
+ {
+ displayName: 'Auto Reply',
+ name: 'autoReply',
+ type: 'boolean',
+ default: false,
+ description: `When autoReply is set to true, an auto reply will be sent
+ as long as there is at least one customer thread in the conversation.`,
+ },
+ {
+ displayName: 'Closed At',
+ name: 'closedAt',
+ type: 'dateTime',
+ default: '',
+ description: `When the conversation was closed, only applicable for imported conversations`,
+ },
+ {
+ displayName: 'Created At',
+ name: 'createdAt',
+ type: 'dateTime',
+ default: '',
+ description: `When this conversation was created - ISO 8601 date time`,
+ },
+ {
+ displayName: 'Customer Email',
+ name: 'customerEmail',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Customer ID',
+ name: 'customerId',
+ type: 'number',
+ default: 0,
+ },
+ {
+ displayName: 'Imported',
+ name: 'imported',
+ type: 'boolean',
+ default: false,
+ description: `When imported is set to true, no outgoing emails or notifications will be generated.`,
+ },
+ {
+ displayName: 'Tags',
+ name: 'tags',
+ type: 'multiOptions',
+ typeOptions: {
+ loadOptionsMethod: 'getTags',
+ },
+ default: [],
+ description: 'List of tags to be be added to the conversation',
+ },
+ {
+ displayName: 'User ID',
+ name: 'user',
+ type: 'number',
+ default: 0,
+ description: 'ID of the user who is adding the conversation and threads.',
+ },
+ ]
+ },
+ {
+ displayName: 'Threads',
+ name: 'threadsUi',
+ placeholder: 'Add Thread',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'conversation',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Thread',
+ name: 'threadsValues',
+ values: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ options: [
+ {
+ name: 'Chat',
+ value: 'chat'
+ },
+ {
+ name: 'Customer',
+ value: 'customer'
+ },
+ {
+ name: 'Note',
+ value: 'note'
+ },
+ {
+ name: 'Phone',
+ value: 'phone'
+ },
+ {
+ name: 'Reply',
+ value: 'reply'
+ },
+ ],
+ default: '',
+ },
+ {
+ displayName: 'Text',
+ name: 'text',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true
+ },
+ default: '',
+ description: 'The message text.'
+ },
+ {
+ displayName: 'Bcc',
+ name: 'bcc',
+ displayOptions: {
+ show: {
+ type: [
+ 'customer'
+ ],
+ },
+ },
+ type: 'string',
+ typeOptions: {
+ multipleValues: true,
+ multipleValueButtonText: 'Add Email',
+ },
+ default: [],
+ description: 'Email addresses.'
+ },
+ {
+ displayName: 'Cc',
+ name: 'cc',
+ displayOptions: {
+ show: {
+ type: [
+ 'customer'
+ ],
+ },
+ },
+ type: 'string',
+ typeOptions: {
+ multipleValues: true,
+ multipleValueButtonText: 'Add Email',
+ },
+ default: [],
+ description: 'Email addresses.'
+ },
+ {
+ displayName: 'Draft',
+ name: 'draft',
+ displayOptions: {
+ show: {
+ type: [
+ 'reply'
+ ],
+ },
+ },
+ type: 'boolean',
+ default: false,
+ description: 'If set to true, a draft reply is created',
+ },
+ ],
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* conversation:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Conversation ID',
+ name: 'conversationId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'conversation',
+ ],
+ operation: [
+ 'get',
+ ],
+ },
+ },
+ description: 'conversation ID',
+ },
+/* -------------------------------------------------------------------------- */
+/* conversation:delete */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Conversation ID',
+ name: 'conversationId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'conversation',
+ ],
+ operation: [
+ 'delete',
+ ],
+ },
+ },
+ description: 'conversation ID',
+ },
+/* -------------------------------------------------------------------------- */
+/* conversation:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Option',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'conversation',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Assign To',
+ name: 'assignTo',
+ type: 'number',
+ default: 0,
+ description: 'Filters conversations by assignee id',
+ },
+ {
+ displayName: 'Embed',
+ name: 'embed',
+ type: 'options',
+ options: [
+ {
+ name: 'Threads',
+ value: 'threads',
+ },
+ ],
+ default: '',
+ description: 'Allows embedding/loading of sub-entities',
+ },
+ {
+ displayName: 'Folder ID',
+ name: 'folder',
+ type: 'string',
+ default: '',
+ description: 'Filters conversations from a specific folder id',
+ },
+ {
+ displayName: 'Mailbox ID',
+ name: 'mailbox',
+ type: 'string',
+ default: '',
+ description: 'Filters conversations from a specific mailbox',
+ },
+ {
+ displayName: 'Modified Since',
+ name: 'modifiedSince',
+ type: 'dateTime',
+ default: '',
+ description: 'Returns only conversations that were modified after this date',
+ },
+ {
+ displayName: 'Number',
+ name: 'number',
+ type: 'number',
+ default: 0,
+ typeOptions: {
+ minValue: 0,
+ },
+ description: 'Looks up conversation by conversation number',
+ },
+ {
+ displayName: 'Query',
+ name: 'query',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Advanced search Examples'
+ },
+ {
+ displayName: 'Sort Field',
+ name: 'sortField',
+ type: 'options',
+ options: [
+ {
+ name: 'Created At',
+ value: 'createdAt',
+ },
+ {
+ name: 'customer Email',
+ value: 'customerEmail',
+ },
+ {
+ name: 'customer Name',
+ value: 'customerName',
+ },
+ {
+ name: 'Mailbox ID',
+ value: 'mailboxid',
+ },
+ {
+ name: 'Modified At',
+ value: 'modifiedAt',
+ },
+ {
+ name: 'Number',
+ value: 'number',
+ },
+ {
+ name: 'Score',
+ value: 'score',
+ },
+ {
+ name: 'Status',
+ value: 'status',
+ },
+ {
+ name: 'Subject',
+ value: 'subject',
+ },
+ ],
+ default: '',
+ description: 'Sorts the result by specified field',
+ },
+ {
+ displayName: 'Sort Order',
+ name: 'sortOrder',
+ type: 'options',
+ options: [
+ {
+ name: 'ASC',
+ value: 'asc',
+ },
+ {
+ name: 'Desc',
+ value: 'desc',
+ },
+ ],
+ default: 'desc',
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ options: [
+ {
+ name: 'Active',
+ value: 'active',
+ },
+ {
+ name: 'All',
+ value: 'all',
+ },
+ {
+ name: 'Closed',
+ value: 'closed',
+ },
+ {
+ name: 'Open',
+ value: 'open',
+ },
+ {
+ name: 'Pending',
+ value: 'pending',
+ },
+ {
+ name: 'Spam',
+ value: 'spam',
+ },
+ ],
+ default: 'active',
+ description: 'Filter conversation by status',
+ },
+ {
+ displayName: 'Tags',
+ name: 'tags',
+ type: 'multiOptions',
+ typeOptions: {
+ loadOptionsMethod: 'getTags',
+ },
+ default: [],
+ description: 'Filter conversation by tags',
+ },
+ ],
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/HelpScout/ConversationInterface.ts b/packages/nodes-base/nodes/HelpScout/ConversationInterface.ts
new file mode 100644
index 000000000..ea617f5aa
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/ConversationInterface.ts
@@ -0,0 +1,18 @@
+import { IDataObject } from 'n8n-workflow';
+
+export interface IConversation {
+ assignTo?: number;
+ autoReply?: boolean;
+ closedAt?: string;
+ createdAt?: string;
+ customer?: IDataObject;
+ fields?: IDataObject[];
+ imported?: boolean;
+ mailboxId?: number;
+ status?: string;
+ subject?: string;
+ tags?: IDataObject[];
+ threads?: IDataObject[];
+ type?: string;
+ user?: number;
+}
diff --git a/packages/nodes-base/nodes/HelpScout/CountriesCodes.ts b/packages/nodes-base/nodes/HelpScout/CountriesCodes.ts
new file mode 100644
index 000000000..3c41a76c7
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/CountriesCodes.ts
@@ -0,0 +1,1579 @@
+export const countriesCodes = [
+ {
+ 'name': 'Afghanistan',
+ 'alpha2': 'AF',
+ 'alpha3': 'AFG',
+ 'numeric': '004'
+ },
+ {
+ 'name': 'Åland Islands',
+ 'alpha2': 'AX',
+ 'alpha3': 'ALA',
+ 'numeric': '248',
+ 'altName': 'Aland Islands'
+ },
+ {
+ 'name': 'Albania',
+ 'alpha2': 'AL',
+ 'alpha3': 'ALB',
+ 'numeric': '008'
+ },
+ {
+ 'name': 'Algeria',
+ 'alpha2': 'DZ',
+ 'alpha3': 'DZA',
+ 'numeric': '012'
+ },
+ {
+ 'name': 'American Samoa',
+ 'alpha2': 'AS',
+ 'alpha3': 'ASM',
+ 'numeric': '016'
+ },
+ {
+ 'name': 'Andorra',
+ 'alpha2': 'AD',
+ 'alpha3': 'AND',
+ 'numeric': '020'
+ },
+ {
+ 'name': 'Angola',
+ 'alpha2': 'AO',
+ 'alpha3': 'AGO',
+ 'numeric': '024'
+ },
+ {
+ 'name': 'Anguilla',
+ 'alpha2': 'AI',
+ 'alpha3': 'AIA',
+ 'numeric': '660'
+ },
+ {
+ 'name': 'Antarctica',
+ 'alpha2': 'AQ',
+ 'alpha3': 'ATA',
+ 'numeric': '010'
+ },
+ {
+ 'name': 'Antigua and Barbuda',
+ 'alpha2': 'AG',
+ 'alpha3': 'ATG',
+ 'numeric': '028'
+ },
+ {
+ 'name': 'Argentina',
+ 'alpha2': 'AR',
+ 'alpha3': 'ARG',
+ 'numeric': '032'
+ },
+ {
+ 'name': 'Armenia',
+ 'alpha2': 'AM',
+ 'alpha3': 'ARM',
+ 'numeric': '051'
+ },
+ {
+ 'name': 'Aruba',
+ 'alpha2': 'AW',
+ 'alpha3': 'ABW',
+ 'numeric': '533'
+ },
+ {
+ 'name': 'Australia',
+ 'alpha2': 'AU',
+ 'alpha3': 'AUS',
+ 'numeric': '036'
+ },
+ {
+ 'name': 'Austria',
+ 'alpha2': 'AT',
+ 'alpha3': 'AUT',
+ 'numeric': '040'
+ },
+ {
+ 'name': 'Azerbaijan',
+ 'alpha2': 'AZ',
+ 'alpha3': 'AZE',
+ 'numeric': '031'
+ },
+ {
+ 'name': 'Bahamas (the)',
+ 'alpha2': 'BS',
+ 'alpha3': 'BHS',
+ 'numeric': '044',
+ 'altName': 'Bahamas'
+ },
+ {
+ 'name': 'Bahrain',
+ 'alpha2': 'BH',
+ 'alpha3': 'BHR',
+ 'numeric': '048'
+ },
+ {
+ 'name': 'Bangladesh',
+ 'alpha2': 'BD',
+ 'alpha3': 'BGD',
+ 'numeric': '050'
+ },
+ {
+ 'name': 'Barbados',
+ 'alpha2': 'BB',
+ 'alpha3': 'BRB',
+ 'numeric': '052'
+ },
+ {
+ 'name': 'Belarus',
+ 'alpha2': 'BY',
+ 'alpha3': 'BLR',
+ 'numeric': '112'
+ },
+ {
+ 'name': 'Belgium',
+ 'alpha2': 'BE',
+ 'alpha3': 'BEL',
+ 'numeric': '056'
+ },
+ {
+ 'name': 'Belize',
+ 'alpha2': 'BZ',
+ 'alpha3': 'BLZ',
+ 'numeric': '084'
+ },
+ {
+ 'name': 'Benin',
+ 'alpha2': 'BJ',
+ 'alpha3': 'BEN',
+ 'numeric': '204'
+ },
+ {
+ 'name': 'Bermuda',
+ 'alpha2': 'BM',
+ 'alpha3': 'BMU',
+ 'numeric': '060'
+ },
+ {
+ 'name': 'Bhutan',
+ 'alpha2': 'BT',
+ 'alpha3': 'BTN',
+ 'numeric': '064'
+ },
+ {
+ 'name': 'Bolivia (Plurinational State of)',
+ 'alpha2': 'BO',
+ 'alpha3': 'BOL',
+ 'numeric': '068',
+ 'altName': 'Bolivia'
+ },
+ {
+ 'name': 'Bonaire, Sint Eustatius and Saba',
+ 'alpha2': 'BQ',
+ 'alpha3': 'BES',
+ 'numeric': '535'
+ },
+ {
+ 'name': 'Bosnia and Herzegovina',
+ 'alpha2': 'BA',
+ 'alpha3': 'BIH',
+ 'numeric': '070'
+ },
+ {
+ 'name': 'Botswana',
+ 'alpha2': 'BW',
+ 'alpha3': 'BWA',
+ 'numeric': '072'
+ },
+ {
+ 'name': 'Bouvet Island',
+ 'alpha2': 'BV',
+ 'alpha3': 'BVT',
+ 'numeric': '074'
+ },
+ {
+ 'name': 'Brazil',
+ 'alpha2': 'BR',
+ 'alpha3': 'BRA',
+ 'numeric': '076'
+ },
+ {
+ 'name': 'British Indian Ocean Territory (the)',
+ 'alpha2': 'IO',
+ 'alpha3': 'IOT',
+ 'numeric': '086',
+ 'altName': 'British Indian Ocean Territory'
+ },
+ {
+ 'name': 'Brunei Darussalam',
+ 'alpha2': 'BN',
+ 'alpha3': 'BRN',
+ 'numeric': '096',
+ 'shortName': 'Brunei'
+ },
+ {
+ 'name': 'Bulgaria',
+ 'alpha2': 'BG',
+ 'alpha3': 'BGR',
+ 'numeric': '100'
+ },
+ {
+ 'name': 'Burkina Faso',
+ 'alpha2': 'BF',
+ 'alpha3': 'BFA',
+ 'numeric': '854'
+ },
+ {
+ 'name': 'Burundi',
+ 'alpha2': 'BI',
+ 'alpha3': 'BDI',
+ 'numeric': '108'
+ },
+ {
+ 'name': 'Cabo Verde',
+ 'alpha2': 'CV',
+ 'alpha3': 'CPV',
+ 'numeric': '132',
+ 'altName': 'Cape Verde'
+ },
+ {
+ 'name': 'Cambodia',
+ 'alpha2': 'KH',
+ 'alpha3': 'KHM',
+ 'numeric': '116'
+ },
+ {
+ 'name': 'Cameroon',
+ 'alpha2': 'CM',
+ 'alpha3': 'CMR',
+ 'numeric': '120'
+ },
+ {
+ 'name': 'Canada',
+ 'alpha2': 'CA',
+ 'alpha3': 'CAN',
+ 'numeric': '124'
+ },
+ {
+ 'name': 'Cayman Islands (the)',
+ 'alpha2': 'KY',
+ 'alpha3': 'CYM',
+ 'numeric': '136',
+ 'altName': 'Cayman Islands'
+ },
+ {
+ 'name': 'Central African Republic (the)',
+ 'alpha2': 'CF',
+ 'alpha3': 'CAF',
+ 'numeric': '140',
+ 'altName': 'Central African Republic'
+ },
+ {
+ 'name': 'Chad',
+ 'alpha2': 'TD',
+ 'alpha3': 'TCD',
+ 'numeric': '148'
+ },
+ {
+ 'name': 'Chile',
+ 'alpha2': 'CL',
+ 'alpha3': 'CHL',
+ 'numeric': '152'
+ },
+ {
+ 'name': 'China',
+ 'alpha2': 'CN',
+ 'alpha3': 'CHN',
+ 'numeric': '156'
+ },
+ {
+ 'name': 'Christmas Island',
+ 'alpha2': 'CX',
+ 'alpha3': 'CXR',
+ 'numeric': '162'
+ },
+ {
+ 'name': 'Cocos (Keeling) Islands (the)',
+ 'alpha2': 'CC',
+ 'alpha3': 'CCK',
+ 'numeric': '166',
+ 'altName': 'Cocos (Keeling) Islands',
+ 'shortName': 'Cocos Islands'
+ },
+ {
+ 'name': 'Colombia',
+ 'alpha2': 'CO',
+ 'alpha3': 'COL',
+ 'numeric': '170'
+ },
+ {
+ 'name': 'Comoros (the)',
+ 'alpha2': 'KM',
+ 'alpha3': 'COM',
+ 'numeric': '174',
+ 'altName': 'Comoros'
+ },
+ {
+ 'name': 'Congo (the Democratic Republic of the)',
+ 'alpha2': 'CD',
+ 'alpha3': 'COD',
+ 'numeric': '180',
+ 'altName': 'Congo, (Kinshasa)',
+ 'shortName': 'Democratic Republic of the Congo'
+ },
+ {
+ 'name': 'Congo (the)',
+ 'alpha2': 'CG',
+ 'alpha3': 'COG',
+ 'numeric': '178',
+ 'altName': 'Congo (Brazzaville)',
+ 'shortName': 'Republic of the Congo'
+ },
+ {
+ 'name': 'Cook Islands (the)',
+ 'alpha2': 'CK',
+ 'alpha3': 'COK',
+ 'numeric': '184',
+ 'altName': 'Cook Islands'
+ },
+ {
+ 'name': 'Costa Rica',
+ 'alpha2': 'CR',
+ 'alpha3': 'CRI',
+ 'numeric': '188'
+ },
+ {
+ 'name': 'Côte d\'Ivoire',
+ 'alpha2': 'CI',
+ 'alpha3': 'CIV',
+ 'numeric': '384',
+ 'shortName': 'Ivory Coast'
+ },
+ {
+ 'name': 'Croatia',
+ 'alpha2': 'HR',
+ 'alpha3': 'HRV',
+ 'numeric': '191'
+ },
+ {
+ 'name': 'Cuba',
+ 'alpha2': 'CU',
+ 'alpha3': 'CUB',
+ 'numeric': '192'
+ },
+ {
+ 'name': 'Curaçao',
+ 'alpha2': 'CW',
+ 'alpha3': 'CUW',
+ 'numeric': '531',
+ 'shortName': 'Curacao'
+ },
+ {
+ 'name': 'Cyprus',
+ 'alpha2': 'CY',
+ 'alpha3': 'CYP',
+ 'numeric': '196'
+ },
+ {
+ 'name': 'Czechia',
+ 'alpha2': 'CZ',
+ 'alpha3': 'CZE',
+ 'numeric': '203',
+ 'altName': 'Czech Republic'
+ },
+ {
+ 'name': 'Denmark',
+ 'alpha2': 'DK',
+ 'alpha3': 'DNK',
+ 'numeric': '208'
+ },
+ {
+ 'name': 'Djibouti',
+ 'alpha2': 'DJ',
+ 'alpha3': 'DJI',
+ 'numeric': '262'
+ },
+ {
+ 'name': 'Dominica',
+ 'alpha2': 'DM',
+ 'alpha3': 'DMA',
+ 'numeric': '212'
+ },
+ {
+ 'name': 'Dominican Republic (the)',
+ 'alpha2': 'DO',
+ 'alpha3': 'DOM',
+ 'numeric': '214',
+ 'altName': 'Dominican Republic'
+ },
+ {
+ 'name': 'Ecuador',
+ 'alpha2': 'EC',
+ 'alpha3': 'ECU',
+ 'numeric': '218'
+ },
+ {
+ 'name': 'Egypt',
+ 'alpha2': 'EG',
+ 'alpha3': 'EGY',
+ 'numeric': '818'
+ },
+ {
+ 'name': 'El Salvador',
+ 'alpha2': 'SV',
+ 'alpha3': 'SLV',
+ 'numeric': '222'
+ },
+ {
+ 'name': 'Equatorial Guinea',
+ 'alpha2': 'GQ',
+ 'alpha3': 'GNQ',
+ 'numeric': '226'
+ },
+ {
+ 'name': 'Eritrea',
+ 'alpha2': 'ER',
+ 'alpha3': 'ERI',
+ 'numeric': '232'
+ },
+ {
+ 'name': 'Estonia',
+ 'alpha2': 'EE',
+ 'alpha3': 'EST',
+ 'numeric': '233'
+ },
+ {
+ 'name': 'Ethiopia',
+ 'alpha2': 'ET',
+ 'alpha3': 'ETH',
+ 'numeric': '231'
+ },
+ {
+ 'name': 'Falkland Islands (the) [Malvinas]',
+ 'alpha2': 'FK',
+ 'alpha3': 'FLK',
+ 'numeric': '238',
+ 'altName': 'Falkland Islands (Malvinas)',
+ 'shortName': 'Falkland Islands'
+ },
+ {
+ 'name': 'Faroe Islands (the)',
+ 'alpha2': 'FO',
+ 'alpha3': 'FRO',
+ 'numeric': '234',
+ 'altName': 'Faroe Islands'
+ },
+ {
+ 'name': 'Fiji',
+ 'alpha2': 'FJ',
+ 'alpha3': 'FJI',
+ 'numeric': '242'
+ },
+ {
+ 'name': 'Finland',
+ 'alpha2': 'FI',
+ 'alpha3': 'FIN',
+ 'numeric': '246'
+ },
+ {
+ 'name': 'France',
+ 'alpha2': 'FR',
+ 'alpha3': 'FRA',
+ 'numeric': '250'
+ },
+ {
+ 'name': 'French Guiana',
+ 'alpha2': 'GF',
+ 'alpha3': 'GUF',
+ 'numeric': '254'
+ },
+ {
+ 'name': 'French Polynesia',
+ 'alpha2': 'PF',
+ 'alpha3': 'PYF',
+ 'numeric': '258'
+ },
+ {
+ 'name': 'French Southern Territories (the)',
+ 'alpha2': 'TF',
+ 'alpha3': 'ATF',
+ 'numeric': '260',
+ 'altName': 'French Southern Territories'
+ },
+ {
+ 'name': 'Gabon',
+ 'alpha2': 'GA',
+ 'alpha3': 'GAB',
+ 'numeric': '266'
+ },
+ {
+ 'name': 'Gambia (the)',
+ 'alpha2': 'GM',
+ 'alpha3': 'GMB',
+ 'numeric': '270',
+ 'altName': 'Gambia'
+ },
+ {
+ 'name': 'Georgia',
+ 'alpha2': 'GE',
+ 'alpha3': 'GEO',
+ 'numeric': '268'
+ },
+ {
+ 'name': 'Germany',
+ 'alpha2': 'DE',
+ 'alpha3': 'DEU',
+ 'numeric': '276'
+ },
+ {
+ 'name': 'Ghana',
+ 'alpha2': 'GH',
+ 'alpha3': 'GHA',
+ 'numeric': '288'
+ },
+ {
+ 'name': 'Gibraltar',
+ 'alpha2': 'GI',
+ 'alpha3': 'GIB',
+ 'numeric': '292'
+ },
+ {
+ 'name': 'Greece',
+ 'alpha2': 'GR',
+ 'alpha3': 'GRC',
+ 'numeric': '300'
+ },
+ {
+ 'name': 'Greenland',
+ 'alpha2': 'GL',
+ 'alpha3': 'GRL',
+ 'numeric': '304'
+ },
+ {
+ 'name': 'Grenada',
+ 'alpha2': 'GD',
+ 'alpha3': 'GRD',
+ 'numeric': '308'
+ },
+ {
+ 'name': 'Guadeloupe',
+ 'alpha2': 'GP',
+ 'alpha3': 'GLP',
+ 'numeric': '312'
+ },
+ {
+ 'name': 'Guam',
+ 'alpha2': 'GU',
+ 'alpha3': 'GUM',
+ 'numeric': '316'
+ },
+ {
+ 'name': 'Guatemala',
+ 'alpha2': 'GT',
+ 'alpha3': 'GTM',
+ 'numeric': '320'
+ },
+ {
+ 'name': 'Guernsey',
+ 'alpha2': 'GG',
+ 'alpha3': 'GGY',
+ 'numeric': '831'
+ },
+ {
+ 'name': 'Guinea',
+ 'alpha2': 'GN',
+ 'alpha3': 'GIN',
+ 'numeric': '324'
+ },
+ {
+ 'name': 'Guinea-Bissau',
+ 'alpha2': 'GW',
+ 'alpha3': 'GNB',
+ 'numeric': '624'
+ },
+ {
+ 'name': 'Guyana',
+ 'alpha2': 'GY',
+ 'alpha3': 'GUY',
+ 'numeric': '328'
+ },
+ {
+ 'name': 'Haiti',
+ 'alpha2': 'HT',
+ 'alpha3': 'HTI',
+ 'numeric': '332'
+ },
+ {
+ 'name': 'Heard Island and McDonald Islands',
+ 'alpha2': 'HM',
+ 'alpha3': 'HMD',
+ 'numeric': '334',
+ 'altName': 'Heard and Mcdonald Islands'
+ },
+ {
+ 'name': 'Holy See (the)',
+ 'alpha2': 'VA',
+ 'alpha3': 'VAT',
+ 'numeric': '336',
+ 'altName': 'Holy See (Vatican City State)',
+ 'shortName': 'Vatican'
+ },
+ {
+ 'name': 'Honduras',
+ 'alpha2': 'HN',
+ 'alpha3': 'HND',
+ 'numeric': '340'
+ },
+ {
+ 'name': 'Hong Kong',
+ 'alpha2': 'HK',
+ 'alpha3': 'HKG',
+ 'numeric': '344',
+ 'altName': 'Hong Kong, SAR China'
+ },
+ {
+ 'name': 'Hungary',
+ 'alpha2': 'HU',
+ 'alpha3': 'HUN',
+ 'numeric': '348'
+ },
+ {
+ 'name': 'Iceland',
+ 'alpha2': 'IS',
+ 'alpha3': 'ISL',
+ 'numeric': '352'
+ },
+ {
+ 'name': 'India',
+ 'alpha2': 'IN',
+ 'alpha3': 'IND',
+ 'numeric': '356'
+ },
+ {
+ 'name': 'Indonesia',
+ 'alpha2': 'ID',
+ 'alpha3': 'IDN',
+ 'numeric': '360'
+ },
+ {
+ 'name': 'Iran (Islamic Republic of)',
+ 'alpha2': 'IR',
+ 'alpha3': 'IRN',
+ 'numeric': '364',
+ 'altName': 'Iran, Islamic Republic of',
+ 'shortName': 'Iran'
+ },
+ {
+ 'name': 'Iraq',
+ 'alpha2': 'IQ',
+ 'alpha3': 'IRQ',
+ 'numeric': '368'
+ },
+ {
+ 'name': 'Ireland',
+ 'alpha2': 'IE',
+ 'alpha3': 'IRL',
+ 'numeric': '372'
+ },
+ {
+ 'name': 'Isle of Man',
+ 'alpha2': 'IM',
+ 'alpha3': 'IMN',
+ 'numeric': '833'
+ },
+ {
+ 'name': 'Israel',
+ 'alpha2': 'IL',
+ 'alpha3': 'ISR',
+ 'numeric': '376'
+ },
+ {
+ 'name': 'Italy',
+ 'alpha2': 'IT',
+ 'alpha3': 'ITA',
+ 'numeric': '380'
+ },
+ {
+ 'name': 'Jamaica',
+ 'alpha2': 'JM',
+ 'alpha3': 'JAM',
+ 'numeric': '388'
+ },
+ {
+ 'name': 'Japan',
+ 'alpha2': 'JP',
+ 'alpha3': 'JPN',
+ 'numeric': '392'
+ },
+ {
+ 'name': 'Jersey',
+ 'alpha2': 'JE',
+ 'alpha3': 'JEY',
+ 'numeric': '832'
+ },
+ {
+ 'name': 'Jordan',
+ 'alpha2': 'JO',
+ 'alpha3': 'JOR',
+ 'numeric': '400'
+ },
+ {
+ 'name': 'Kazakhstan',
+ 'alpha2': 'KZ',
+ 'alpha3': 'KAZ',
+ 'numeric': '398'
+ },
+ {
+ 'name': 'Kenya',
+ 'alpha2': 'KE',
+ 'alpha3': 'KEN',
+ 'numeric': '404'
+ },
+ {
+ 'name': 'Kiribati',
+ 'alpha2': 'KI',
+ 'alpha3': 'KIR',
+ 'numeric': '296'
+ },
+ {
+ 'name': 'Korea (the Democratic People\'s Republic of)',
+ 'alpha2': 'KP',
+ 'alpha3': 'PRK',
+ 'numeric': '408',
+ 'altName': 'Korea (North)',
+ 'shortName': 'North Korea'
+ },
+ {
+ 'name': 'Korea (the Republic of)',
+ 'alpha2': 'KR',
+ 'alpha3': 'KOR',
+ 'numeric': '410',
+ 'altName': 'Korea (South)',
+ 'shortName': 'South Korea'
+ },
+ {
+ 'name': 'Kuwait',
+ 'alpha2': 'KW',
+ 'alpha3': 'KWT',
+ 'numeric': '414'
+ },
+ {
+ 'name': 'Kyrgyzstan',
+ 'alpha2': 'KG',
+ 'alpha3': 'KGZ',
+ 'numeric': '417'
+ },
+ {
+ 'name': 'Lao People\'s Democratic Republic (the)',
+ 'alpha2': 'LA',
+ 'alpha3': 'LAO',
+ 'numeric': '418',
+ 'altName': 'Lao PDR',
+ 'shortName': 'Laos'
+ },
+ {
+ 'name': 'Latvia',
+ 'alpha2': 'LV',
+ 'alpha3': 'LVA',
+ 'numeric': '428'
+ },
+ {
+ 'name': 'Lebanon',
+ 'alpha2': 'LB',
+ 'alpha3': 'LBN',
+ 'numeric': '422'
+ },
+ {
+ 'name': 'Lesotho',
+ 'alpha2': 'LS',
+ 'alpha3': 'LSO',
+ 'numeric': '426'
+ },
+ {
+ 'name': 'Liberia',
+ 'alpha2': 'LR',
+ 'alpha3': 'LBR',
+ 'numeric': '430'
+ },
+ {
+ 'name': 'Libya',
+ 'alpha2': 'LY',
+ 'alpha3': 'LBY',
+ 'numeric': '434'
+ },
+ {
+ 'name': 'Liechtenstein',
+ 'alpha2': 'LI',
+ 'alpha3': 'LIE',
+ 'numeric': '438'
+ },
+ {
+ 'name': 'Lithuania',
+ 'alpha2': 'LT',
+ 'alpha3': 'LTU',
+ 'numeric': '440'
+ },
+ {
+ 'name': 'Luxembourg',
+ 'alpha2': 'LU',
+ 'alpha3': 'LUX',
+ 'numeric': '442'
+ },
+ {
+ 'name': 'Macao',
+ 'alpha2': 'MO',
+ 'alpha3': 'MAC',
+ 'numeric': '446',
+ 'altName': 'Macao, SAR China',
+ 'shortName': 'Macau'
+ },
+ {
+ 'name': 'Macedonia (the former Yugoslav Republic of)',
+ 'alpha2': 'MK',
+ 'alpha3': 'MKD',
+ 'numeric': '807',
+ 'altName': 'Macedonia, Republic of',
+ 'shortName': 'Macedonia'
+ },
+ {
+ 'name': 'Madagascar',
+ 'alpha2': 'MG',
+ 'alpha3': 'MDG',
+ 'numeric': '450'
+ },
+ {
+ 'name': 'Malawi',
+ 'alpha2': 'MW',
+ 'alpha3': 'MWI',
+ 'numeric': '454'
+ },
+ {
+ 'name': 'Malaysia',
+ 'alpha2': 'MY',
+ 'alpha3': 'MYS',
+ 'numeric': '458'
+ },
+ {
+ 'name': 'Maldives',
+ 'alpha2': 'MV',
+ 'alpha3': 'MDV',
+ 'numeric': '462'
+ },
+ {
+ 'name': 'Mali',
+ 'alpha2': 'ML',
+ 'alpha3': 'MLI',
+ 'numeric': '466'
+ },
+ {
+ 'name': 'Malta',
+ 'alpha2': 'MT',
+ 'alpha3': 'MLT',
+ 'numeric': '470'
+ },
+ {
+ 'name': 'Marshall Islands (the)',
+ 'alpha2': 'MH',
+ 'alpha3': 'MHL',
+ 'numeric': '584',
+ 'altName': 'Marshall Islands'
+ },
+ {
+ 'name': 'Martinique',
+ 'alpha2': 'MQ',
+ 'alpha3': 'MTQ',
+ 'numeric': '474'
+ },
+ {
+ 'name': 'Mauritania',
+ 'alpha2': 'MR',
+ 'alpha3': 'MRT',
+ 'numeric': '478'
+ },
+ {
+ 'name': 'Mauritius',
+ 'alpha2': 'MU',
+ 'alpha3': 'MUS',
+ 'numeric': '480'
+ },
+ {
+ 'name': 'Mayotte',
+ 'alpha2': 'YT',
+ 'alpha3': 'MYT',
+ 'numeric': '175'
+ },
+ {
+ 'name': 'Mexico',
+ 'alpha2': 'MX',
+ 'alpha3': 'MEX',
+ 'numeric': '484'
+ },
+ {
+ 'name': 'Micronesia (Federated States of)',
+ 'alpha2': 'FM',
+ 'alpha3': 'FSM',
+ 'numeric': '583',
+ 'altName': 'Micronesia, Federated States of',
+ 'shortName': 'Micronesia'
+ },
+ {
+ 'name': 'Moldova (the Republic of)',
+ 'alpha2': 'MD',
+ 'alpha3': 'MDA',
+ 'numeric': '498',
+ 'altName': 'Moldova'
+ },
+ {
+ 'name': 'Monaco',
+ 'alpha2': 'MC',
+ 'alpha3': 'MCO',
+ 'numeric': '492'
+ },
+ {
+ 'name': 'Mongolia',
+ 'alpha2': 'MN',
+ 'alpha3': 'MNG',
+ 'numeric': '496'
+ },
+ {
+ 'name': 'Montenegro',
+ 'alpha2': 'ME',
+ 'alpha3': 'MNE',
+ 'numeric': '499'
+ },
+ {
+ 'name': 'Montserrat',
+ 'alpha2': 'MS',
+ 'alpha3': 'MSR',
+ 'numeric': '500'
+ },
+ {
+ 'name': 'Morocco',
+ 'alpha2': 'MA',
+ 'alpha3': 'MAR',
+ 'numeric': '504'
+ },
+ {
+ 'name': 'Mozambique',
+ 'alpha2': 'MZ',
+ 'alpha3': 'MOZ',
+ 'numeric': '508'
+ },
+ {
+ 'name': 'Myanmar',
+ 'alpha2': 'MM',
+ 'alpha3': 'MMR',
+ 'numeric': '104'
+ },
+ {
+ 'name': 'Namibia',
+ 'alpha2': 'NA',
+ 'alpha3': 'NAM',
+ 'numeric': '516'
+ },
+ {
+ 'name': 'Nauru',
+ 'alpha2': 'NR',
+ 'alpha3': 'NRU',
+ 'numeric': '520'
+ },
+ {
+ 'name': 'Nepal',
+ 'alpha2': 'NP',
+ 'alpha3': 'NPL',
+ 'numeric': '524'
+ },
+ {
+ 'name': 'Netherlands (the)',
+ 'alpha2': 'NL',
+ 'alpha3': 'NLD',
+ 'numeric': '528',
+ 'altName': 'Netherlands'
+ },
+ {
+ 'name': 'New Caledonia',
+ 'alpha2': 'NC',
+ 'alpha3': 'NCL',
+ 'numeric': '540'
+ },
+ {
+ 'name': 'New Zealand',
+ 'alpha2': 'NZ',
+ 'alpha3': 'NZL',
+ 'numeric': '554'
+ },
+ {
+ 'name': 'Nicaragua',
+ 'alpha2': 'NI',
+ 'alpha3': 'NIC',
+ 'numeric': '558'
+ },
+ {
+ 'name': 'Niger (the)',
+ 'alpha2': 'NE',
+ 'alpha3': 'NER',
+ 'numeric': '562',
+ 'altName': 'Niger'
+ },
+ {
+ 'name': 'Nigeria',
+ 'alpha2': 'NG',
+ 'alpha3': 'NGA',
+ 'numeric': '566'
+ },
+ {
+ 'name': 'Niue',
+ 'alpha2': 'NU',
+ 'alpha3': 'NIU',
+ 'numeric': '570'
+ },
+ {
+ 'name': 'Norfolk Island',
+ 'alpha2': 'NF',
+ 'alpha3': 'NFK',
+ 'numeric': '574'
+ },
+ {
+ 'name': 'Northern Mariana Islands (the)',
+ 'alpha2': 'MP',
+ 'alpha3': 'MNP',
+ 'numeric': '580',
+ 'altName': 'Northern Mariana Islands'
+ },
+ {
+ 'name': 'Norway',
+ 'alpha2': 'NO',
+ 'alpha3': 'NOR',
+ 'numeric': '578'
+ },
+ {
+ 'name': 'Oman',
+ 'alpha2': 'OM',
+ 'alpha3': 'OMN',
+ 'numeric': '512'
+ },
+ {
+ 'name': 'Pakistan',
+ 'alpha2': 'PK',
+ 'alpha3': 'PAK',
+ 'numeric': '586'
+ },
+ {
+ 'name': 'Palau',
+ 'alpha2': 'PW',
+ 'alpha3': 'PLW',
+ 'numeric': '585'
+ },
+ {
+ 'name': 'Palestine, State of',
+ 'alpha2': 'PS',
+ 'alpha3': 'PSE',
+ 'numeric': '275',
+ 'altName': 'Palestinian Territory',
+ 'shortName': 'Palestine'
+ },
+ {
+ 'name': 'Panama',
+ 'alpha2': 'PA',
+ 'alpha3': 'PAN',
+ 'numeric': '591'
+ },
+ {
+ 'name': 'Papua New Guinea',
+ 'alpha2': 'PG',
+ 'alpha3': 'PNG',
+ 'numeric': '598'
+ },
+ {
+ 'name': 'Paraguay',
+ 'alpha2': 'PY',
+ 'alpha3': 'PRY',
+ 'numeric': '600'
+ },
+ {
+ 'name': 'Peru',
+ 'alpha2': 'PE',
+ 'alpha3': 'PER',
+ 'numeric': '604'
+ },
+ {
+ 'name': 'Philippines (the)',
+ 'alpha2': 'PH',
+ 'alpha3': 'PHL',
+ 'numeric': '608',
+ 'altName': 'Philippines'
+ },
+ {
+ 'name': 'Pitcairn',
+ 'alpha2': 'PN',
+ 'alpha3': 'PCN',
+ 'numeric': '612'
+ },
+ {
+ 'name': 'Poland',
+ 'alpha2': 'PL',
+ 'alpha3': 'POL',
+ 'numeric': '616'
+ },
+ {
+ 'name': 'Portugal',
+ 'alpha2': 'PT',
+ 'alpha3': 'PRT',
+ 'numeric': '620'
+ },
+ {
+ 'name': 'Puerto Rico',
+ 'alpha2': 'PR',
+ 'alpha3': 'PRI',
+ 'numeric': '630'
+ },
+ {
+ 'name': 'Qatar',
+ 'alpha2': 'QA',
+ 'alpha3': 'QAT',
+ 'numeric': '634'
+ },
+ {
+ 'name': 'Réunion',
+ 'alpha2': 'RE',
+ 'alpha3': 'REU',
+ 'numeric': '638',
+ 'shortName': 'Reunion'
+ },
+ {
+ 'name': 'Romania',
+ 'alpha2': 'RO',
+ 'alpha3': 'ROU',
+ 'numeric': '642'
+ },
+ {
+ 'name': 'Russian Federation (the)',
+ 'alpha2': 'RU',
+ 'alpha3': 'RUS',
+ 'numeric': '643',
+ 'altName': 'Russian Federation',
+ 'shortName': 'Russia'
+ },
+ {
+ 'name': 'Rwanda',
+ 'alpha2': 'RW',
+ 'alpha3': 'RWA',
+ 'numeric': '646'
+ },
+ {
+ 'name': 'Saint Barthélemy',
+ 'alpha2': 'BL',
+ 'alpha3': 'BLM',
+ 'numeric': '652',
+ 'altName': 'Saint-Barthélemy',
+ 'shortName': 'Saint Barthelemy'
+ },
+ {
+ 'name': 'Saint Helena, Ascension and Tristan da Cunha',
+ 'alpha2': 'SH',
+ 'alpha3': 'SHN',
+ 'numeric': '654',
+ 'altName': 'Saint Helena'
+ },
+ {
+ 'name': 'Saint Kitts and Nevis',
+ 'alpha2': 'KN',
+ 'alpha3': 'KNA',
+ 'numeric': '659'
+ },
+ {
+ 'name': 'Saint Lucia',
+ 'alpha2': 'LC',
+ 'alpha3': 'LCA',
+ 'numeric': '662'
+ },
+ {
+ 'name': 'Saint Martin (French part)',
+ 'alpha2': 'MF',
+ 'alpha3': 'MAF',
+ 'numeric': '663',
+ 'altName': 'Saint-Martin (French part)',
+ 'shortName': 'Saint Martin'
+ },
+ {
+ 'name': 'Saint Pierre and Miquelon',
+ 'alpha2': 'PM',
+ 'alpha3': 'SPM',
+ 'numeric': '666'
+ },
+ {
+ 'name': 'Saint Vincent and the Grenadines',
+ 'alpha2': 'VC',
+ 'alpha3': 'VCT',
+ 'numeric': '670',
+ 'altName': 'Saint Vincent and Grenadines'
+ },
+ {
+ 'name': 'Samoa',
+ 'alpha2': 'WS',
+ 'alpha3': 'WSM',
+ 'numeric': '882'
+ },
+ {
+ 'name': 'San Marino',
+ 'alpha2': 'SM',
+ 'alpha3': 'SMR',
+ 'numeric': '674'
+ },
+ {
+ 'name': 'Sao Tome and Principe',
+ 'alpha2': 'ST',
+ 'alpha3': 'STP',
+ 'numeric': '678'
+ },
+ {
+ 'name': 'Saudi Arabia',
+ 'alpha2': 'SA',
+ 'alpha3': 'SAU',
+ 'numeric': '682'
+ },
+ {
+ 'name': 'Senegal',
+ 'alpha2': 'SN',
+ 'alpha3': 'SEN',
+ 'numeric': '686'
+ },
+ {
+ 'name': 'Serbia',
+ 'alpha2': 'RS',
+ 'alpha3': 'SRB',
+ 'numeric': '688'
+ },
+ {
+ 'name': 'Seychelles',
+ 'alpha2': 'SC',
+ 'alpha3': 'SYC',
+ 'numeric': '690'
+ },
+ {
+ 'name': 'Sierra Leone',
+ 'alpha2': 'SL',
+ 'alpha3': 'SLE',
+ 'numeric': '694'
+ },
+ {
+ 'name': 'Singapore',
+ 'alpha2': 'SG',
+ 'alpha3': 'SGP',
+ 'numeric': '702'
+ },
+ {
+ 'name': 'Sint Maarten (Dutch part)',
+ 'alpha2': 'SX',
+ 'alpha3': 'SXM',
+ 'numeric': '534',
+ 'shortName': 'Sint Maarten'
+ },
+ {
+ 'name': 'Slovakia',
+ 'alpha2': 'SK',
+ 'alpha3': 'SVK',
+ 'numeric': '703'
+ },
+ {
+ 'name': 'Slovenia',
+ 'alpha2': 'SI',
+ 'alpha3': 'SVN',
+ 'numeric': '705'
+ },
+ {
+ 'name': 'Solomon Islands',
+ 'alpha2': 'SB',
+ 'alpha3': 'SLB',
+ 'numeric': '090'
+ },
+ {
+ 'name': 'Somalia',
+ 'alpha2': 'SO',
+ 'alpha3': 'SOM',
+ 'numeric': '706'
+ },
+ {
+ 'name': 'South Africa',
+ 'alpha2': 'ZA',
+ 'alpha3': 'ZAF',
+ 'numeric': '710'
+ },
+ {
+ 'name': 'South Georgia and the South Sandwich Islands',
+ 'alpha2': 'GS',
+ 'alpha3': 'SGS',
+ 'numeric': '239'
+ },
+ {
+ 'name': 'South Sudan',
+ 'alpha2': 'SS',
+ 'alpha3': 'SSD',
+ 'numeric': '728'
+ },
+ {
+ 'name': 'Spain',
+ 'alpha2': 'ES',
+ 'alpha3': 'ESP',
+ 'numeric': '724'
+ },
+ {
+ 'name': 'Sri Lanka',
+ 'alpha2': 'LK',
+ 'alpha3': 'LKA',
+ 'numeric': '144'
+ },
+ {
+ 'name': 'Sudan (the)',
+ 'alpha2': 'SD',
+ 'alpha3': 'SDN',
+ 'numeric': '729',
+ 'altName': 'Sudan'
+ },
+ {
+ 'name': 'Suriname',
+ 'alpha2': 'SR',
+ 'alpha3': 'SUR',
+ 'numeric': '740'
+ },
+ {
+ 'name': 'Svalbard and Jan Mayen',
+ 'alpha2': 'SJ',
+ 'alpha3': 'SJM',
+ 'numeric': '744',
+ 'altName': 'Svalbard and Jan Mayen Islands'
+ },
+ {
+ 'name': 'Swaziland',
+ 'alpha2': 'SZ',
+ 'alpha3': 'SWZ',
+ 'numeric': '748'
+ },
+ {
+ 'name': 'Sweden',
+ 'alpha2': 'SE',
+ 'alpha3': 'SWE',
+ 'numeric': '752'
+ },
+ {
+ 'name': 'Switzerland',
+ 'alpha2': 'CH',
+ 'alpha3': 'CHE',
+ 'numeric': '756'
+ },
+ {
+ 'name': 'Syrian Arab Republic',
+ 'alpha2': 'SY',
+ 'alpha3': 'SYR',
+ 'numeric': '760',
+ 'altName': 'Syrian Arab Republic (Syria)',
+ 'shortName': 'Syria'
+ },
+ {
+ 'name': 'Taiwan (Province of China)',
+ 'alpha2': 'TW',
+ 'alpha3': 'TWN',
+ 'numeric': '158',
+ 'altName': 'Taiwan, Republic of China',
+ 'shortName': 'Taiwan'
+ },
+ {
+ 'name': 'Tajikistan',
+ 'alpha2': 'TJ',
+ 'alpha3': 'TJK',
+ 'numeric': '762'
+ },
+ {
+ 'name': 'Tanzania, United Republic of',
+ 'alpha2': 'TZ',
+ 'alpha3': 'TZA',
+ 'numeric': '834',
+ 'shortName': 'Tanzania'
+ },
+ {
+ 'name': 'Thailand',
+ 'alpha2': 'TH',
+ 'alpha3': 'THA',
+ 'numeric': '764'
+ },
+ {
+ 'name': 'Timor-Leste',
+ 'alpha2': 'TL',
+ 'alpha3': 'TLS',
+ 'numeric': '626',
+ 'shortName': 'East Timor'
+ },
+ {
+ 'name': 'Togo',
+ 'alpha2': 'TG',
+ 'alpha3': 'TGO',
+ 'numeric': '768'
+ },
+ {
+ 'name': 'Tokelau',
+ 'alpha2': 'TK',
+ 'alpha3': 'TKL',
+ 'numeric': '772'
+ },
+ {
+ 'name': 'Tonga',
+ 'alpha2': 'TO',
+ 'alpha3': 'TON',
+ 'numeric': '776'
+ },
+ {
+ 'name': 'Trinidad and Tobago',
+ 'alpha2': 'TT',
+ 'alpha3': 'TTO',
+ 'numeric': '780'
+ },
+ {
+ 'name': 'Tunisia',
+ 'alpha2': 'TN',
+ 'alpha3': 'TUN',
+ 'numeric': '788'
+ },
+ {
+ 'name': 'Turkey',
+ 'alpha2': 'TR',
+ 'alpha3': 'TUR',
+ 'numeric': '792'
+ },
+ {
+ 'name': 'Turkmenistan',
+ 'alpha2': 'TM',
+ 'alpha3': 'TKM',
+ 'numeric': '795'
+ },
+ {
+ 'name': 'Turks and Caicos Islands (the)',
+ 'alpha2': 'TC',
+ 'alpha3': 'TCA',
+ 'numeric': '796',
+ 'altName': 'Turks and Caicos Islands'
+ },
+ {
+ 'name': 'Tuvalu',
+ 'alpha2': 'TV',
+ 'alpha3': 'TUV',
+ 'numeric': '798'
+ },
+ {
+ 'name': 'Uganda',
+ 'alpha2': 'UG',
+ 'alpha3': 'UGA',
+ 'numeric': '800'
+ },
+ {
+ 'name': 'Ukraine',
+ 'alpha2': 'UA',
+ 'alpha3': 'UKR',
+ 'numeric': '804'
+ },
+ {
+ 'name': 'United Arab Emirates (the)',
+ 'alpha2': 'AE',
+ 'alpha3': 'ARE',
+ 'numeric': '784',
+ 'altName': 'United Arab Emirates'
+ },
+ {
+ 'name': 'United Kingdom of Great Britain and Northern Ireland (the)',
+ 'alpha2': 'GB',
+ 'alpha3': 'GBR',
+ 'numeric': '826',
+ 'altName': 'United Kingdom'
+ },
+ {
+ 'name': 'United States Minor Outlying Islands (the)',
+ 'alpha2': 'UM',
+ 'alpha3': 'UMI',
+ 'numeric': '581',
+ 'altName': 'US Minor Outlying Islands'
+ },
+ {
+ 'name': 'United States of America (the)',
+ 'alpha2': 'US',
+ 'alpha3': 'USA',
+ 'numeric': '840',
+ 'altName': 'United States of America',
+ 'shortName': 'United States'
+ },
+ {
+ 'name': 'Uruguay',
+ 'alpha2': 'UY',
+ 'alpha3': 'URY',
+ 'numeric': '858'
+ },
+ {
+ 'name': 'Uzbekistan',
+ 'alpha2': 'UZ',
+ 'alpha3': 'UZB',
+ 'numeric': '860'
+ },
+ {
+ 'name': 'Vanuatu',
+ 'alpha2': 'VU',
+ 'alpha3': 'VUT',
+ 'numeric': '548'
+ },
+ {
+ 'name': 'Venezuela (Bolivarian Republic of)',
+ 'alpha2': 'VE',
+ 'alpha3': 'VEN',
+ 'numeric': '862',
+ 'altName': 'Venezuela (Bolivarian Republic)',
+ 'shortName': 'Venezuela'
+ },
+ {
+ 'name': 'Viet Nam',
+ 'alpha2': 'VN',
+ 'alpha3': 'VNM',
+ 'numeric': '704',
+ 'shortName': 'Vietnam'
+ },
+ {
+ 'name': 'Virgin Islands (British)',
+ 'alpha2': 'VG',
+ 'alpha3': 'VGB',
+ 'numeric': '092',
+ 'altName': 'British Virgin Islands'
+ },
+ {
+ 'name': 'Virgin Islands (U.S.)',
+ 'alpha2': 'VI',
+ 'alpha3': 'VIR',
+ 'numeric': '850',
+ 'altName': 'Virgin Islands, US',
+ 'shortName': 'U.S. Virgin Islands'
+ },
+ {
+ 'name': 'Wallis and Futuna',
+ 'alpha2': 'WF',
+ 'alpha3': 'WLF',
+ 'numeric': '876',
+ 'altName': 'Wallis and Futuna Islands'
+ },
+ {
+ 'name': 'Western Sahara*',
+ 'alpha2': 'EH',
+ 'alpha3': 'ESH',
+ 'numeric': '732',
+ 'altName': 'Western Sahara'
+ },
+ {
+ 'name': 'Yemen',
+ 'alpha2': 'YE',
+ 'alpha3': 'YEM',
+ 'numeric': '887'
+ },
+ {
+ 'name': 'Zambia',
+ 'alpha2': 'ZM',
+ 'alpha3': 'ZMB',
+ 'numeric': '894'
+ },
+ {
+ 'name': 'Zimbabwe',
+ 'alpha2': 'ZW',
+ 'alpha3': 'ZWE',
+ 'numeric': '716'
+ }
+];
diff --git a/packages/nodes-base/nodes/HelpScout/CustomerDescription.ts b/packages/nodes-base/nodes/HelpScout/CustomerDescription.ts
new file mode 100644
index 000000000..584108cf7
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/CustomerDescription.ts
@@ -0,0 +1,811 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const customerOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a new customer',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a customer',
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all customers',
+ },
+ {
+ name: 'Properties',
+ value: 'properties',
+ description: 'Get customer property definitions',
+ },
+ {
+ name: 'Update',
+ value: 'update',
+ description: 'Update a customer',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const customerFields = [
+/* -------------------------------------------------------------------------- */
+/* customer:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Resolve Data',
+ name: 'resolveData',
+ type: 'boolean',
+ default: true,
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ description: 'By default the response only contain the ID to resource
. If this option gets activated it
will resolve the data automatically.',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Age',
+ name: 'age',
+ type: 'number',
+ typeOptions: {
+ minValue: 1,
+ },
+ default: 1,
+ description: `Customer’s age`,
+ },
+ {
+ displayName: 'First Name',
+ name: 'firstName',
+ type: 'string',
+ default: '',
+ description: `First name of the customer. When defined it must be between 1 and 40 characters.`,
+ },
+ {
+ displayName: 'Gender',
+ name: 'gender',
+ type: 'options',
+ options: [
+ {
+ name: 'Female',
+ value: 'female',
+ },
+ {
+ name: 'Male',
+ value: 'male',
+ },
+ {
+ name: 'Unknown',
+ value: 'unknown',
+ },
+ ],
+ default: '',
+ description: 'Gender of this customer.',
+ },
+ {
+ displayName: 'Job Title',
+ name: 'jobTitle',
+ type: 'string',
+ default: '',
+ description: 'Job title. Max length 60 characters.',
+ },
+ {
+ displayName: 'Last Name',
+ name: 'lastName',
+ type: 'string',
+ default: '',
+ description: 'Last name of the customer',
+ },
+ {
+ displayName: 'Location',
+ name: 'location',
+ type: 'string',
+ default: '',
+ description: 'Location of the customer.',
+ },
+ {
+ displayName: 'Notes',
+ name: 'background',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Notes`,
+ },
+ {
+ displayName: 'Organization',
+ name: 'organization',
+ type: 'string',
+ default: '',
+ description: 'Organization',
+ },
+ {
+ displayName: 'Photo Url',
+ name: 'photoUrl',
+ type: 'string',
+ default: '',
+ description: 'URL of the customer’s photo',
+ },
+ ]
+ },
+ {
+ displayName: 'Address',
+ name: 'addressUi',
+ placeholder: 'Add Address',
+ type: 'fixedCollection',
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Address',
+ name: 'addressValue',
+ values: [
+ {
+ displayName: 'Line 1',
+ name: 'line1',
+ type: 'string',
+ default: '',
+ description: 'line1',
+ },
+ {
+ displayName: 'Line 2',
+ name: 'line2',
+ type: 'string',
+ default: '',
+ description: 'line2',
+ },
+ {
+ displayName: 'City',
+ name: 'city',
+ type: 'string',
+ default: '',
+ description: 'City',
+ },
+ {
+ displayName: 'State',
+ name: 'state',
+ type: 'string',
+ default: '',
+ description: 'State',
+ },
+ {
+ displayName: 'Country',
+ name: 'country',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCountriesCodes',
+ },
+ default: '',
+ description: 'Country',
+ },
+ {
+ displayName: 'Postal Code',
+ name: 'postalCode',
+ type: 'string',
+ default: '',
+ description: 'Postal code',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ displayName: 'Chat Handles',
+ name: 'chatsUi',
+ placeholder: 'Add Chat Handle',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Chat Handle',
+ name: 'chatsValues',
+ values: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ options: [
+ {
+ name: 'AIM',
+ value: 'aim',
+ },
+ {
+ name: 'Google Talk',
+ value: 'gtalk',
+ },
+ {
+ name: 'ICQ',
+ value: 'icq',
+ },
+ {
+ name: 'MSN',
+ value: 'msn',
+ },
+ {
+ name: 'Other',
+ value: 'other',
+ },
+ {
+ name: 'QQ',
+ value: 'qq',
+ },
+ {
+ name: 'Skype',
+ value: 'skype',
+ },
+ {
+ name: 'XMPP',
+ value: 'xmpp',
+ },
+ {
+ name: 'Yahoo',
+ value: 'yahoo',
+ },
+ ],
+ description: 'Chat type',
+ default: '',
+ },
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Chat handle',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ displayName: 'Emails',
+ name: 'emailsUi',
+ placeholder: 'Add Email',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Email',
+ name: 'emailsValues',
+ values: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ options: [
+ {
+ name: 'Home',
+ value: 'home',
+ },
+ {
+ name: 'Other',
+ value: 'other',
+ },
+ {
+ name: 'Work',
+ value: 'work',
+ },
+ ],
+ description: 'Location for this email address',
+ default: '',
+ },
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Email',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ displayName: 'Phones',
+ name: 'phonesUi',
+ placeholder: 'Add Phone',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Email',
+ name: 'phonesValues',
+ values: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ options: [
+ {
+ name: 'Fax',
+ value: 'fax',
+ },
+ {
+ name: 'Home',
+ value: 'home',
+ },
+ {
+ name: 'Other',
+ value: 'other',
+ },
+ {
+ name: 'Pager',
+ value: 'pager',
+ },
+ {
+ name: 'Work',
+ value: 'work',
+ },
+ ],
+ description: 'Location for this phone',
+ default: '',
+ },
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Phone',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ displayName: 'Social Profiles',
+ name: 'socialProfilesUi',
+ placeholder: 'Add Social Profile',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Social Profile',
+ name: 'socialProfilesValues',
+ values: [
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ options: [
+ {
+ name: 'About Me',
+ value: 'aboutMe',
+ },
+ {
+ name: 'Facebook',
+ value: 'facebook',
+ },
+ {
+ name: 'Flickr',
+ value: 'flickr',
+ },
+ {
+ name: 'Forsquare',
+ value: 'forsquare',
+ },
+ {
+ name: 'Google',
+ value: 'google',
+ },
+ {
+ name: 'Google Plus',
+ value: 'googleplus',
+ },
+ {
+ name: 'Linkedin',
+ value: 'linkedin',
+ },
+ {
+ name: 'Other',
+ value: 'other',
+ },
+ {
+ name: 'Quora',
+ value: 'quora',
+ },
+ {
+ name: 'Tungleme',
+ value: 'tungleme',
+ },
+ {
+ name: 'Twitter',
+ value: 'twitter',
+ },
+ {
+ name: 'Youtube',
+ value: 'youtube',
+ },
+ ],
+ description: 'Type of social profile',
+ default: '',
+ },
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Social Profile handle (url for example)',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ displayName: 'Websites',
+ name: 'websitesUi',
+ placeholder: 'Add Website',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ default: {},
+ options: [
+ {
+ displayName: 'Website',
+ name: 'websitesValues',
+ values: [
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Website URL',
+ },
+ ],
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* customer:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Option',
+ default: {},
+ displayOptions: {
+ show: {
+ resource: [
+ 'customer',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'First Name',
+ name: 'firstName',
+ type: 'string',
+ default: '',
+ description: 'Filters customers by first name',
+ },
+ {
+ displayName: 'Last Name',
+ name: 'lastName',
+ type: 'string',
+ default: '',
+ description: 'Filters customers by last name',
+ },
+ {
+ displayName: 'Mailbox ID',
+ name: 'mailbox',
+ type: 'string',
+ default: '',
+ description: 'Filters customers from a specific mailbox',
+ },
+ {
+ displayName: 'Modified Since',
+ name: 'modifiedSince',
+ type: 'dateTime',
+ default: '',
+ description: 'Returns only customers that were modified after this date',
+ },
+ {
+ displayName: 'Sort Field',
+ name: 'sortField',
+ type: 'options',
+ options: [
+ {
+ name: 'Score',
+ value: 'score',
+ },
+ {
+ name: 'First Name',
+ value: 'firstName',
+ },
+ {
+ name: 'Last Name',
+ value: 'lastName',
+ },
+ {
+ name: 'Modified At',
+ value: 'modifiedAt',
+ },
+ ],
+ default: 'score',
+ description: 'Sorts the result by specified field',
+ },
+ {
+ displayName: 'Sort Order',
+ name: 'sortOrder',
+ type: 'options',
+ options: [
+ {
+ name: 'ASC',
+ value: 'asc',
+ },
+ {
+ name: 'Desc',
+ value: 'desc',
+ },
+ ],
+ default: 'desc',
+ },
+ {
+ displayName: 'Query',
+ name: 'query',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Advanced search Examples'
+ },
+ ],
+ },
+/* -------------------------------------------------------------------------- */
+/* customer:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Customer ID',
+ name: 'customerId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'customer',
+ ],
+ operation: [
+ 'get',
+ ],
+ },
+ },
+ description: 'Customer ID',
+ },
+/* -------------------------------------------------------------------------- */
+/* customer:update */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Customer ID',
+ name: 'customerId',
+ type: 'string',
+ default: '',
+ displayOptions: {
+ show: {
+ operation: [
+ 'update',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ description: 'Customer ID',
+ },
+ {
+ displayName: 'Update Fields',
+ name: 'updateFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ operation: [
+ 'update',
+ ],
+ resource: [
+ 'customer',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Age',
+ name: 'age',
+ type: 'number',
+ typeOptions: {
+ minValue: 1,
+ },
+ default: 1,
+ description: `Customer’s age`,
+ },
+ {
+ displayName: 'First Name',
+ name: 'firstName',
+ type: 'string',
+ default: '',
+ description: `First name of the customer. When defined it must be between 1 and 40 characters.`,
+ },
+ {
+ displayName: 'Gender',
+ name: 'gender',
+ type: 'options',
+ options: [
+ {
+ name: 'Female',
+ value: 'female',
+ },
+ {
+ name: 'Male',
+ value: 'male',
+ },
+ {
+ name: 'Unknown',
+ value: 'unknown',
+ },
+ ],
+ default: '',
+ description: 'Gender of this customer.',
+ },
+ {
+ displayName: 'Job Title',
+ name: 'jobTitle',
+ type: 'string',
+ default: '',
+ description: 'Job title. Max length 60 characters.',
+ },
+ {
+ displayName: 'Last Name',
+ name: 'lastName',
+ type: 'string',
+ default: '',
+ description: 'Last name of the customer',
+ },
+ {
+ displayName: 'Location',
+ name: 'location',
+ type: 'string',
+ default: '',
+ description: 'Location of the customer.',
+ },
+ {
+ displayName: 'Notes',
+ name: 'background',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Notes`,
+ },
+ {
+ displayName: 'Organization',
+ name: 'organization',
+ type: 'string',
+ default: '',
+ description: 'Organization',
+ },
+ {
+ displayName: 'Photo Url',
+ name: 'photoUrl',
+ type: 'string',
+ default: '',
+ description: 'URL of the customer’s photo',
+ },
+ ],
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/HelpScout/CustomerInterface.ts b/packages/nodes-base/nodes/HelpScout/CustomerInterface.ts
new file mode 100644
index 000000000..fe50a7cb3
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/CustomerInterface.ts
@@ -0,0 +1,20 @@
+import { IDataObject } from 'n8n-workflow';
+
+export interface ICustomer {
+ address?: IDataObject;
+ age?: string;
+ background?: string;
+ chats?: IDataObject[];
+ emails?: IDataObject[];
+ firstName?: string;
+ gender?: string;
+ jobTitle?: string;
+ lastName?: string;
+ location?: string;
+ organization?: string;
+ phones?: IDataObject[];
+ photoUrl?: string;
+ properties?: IDataObject;
+ socialProfiles?: IDataObject[];
+ websites?: IDataObject[];
+}
diff --git a/packages/nodes-base/nodes/HelpScout/GenericFunctions.ts b/packages/nodes-base/nodes/HelpScout/GenericFunctions.ts
new file mode 100644
index 000000000..fb04b669e
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/GenericFunctions.ts
@@ -0,0 +1,70 @@
+import { OptionsWithUri } from 'request';
+import {
+ IHookFunctions,
+ IExecuteFunctions,
+ IExecuteSingleFunctions,
+ ILoadOptionsFunctions,
+} from 'n8n-core';
+import {
+ IDataObject,
+} from 'n8n-workflow';
+
+import {
+ get,
+} from 'lodash';
+
+export async function helpscoutApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any
+ let options: OptionsWithUri = {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ method,
+ body,
+ qs,
+ uri: uri || `https://api.helpscout.net${resource}`,
+ json: true
+ };
+ try {
+ if (Object.keys(option).length !== 0) {
+ options = Object.assign({}, options, option);
+ }
+ if (Object.keys(body).length === 0) {
+ delete options.body;
+ }
+ //@ts-ignore
+ return await this.helpers.requestOAuth.call(this, 'helpScoutOAuth2Api', options);
+ } catch (error) {
+ if (error.response && error.response.body
+ && error.response.body._embedded
+ && error.response.body._embedded.errors) {
+ // Try to return the error prettier
+ //@ts-ignore
+ throw new Error(`HelpScout error response [${error.statusCode}]: ${error.response.body.message} - ${error.response.body._embedded.errors.map(error => {
+ return `${error.path} ${error.message}`;
+ }).join('-')}`);
+ }
+
+ throw new Error(`HelpScout error response [${error.statusCode}]: ${error.message}`);
+ }
+}
+
+export async function helpscoutApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any
+
+ const returnData: IDataObject[] = [];
+
+ let responseData;
+ query.size = 50;
+ let uri;
+
+ do {
+ responseData = await helpscoutApiRequest.call(this, method, endpoint, body, query, uri);
+ uri = get(responseData, '_links.next.href');
+ returnData.push.apply(returnData, get(responseData, propertyName));
+ } while (
+ responseData['_links'] !== undefined &&
+ responseData['_links'].next !== undefined &&
+ responseData['_links'].next.href !== undefined
+ );
+
+ return returnData;
+}
diff --git a/packages/nodes-base/nodes/HelpScout/HelpScout.node.ts b/packages/nodes-base/nodes/HelpScout/HelpScout.node.ts
new file mode 100644
index 000000000..190b276cb
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/HelpScout.node.ts
@@ -0,0 +1,411 @@
+import {
+ IExecuteFunctions,
+} from 'n8n-core';
+
+import {
+ IBinaryKeyData,
+ IDataObject,
+ ILoadOptionsFunctions,
+ INodeExecutionData,
+ INodePropertyOptions,
+ INodeTypeDescription,
+ INodeType,
+} from 'n8n-workflow';
+
+import {
+ countriesCodes
+} from './CountriesCodes';
+
+import {
+ conversationFields,
+ conversationOperations,
+} from './ConversationDescription';
+
+import {
+ customerFields,
+ customerOperations,
+} from './CustomerDescription';
+
+import {
+ ICustomer,
+} from './CustomerInterface';
+
+import {
+ IConversation,
+} from './ConversationInterface';
+
+import {
+ helpscoutApiRequest,
+ helpscoutApiRequestAllItems,
+} from './GenericFunctions';
+
+import {
+ mailboxFields,
+ mailboxOperations,
+} from './MailboxDescription';
+
+import {
+ threadFields,
+ threadOperations,
+} from './ThreadDescription';
+
+import {
+ IAttachment,
+ IThread,
+} from './ThreadInterface';
+
+
+export class HelpScout implements INodeType {
+ description: INodeTypeDescription = {
+ displayName: 'HelpScout',
+ name: 'helpScout',
+ icon: 'file:helpScout.png',
+ group: ['input'],
+ version: 1,
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
+ description: 'Consume Help Scout API.',
+ defaults: {
+ name: 'HelpScout',
+ color: '#1392ee',
+ },
+ inputs: ['main'],
+ outputs: ['main'],
+ credentials: [
+ {
+ name: 'helpScoutOAuth2Api',
+ required: true,
+ },
+ ],
+ properties: [
+ {
+ displayName: 'Resource',
+ name: 'resource',
+ type: 'options',
+ options: [
+ {
+ name: 'Conversation',
+ value: 'conversation',
+ },
+ {
+ name: 'Customer',
+ value: 'customer',
+ },
+ {
+ name: 'Mailbox',
+ value: 'mailbox',
+ },
+ {
+ name: 'Thread',
+ value: 'thread',
+ },
+ ],
+ default: 'conversation',
+ description: 'The resource to operate on.',
+ },
+ ...conversationOperations,
+ ...conversationFields,
+ ...customerOperations,
+ ...customerFields,
+ ...mailboxOperations,
+ ...mailboxFields,
+ ...threadOperations,
+ ...threadFields,
+ ],
+ };
+
+ methods = {
+ loadOptions: {
+ // Get all the countries codes to display them to user so that he can
+ // select them easily
+ async getCountriesCodes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ for (const countryCode of countriesCodes) {
+ const countryCodeName = `${countryCode.name} - ${countryCode.alpha2}`;
+ const countryCodeId = countryCode.alpha2;
+ returnData.push({
+ name: countryCodeName,
+ value: countryCodeId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the tags to display them to user so that he can
+ // select them easily
+ async getTags(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const tags = await helpscoutApiRequestAllItems.call(this, '_embedded.tags', 'GET', '/v2/tags');
+ for (const tag of tags) {
+ const tagName = tag.name;
+ const tagId = tag.id;
+ returnData.push({
+ name: tagName,
+ value: tagId,
+ });
+ }
+ return returnData;
+ },
+ // Get all the mailboxes to display them to user so that he can
+ // select them easily
+ async getMailboxes(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const mailboxes = await helpscoutApiRequestAllItems.call(this, '_embedded.mailboxes', 'GET', '/v2/mailboxes');
+ for (const mailbox of mailboxes) {
+ const mailboxName = mailbox.name;
+ const mailboxId = mailbox.id;
+ returnData.push({
+ name: mailboxName,
+ value: mailboxId,
+ });
+ }
+ return returnData;
+ },
+ },
+ };
+
+ async execute(this: IExecuteFunctions): Promise {
+ const items = this.getInputData();
+ const returnData: IDataObject[] = [];
+ const length = items.length as unknown as number;
+ const qs: IDataObject = {};
+ let responseData;
+ const resource = this.getNodeParameter('resource', 0) as string;
+ const operation = this.getNodeParameter('operation', 0) as string;
+ for (let i = 0; i < length; i++) {
+ if (resource === 'conversation') {
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/create
+ if (operation === 'create') {
+ const mailboxId = this.getNodeParameter('mailboxId', i) as number;
+ const status = this.getNodeParameter('status', i) as string;
+ const subject = this.getNodeParameter('subject', i) as string;
+ const type = this.getNodeParameter('type', i) as string;
+ const resolveData = this.getNodeParameter('resolveData', i) as boolean;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const threads = (this.getNodeParameter('threadsUi', i) as IDataObject).threadsValues as IDataObject[];
+ const body: IConversation = {
+ mailboxId,
+ status,
+ subject,
+ type,
+ };
+ Object.assign(body, additionalFields);
+ if (additionalFields.customerId) {
+ body.customer = {
+ id: additionalFields.customerId,
+ };
+ //@ts-ignore
+ delete body.customerId;
+ }
+ if (additionalFields.customerEmail) {
+ body.customer = {
+ email: additionalFields.customerEmail,
+ };
+ //@ts-ignore
+ delete body.customerEmail;
+ }
+ if (body.customer === undefined) {
+ throw new Error('Either customer email or customer ID must be set');
+ }
+ if (threads) {
+ for (let i = 0; i < threads.length; i++) {
+ if (threads[i].type === '' || threads[i].text === '') {
+ throw new Error('Chat Threads cannot be empty');
+ }
+ if (threads[i].type !== 'note') {
+ threads[i].customer = body.customer;
+ }
+ }
+ body.threads = threads;
+ }
+ responseData = await helpscoutApiRequest.call(this, 'POST', '/v2/conversations', body, qs, undefined, { resolveWithFullResponse: true });
+ const id = responseData.headers['resource-id'];
+ const uri = responseData.headers.location;
+ if (resolveData) {
+ responseData = await helpscoutApiRequest.call(this, 'GET', '', {}, {}, uri);
+ } else {
+ responseData = {
+ id,
+ uri,
+ };
+ }
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/delete
+ if (operation === 'delete') {
+ const conversationId = this.getNodeParameter('conversationId', i) as string;
+ responseData = await helpscoutApiRequest.call(this, 'DELETE', `/v2/conversations/${conversationId}`);
+ responseData = { success: true };
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/get
+ if (operation === 'get') {
+ const conversationId = this.getNodeParameter('conversationId', i) as string;
+ responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/conversations/${conversationId}`);
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/list
+ if (operation === 'getAll') {
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ Object.assign(qs, options);
+ responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.conversations', 'GET', '/v2/conversations', {}, qs);
+ }
+ }
+ if (resource === 'customer') {
+ //https://developer.helpscout.com/mailbox-api/endpoints/customers/create
+ if (operation === 'create') {
+ const resolveData = this.getNodeParameter('resolveData', i) as boolean;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const chats = (this.getNodeParameter('chatsUi', i) as IDataObject).chatsValues as IDataObject[];
+ const address = (this.getNodeParameter('addressUi', i) as IDataObject).addressValue as IDataObject;
+ const emails = (this.getNodeParameter('emailsUi', i) as IDataObject).emailsValues as IDataObject[];
+ const phones = (this.getNodeParameter('phonesUi', i) as IDataObject).phonesValues as IDataObject[];
+ const socialProfiles = (this.getNodeParameter('socialProfilesUi', i) as IDataObject).socialProfilesValues as IDataObject[];
+ const websites = (this.getNodeParameter('websitesUi', i) as IDataObject).websitesValues as IDataObject[];
+ let body: ICustomer = {};
+ body = Object.assign({}, additionalFields);
+ if (body.age) {
+ body.age = body.age.toString();
+ }
+ if (chats) {
+ body.chats = chats;
+ }
+ if (address) {
+ body.address = address;
+ body.address.lines = [address.line1, address.line2];
+ }
+ if (emails) {
+ body.emails = emails;
+ }
+ if (phones) {
+ body.phones = phones;
+ }
+ if (socialProfiles) {
+ body.socialProfiles = socialProfiles;
+ }
+ if (websites) {
+ body.websites = websites;
+ }
+ if (Object.keys(body).length === 0) {
+ throw new Error('You have to set at least one field');
+ }
+ responseData = await helpscoutApiRequest.call(this, 'POST', '/v2/customers', body, qs, undefined, { resolveWithFullResponse: true });
+ const id = responseData.headers['resource-id'];
+ const uri = responseData.headers.location;
+ if (resolveData) {
+ responseData = await helpscoutApiRequest.call(this, 'GET', '', {}, {}, uri);
+ } else {
+ responseData = {
+ id,
+ uri,
+ };
+ }
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/customer_properties/list
+ if (operation === 'properties') {
+ responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.customer-properties', 'GET', '/v2/customer-properties', {}, qs);
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/customers/get
+ if (operation === 'get') {
+ const customerId = this.getNodeParameter('customerId', i) as string;
+ responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/customers/${customerId}`);
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/customers/list
+ if (operation === 'getAll') {
+ const options = this.getNodeParameter('options', i) as IDataObject;
+ Object.assign(qs, options);
+ responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.customers', 'GET', '/v2/customers', {}, qs);
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/customers/overwrite/
+ if (operation === 'update') {
+ const customerId = this.getNodeParameter('customerId', i) as string;
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+ let body: ICustomer = {};
+ body = Object.assign({}, updateFields);
+ if (body.age) {
+ body.age = body.age.toString();
+ }
+ if (Object.keys(body).length === 0) {
+ throw new Error('You have to set at least one field');
+ }
+ responseData = await helpscoutApiRequest.call(this, 'PUT', `/v2/customers/${customerId}`, body, qs, undefined, { resolveWithFullResponse: true });
+ responseData = { success: true };
+ }
+ }
+ if (resource === 'mailbox') {
+ //https://developer.helpscout.com/mailbox-api/endpoints/mailboxes/get
+ if (operation === 'get') {
+ const mailboxId = this.getNodeParameter('mailboxId', i) as string;
+ responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/mailboxes/${mailboxId}`, {}, qs);
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/mailboxes/list
+ if (operation === 'getAll') {
+ responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.mailboxes', 'GET', '/v2/mailboxes', {}, qs);
+ }
+ }
+ if (resource === 'thread') {
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/chat
+ if (operation === 'create') {
+ const conversationId = this.getNodeParameter('conversationId', i) as string;
+ const type = this.getNodeParameter('type', i) as string;
+ const text = this.getNodeParameter('text', i) as string;
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+ const attachments = this.getNodeParameter('attachmentsUi', i) as IDataObject;
+ const body: IThread = {
+ text,
+ attachments: [],
+ };
+ Object.assign(body, additionalFields);
+ if (additionalFields.customerId) {
+ body.customer = {
+ id: additionalFields.customerId,
+ };
+ //@ts-ignore
+ delete body.customerId;
+ }
+ if (additionalFields.customerEmail) {
+ body.customer = {
+ email: additionalFields.customerEmail,
+ };
+ //@ts-ignore
+ delete body.customerEmail;
+ }
+ if (body.customer === undefined) {
+ throw new Error('Either customer email or customer ID must be set');
+ }
+ if (attachments) {
+ if (attachments.attachmentsValues
+ && (attachments.attachmentsValues as IDataObject[]).length !== 0) {
+ body.attachments?.push.apply(body.attachments, attachments.attachmentsValues as IAttachment[]);
+ }
+ if (attachments.attachmentsBinary
+ && (attachments.attachmentsBinary as IDataObject[]).length !== 0
+ && items[i].binary) {
+ const mapFunction = (value: IDataObject): IAttachment => {
+ const binaryProperty = (items[i].binary as IBinaryKeyData)[value.property as string];
+ if (binaryProperty) {
+ return {
+ fileName: binaryProperty.fileName || 'unknown',
+ data: binaryProperty.data,
+ mimeType: binaryProperty.mimeType,
+ };
+ } else {
+ throw new Error(`Binary property ${value.property} does not exist on input`);
+ }
+ };
+ body.attachments?.push.apply(body.attachments, (attachments.attachmentsBinary as IDataObject[]).map(mapFunction) as IAttachment[]);
+ }
+ }
+ responseData = await helpscoutApiRequest.call(this, 'POST', `/v2/conversations/${conversationId}/chats`, body);
+ responseData = { success: true };
+ }
+ //https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/list
+ if (operation === 'getAll') {
+ const conversationId = this.getNodeParameter('conversationId', i) as string;
+ responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.threads', 'GET', `/v2/conversations/${conversationId}/threads`);
+ }
+ }
+ if (Array.isArray(responseData)) {
+ returnData.push.apply(returnData, responseData as IDataObject[]);
+ } else if (responseData !== undefined) {
+ returnData.push(responseData as IDataObject);
+ }
+ }
+ return [this.helpers.returnJsonArray(returnData)];
+ }
+}
diff --git a/packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts b/packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts
new file mode 100644
index 000000000..63592aa14
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts
@@ -0,0 +1,203 @@
+import {
+ IHookFunctions,
+ IWebhookFunctions,
+} from 'n8n-core';
+
+import {
+ IDataObject,
+ INodeType,
+ INodeTypeDescription,
+ IWebhookResponseData,
+} from 'n8n-workflow';
+
+import {
+ helpscoutApiRequest,
+ helpscoutApiRequestAllItems,
+} from './GenericFunctions';
+
+import { createHmac } from 'crypto';
+
+export class HelpScoutTrigger implements INodeType {
+ description: INodeTypeDescription = {
+ displayName: 'HelpScout Trigger',
+ name: 'helpScoutTrigger',
+ icon: 'file:helpScout.png',
+ group: ['trigger'],
+ version: 1,
+ description: 'Starts the workflow when HelpScout events occure.',
+ defaults: {
+ name: 'HelpScout Trigger',
+ color: '#1392ee',
+ },
+ inputs: [],
+ outputs: ['main'],
+ credentials: [
+ {
+ name: 'helpScoutOAuth2Api',
+ required: true,
+ },
+ ],
+ webhooks: [
+ {
+ name: 'default',
+ httpMethod: 'POST',
+ responseMode: 'onReceived',
+ path: 'webhook',
+ },
+ ],
+ properties: [
+ {
+ displayName: 'Events',
+ name: 'events',
+ type: 'multiOptions',
+ options: [
+
+ {
+ name: 'Conversation - Assigned',
+ value: 'convo.assigned',
+ },
+ {
+ name: 'Conversation - Created',
+ value: 'convo.created',
+ },
+ {
+ name: 'Conversation - Deleted',
+ value: 'convo.deleted',
+ },
+ {
+ name: 'Conversation - Merged',
+ value: 'convo.merged',
+ },
+ {
+ name: 'Conversation - Moved',
+ value: 'convo.moved',
+ },
+ {
+ name: 'Conversation - Status',
+ value: 'convo.status',
+ },
+ {
+ name: 'Conversation - Tags',
+ value: 'convo.tags',
+ },
+ {
+ name: 'Conversation Agent Reply - Created',
+ value: 'convo.agent.reply.created',
+ },
+ {
+ name: 'Conversation Customer Reply - Created',
+ value: 'convo.customer.reply.created',
+ },
+ {
+ name: 'Conversation Note - Created',
+ value: 'convo.note.created',
+ },
+ {
+ name: 'Customer - Created',
+ value: 'customer.created',
+ },
+ {
+ name: 'Rating - Received',
+ value: 'satisfaction.ratings',
+ },
+ ],
+ default: [],
+ required: true,
+ },
+ ],
+
+ };
+
+ // @ts-ignore (because of request)
+ webhookMethods = {
+ default: {
+ async checkExists(this: IHookFunctions): Promise {
+ const webhookUrl = this.getNodeWebhookUrl('default');
+ const webhookData = this.getWorkflowStaticData('node');
+ const events = this.getNodeParameter('events') as string;
+
+ // Check all the webhooks which exist already if it is identical to the
+ // one that is supposed to get created.
+ const endpoint = '/v2/webhooks';
+ const data = await helpscoutApiRequestAllItems.call(this, '_embedded.webhooks', 'GET', endpoint, {});
+
+ for (const webhook of data) {
+ if (webhook.url === webhookUrl) {
+ for (const event of events) {
+ if (!webhook.events.includes(event)
+ && webhook.state === 'enabled') {
+ return false;
+ }
+ }
+ }
+ // Set webhook-id to be sure that it can be deleted
+ webhookData.webhookId = webhook.id as string;
+ return true;
+ }
+ return false;
+ },
+ async create(this: IHookFunctions): Promise {
+ const webhookData = this.getWorkflowStaticData('node');
+ const webhookUrl = this.getNodeWebhookUrl('default');
+ const events = this.getNodeParameter('events') as string;
+
+ const endpoint = '/v2/webhooks';
+
+ const body = {
+ url: webhookUrl,
+ events,
+ secret: Math.random().toString(36).substring(2, 15),
+ };
+
+ const responseData = await helpscoutApiRequest.call(this, 'POST', endpoint, body, {}, undefined, { resolveWithFullResponse: true });
+
+ if (responseData.headers['resource-id'] === undefined) {
+ // Required data is missing so was not successful
+ return false;
+ }
+
+ webhookData.webhookId = responseData.headers['resource-id'] as string;
+ webhookData.secret = body.secret;
+ return true;
+ },
+ async delete(this: IHookFunctions): Promise {
+ const webhookData = this.getWorkflowStaticData('node');
+ if (webhookData.webhookId !== undefined) {
+
+ const endpoint = `/v2/webhooks/${webhookData.webhookId}`;
+ try {
+ await helpscoutApiRequest.call(this, 'DELETE', endpoint);
+ } catch (e) {
+ return false;
+ }
+
+ // Remove from the static workflow data so that it is clear
+ // that no webhooks are registred anymore
+ delete webhookData.webhookId;
+ delete webhookData.secret;
+ }
+ return true;
+ },
+ },
+ };
+
+ async webhook(this: IWebhookFunctions): Promise {
+ const req = this.getRequestObject();
+ const bodyData = this.getBodyData();
+ const headerData = this.getHeaderData() as IDataObject;
+ const webhookData = this.getWorkflowStaticData('node');
+ if (headerData['x-helpscout-signature'] === undefined) {
+ return {};
+ }
+ //@ts-ignore
+ const computedSignature = createHmac('sha1', webhookData.secret as string).update(req.rawBody).digest('base64');
+ if (headerData['x-helpscout-signature'] !== computedSignature) {
+ return {};
+ }
+ return {
+ workflowData: [
+ this.helpers.returnJsonArray(bodyData),
+ ],
+ };
+ }
+}
diff --git a/packages/nodes-base/nodes/HelpScout/MailboxDescription.ts b/packages/nodes-base/nodes/HelpScout/MailboxDescription.ts
new file mode 100644
index 000000000..27063c05e
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/MailboxDescription.ts
@@ -0,0 +1,54 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const mailboxOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'mailbox',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get data of a mailbox',
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all mailboxes',
+ },
+ ],
+ default: 'get',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const mailboxFields = [
+
+/* -------------------------------------------------------------------------- */
+/* mailbox:get */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Mailbox ID',
+ name: 'mailboxId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'mailbox',
+ ],
+ operation: [
+ 'get',
+ ],
+ },
+ },
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/HelpScout/ThreadDescription.ts b/packages/nodes-base/nodes/HelpScout/ThreadDescription.ts
new file mode 100644
index 000000000..4374e6845
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/ThreadDescription.ts
@@ -0,0 +1,257 @@
+import { INodeProperties } from 'n8n-workflow';
+
+export const threadOperations = [
+ {
+ displayName: 'Operation',
+ name: 'operation',
+ type: 'options',
+ displayOptions: {
+ show: {
+ resource: [
+ 'thread',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Create',
+ value: 'create',
+ description: 'Create a new chat thread',
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all chat threads',
+ },
+ ],
+ default: 'create',
+ description: 'The operation to perform.',
+ },
+] as INodeProperties[];
+
+export const threadFields = [
+/* -------------------------------------------------------------------------- */
+/* thread:create */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Conversation ID',
+ name: 'conversationId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'thread',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ description: 'conversation ID',
+ },
+ {
+ displayName: 'Type',
+ name: 'type',
+ type: 'options',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'thread',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'Chat',
+ value: 'chat'
+ },
+ {
+ name: 'Customer',
+ value: 'customer'
+ },
+ {
+ name: 'Note',
+ value: 'note'
+ },
+ {
+ name: 'Phone',
+ value: 'phone'
+ },
+ {
+ name: 'Reply',
+ value: 'reply'
+ },
+ ],
+ default: '',
+ },
+ {
+ displayName: 'Text',
+ name: 'text',
+ type: 'string',
+ default: '',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'thread',
+ ],
+ operation: [
+ 'create',
+ ],
+ },
+ },
+ description: 'The chat text',
+ },
+ {
+ displayName: 'Additional Fields',
+ name: 'additionalFields',
+ type: 'collection',
+ placeholder: 'Add Field',
+ default: {},
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'thread',
+ ],
+ },
+ },
+ options: [
+ {
+ displayName: 'Created At',
+ name: 'createdAt',
+ type: 'dateTime',
+ default: '',
+ },
+ {
+ displayName: 'Customer Email',
+ name: 'customerEmail',
+ type: 'string',
+ default: '',
+ },
+ {
+ displayName: 'Customer ID',
+ name: 'customerId',
+ type: 'number',
+ default: 0,
+ },
+ {
+ displayName: 'Draft',
+ name: 'draft',
+ type: 'boolean',
+ default: false,
+ displayOptions: {
+ show: {
+ '/type': [
+ 'note',
+ ],
+ },
+ },
+ description: 'If set to true, a draft reply is created',
+ },
+ {
+ displayName: 'Imported',
+ name: 'imported',
+ type: 'boolean',
+ default: false,
+ description: 'When imported is set to true, no outgoing emails or notifications will be generated.',
+ },
+ ]
+ },
+ {
+ displayName: 'Attachments',
+ name: 'attachmentsUi',
+ placeholder: 'Add Attachments',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ operation: [
+ 'create',
+ ],
+ resource: [
+ 'thread',
+ ],
+ },
+ },
+ options: [
+ {
+ name: 'attachmentsValues',
+ displayName: 'Attachments Values',
+ values: [
+ {
+ displayName: 'FileName',
+ name: 'fileName',
+ type: 'string',
+ default: '',
+ description: 'Attachment’s file name',
+ },
+ {
+ displayName: 'Mime Type',
+ name: 'mimeType',
+ type: 'string',
+ default: '',
+ description: 'Attachment’s mime type',
+ },
+ {
+ displayName: 'Data',
+ name: 'data',
+ type: 'string',
+ default: '',
+ placeholder: 'ZXhhbXBsZSBmaWxl',
+ description: 'Base64-encoded stream of data.',
+ },
+ ],
+ },
+ {
+ name: 'attachmentsBinary',
+ displayName: 'Attachments Binary',
+ values: [
+ {
+ displayName: 'Property',
+ name: 'property',
+ type: 'string',
+ default: 'data',
+ description: 'Name of the binary properties which contain data which should be added to email as attachment',
+ },
+ ],
+ },
+ ],
+ default: '',
+ description: 'Array of supported attachments to add to the message.',
+ },
+/* -------------------------------------------------------------------------- */
+/* thread:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Conversation ID',
+ name: 'conversationId',
+ type: 'string',
+ default: '',
+ required: true,
+ displayOptions: {
+ show: {
+ resource: [
+ 'thread',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ description: 'conversation ID',
+ },
+] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/HelpScout/ThreadInterface.ts b/packages/nodes-base/nodes/HelpScout/ThreadInterface.ts
new file mode 100644
index 000000000..e47a0a674
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/ThreadInterface.ts
@@ -0,0 +1,15 @@
+import { IDataObject } from 'n8n-workflow';
+
+export interface IAttachment {
+ fileName?: string;
+ mimeType?: string;
+ data?: string;
+}
+
+export interface IThread {
+ createdAt?: string;
+ customer?: IDataObject;
+ imported?: boolean;
+ text?: string;
+ attachments?: IAttachment[];
+}
diff --git a/packages/nodes-base/nodes/HelpScout/helpScout.png b/packages/nodes-base/nodes/HelpScout/helpScout.png
new file mode 100644
index 000000000..1ebdaa8e5
Binary files /dev/null and b/packages/nodes-base/nodes/HelpScout/helpScout.png differ
diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json
index 25f148aa7..67490dd1c 100644
--- a/packages/nodes-base/package.json
+++ b/packages/nodes-base/package.json
@@ -44,6 +44,7 @@
"dist/credentials/GitlabApi.credentials.js",
"dist/credentials/GoogleApi.credentials.js",
"dist/credentials/GoogleOAuth2Api.credentials.js",
+ "dist/credentials/HelpScoutOAuth2Api.credentials.js",
"dist/credentials/HttpBasicAuth.credentials.js",
"dist/credentials/HttpDigestAuth.credentials.js",
"dist/credentials/HttpHeaderAuth.credentials.js",
@@ -124,6 +125,8 @@
"dist/nodes/Google/GoogleDrive.node.js",
"dist/nodes/Google/GoogleSheets.node.js",
"dist/nodes/GraphQL/GraphQL.node.js",
+ "dist/nodes/HelpScout/HelpScout.node.js",
+ "dist/nodes/HelpScout/HelpScoutTrigger.node.js",
"dist/nodes/HtmlExtract/HtmlExtract.node.js",
"dist/nodes/HttpRequest.node.js",
"dist/nodes/Hubspot/Hubspot.node.js",
@@ -195,8 +198,8 @@
"@types/gm": "^1.18.2",
"@types/imap-simple": "^4.2.0",
"@types/jest": "^24.0.18",
- "@types/lodash.set": "^4.3.6",
- "@types/moment-timezone": "^0.5.12",
+ "@types/lodash.set": "^4.3.6",
+ "@types/moment-timezone": "^0.5.12",
"@types/mongodb": "^3.3.6",
"@types/node": "^10.10.1",
"@types/nodemailer": "^4.6.5",
@@ -222,8 +225,8 @@
"imap-simple": "^4.3.0",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
- "lodash.unset": "^4.5.2",
- "moment-timezone": "0.5.28",
+ "lodash.unset": "^4.5.2",
+ "moment-timezone": "0.5.28",
"mongodb": "^3.3.2",
"mysql2": "^2.0.1",
"n8n-core": "~0.20.0",