diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts
index 4fe1ef70d7..99cda09412 100644
--- a/packages/cli/src/Server.ts
+++ b/packages/cli/src/Server.ts
@@ -203,7 +203,7 @@ class App {
});
}
- jwt.verify(token, getKey, {}, (err: Error, decoded: string) => {
+ jwt.verify(token, getKey, {}, (err: Error, decoded: object) => {
if (err) return ResponseHelper.jwtAuthAuthorizationError(res, "Invalid token");
next();
diff --git a/packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts b/packages/nodes-base/credentials/HelpScoutOAuth2Api.credentials.ts
new file mode 100644
index 0000000000..0301bf2c51
--- /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 0000000000..cce35b096a
--- /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: 'Embed',
+ name: 'embed',
+ type: 'options',
+ options: [
+ {
+ name: 'Threads',
+ value: 'threads',
+ },
+ ],
+ default: '',
+ description: 'Allows embedding/loading of sub-entities',
+ },
+ {
+ displayName: 'Mailbox ID',
+ name: 'mailbox',
+ type: 'string',
+ default: '',
+ description: 'Filters conversations from a specific mailbox',
+ },
+ {
+ displayName: 'Folder ID',
+ name: 'folder',
+ type: 'string',
+ default: '',
+ description: 'Filters conversations from a specific folder id',
+ },
+ {
+ 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',
+ },
+ {
+ displayName: 'Assign To',
+ name: 'assignTo',
+ type: 'number',
+ default: 0,
+ description: 'Filters conversations by assignee id',
+ },
+ {
+ 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: '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: 'Query',
+ name: 'query',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: 'Advanced search Examples'
+ },
+ ],
+ },
+] 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 0000000000..4140fda218
--- /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 0000000000..653e876beb
--- /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 0000000000..9f909a0b6b
--- /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: 'Properties',
+ value: 'properties',
+ description: 'Get customer property definitions',
+ },
+ {
+ name: 'Get',
+ value: 'get',
+ description: 'Get a customer',
+ },
+ {
+ name: 'Get All',
+ value: 'getAll',
+ description: 'Get all customers',
+ },
+ {
+ 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: 'Notes',
+ name: 'background',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Notes`,
+ },
+ {
+ 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: '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: 'gtalk',
+ 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: 'Mailbox ID',
+ name: 'mailbox',
+ type: 'string',
+ default: '',
+ description: 'Filters customers from a specific mailbox',
+ },
+ {
+ 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: '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: 'Notes',
+ name: 'background',
+ type: 'string',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ description: `Notes`,
+ },
+ {
+ 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: '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 0000000000..569a92c9aa
--- /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 0000000000..c7cda4eac6
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/GenericFunctions.ts
@@ -0,0 +1,69 @@
+import { OptionsWithUri } from 'request';
+import {
+ IExecuteFunctions,
+ IExecuteSingleFunctions,
+ ILoadOptionsFunctions,
+ IHookFunctions,
+} 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 error;
+ }
+}
+
+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 0000000000..27534b2426
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/HelpScout.node.ts
@@ -0,0 +1,410 @@
+import {
+ IExecuteFunctions,
+} from 'n8n-core';
+
+import {
+ IDataObject,
+ INodeExecutionData,
+ INodeTypeDescription,
+ INodeType,
+ ILoadOptionsFunctions,
+ INodePropertyOptions,
+ IBinaryKeyData,
+} from 'n8n-workflow';
+
+import {
+ helpscoutApiRequest,
+ helpscoutApiRequestAllItems,
+} from './GenericFunctions';
+
+import {
+ conversationOperations,
+ conversationFields,
+} from './ConversationDescription';
+
+import {
+ customerOperations,
+ customerFields,
+} from './CustomerDescription';
+
+import {
+ mailboxOperations,
+ mailboxFields,
+} from './MailboxDescription';
+
+import {
+ threadOperations,
+ threadFields,
+} from './ThreadDescription';
+
+import {
+ ICustomer,
+} from './CustomerInterface';
+
+import {
+ IConversation,
+ } from './ConversationInterface';
+
+ import {
+ IThread,
+ IAttachment,
+ } from './ThreadInterface';
+
+ import {
+ countriesCodes
+} from './CountriesCodes';
+
+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 0000000000..ecb7e2a12a
--- /dev/null
+++ b/packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts
@@ -0,0 +1,202 @@
+import {
+ IHookFunctions,
+ IWebhookFunctions,
+} from 'n8n-core';
+
+import {
+ INodeTypeDescription,
+ INodeType,
+ IWebhookResponseData,
+ IDataObject,
+} 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: 'convo.agent.reply.created',
+ value: 'convo.agent.reply.created',
+ },
+ {
+ name: 'convo.assigned',
+ value: 'convo.assigned',
+ },
+ {
+ name: 'convo.created',
+ value: 'convo.created',
+ },
+ {
+ name: 'convo.customer.reply.created',
+ value: 'convo.customer.reply.created',
+ },
+ {
+ name: 'convo.deleted',
+ value: 'convo.deleted',
+ },
+ {
+ name: 'convo.merged',
+ value: 'convo.merged',
+ },
+ {
+ name: 'convo.moved',
+ value: 'convo.moved',
+ },
+ {
+ name: 'convo.note.created',
+ value: 'convo.note.created',
+ },
+ {
+ name: 'convo.status',
+ value: 'convo.status',
+ },
+ {
+ name: 'convo.tags',
+ value: 'convo.tags',
+ },
+ {
+ name: 'customer.created',
+ value: 'customer.created',
+ },
+ {
+ name: 'satisfaction.ratings',
+ 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 0000000000..923b01677f
--- /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 0000000000..230b99ce56
--- /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: '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: 'Created At',
+ name: 'createdAt',
+ type: 'dateTime',
+ default: '',
+ },
+ ]
+ },
+ {
+ 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 0000000000..b6cbbda213
--- /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 0000000000..a2be95ba7f
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 746f91f723..282af6371b 100644
--- a/packages/nodes-base/package.json
+++ b/packages/nodes-base/package.json
@@ -42,7 +42,8 @@
"dist/credentials/GithubApi.credentials.js",
"dist/credentials/GithubOAuth2Api.credentials.js",
"dist/credentials/GitlabApi.credentials.js",
- "dist/credentials/GoogleApi.credentials.js",
+ "dist/credentials/GoogleApi.credentials.js",
+ "dist/credentials/HelpScoutOAuth2Api.credentials.js",
"dist/credentials/HttpBasicAuth.credentials.js",
"dist/credentials/HttpDigestAuth.credentials.js",
"dist/credentials/HttpHeaderAuth.credentials.js",
@@ -118,7 +119,9 @@
"dist/nodes/Gitlab/GitlabTrigger.node.js",
"dist/nodes/Google/GoogleDrive.node.js",
"dist/nodes/Google/GoogleSheets.node.js",
- "dist/nodes/GraphQL/GraphQL.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",