Add Activepieces integration for workflow automation

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

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

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

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-help-scout
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-help-scout` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-help-scout",
"version": "0.0.8",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-help-scout",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/help-scout/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": [
"dist/{projectRoot}"
],
"currentVersionResolver": "git-tag",
"fallbackCurrentVersionResolver": "disk"
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/help-scout",
"tsConfig": "packages/pieces/community/help-scout/tsconfig.lib.json",
"packageJson": "packages/pieces/community/help-scout/package.json",
"main": "packages/pieces/community/help-scout/src/index.ts",
"assets": [
"packages/pieces/community/help-scout/*.md",
{
"input": "packages/pieces/community/help-scout/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"^build",
"prebuild"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
},
"prebuild": {
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/help-scout",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Klicke auf dein Profilsymbol oben rechts und wähle **Dein Profil**.\n 2. Gehen Sie zu **Meine Apps** und klicken Sie auf **App erstellen**.\n 3. Geben Sie **App Name** ein und verwenden Sie unten die Weiterleitungs-URL.\n 4. Kopiere die **App ID** und **App Secret** und gib sie als **Client ID** bzw. **Client Secret** an.",
"Create Conversation": "Unterhaltung erstellen",
"Send Reply": "Antwort senden",
"Add Note": "Notiz hinzufügen",
"Create Customer": "Kunde erstellen",
"Update Customer Properties": "Kundeneigenschaften aktualisieren",
"Find Conversation": "Unterhaltung finden",
"Find Customer": "Kunde finden",
"Find User": "Benutzer finden",
"Custom API Call": "Eigener API-Aufruf",
"Start a new conversation.": "Starte eine neue Unterhaltung.",
"Sends a reply in an existing conversation.": "Sendet eine Antwort in einer bestehenden Konversation.",
"Adds a note to a conversation.": "Fügt eine Notiz zu einer Unterhaltung hinzu.",
"Adds a new customer to Help Scout.": "Fügt einen neuen Kunden hinzu, um Späher zu helfen.",
"Updates customer's properties.": "Aktualisiert die Eigenschaften des Kunden.",
"Finds an existing conversation using provided filter.": "Findet eine bestehende Unterhaltung mit dem angegebenen Filter.",
"Finds a customer by email.": "Findet einen Kunden per E-Mail.",
"Finds a user by email.": "Findet einen Benutzer per E-Mail.",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Mailbox": "Postfach",
"Subject": "Betreff",
"Customer Email": "Kunden-E-Mail",
"From User": "Von Benutzer",
"Thread Type": "Thread-Typ",
"Conversation Status": "Konversationsstatus",
"Body": "Körper",
"Assigned User": "Zugewiesener Benutzer",
"Tags": "Tags",
"CC": "CC",
"BCC": "BCC",
"Imported": "Importiert",
"Conversation": "Unterhaltung",
"Reply Text": "Antworttext",
"Draft": "Entwurf",
"User (who adds the reply)": "Benutzer (der die Antwort hinzufügt)",
"CC (emails)": "CC (E-Mails)",
"BCC (emails)": "BCC (E-Mails)",
"Note Text": "Notiztext",
"User": "Benutzer",
"Email": "E-Mail",
"First Name": "Vorname",
"Last Name": "Nachname",
"Phone": "Telefon",
"Photo URL": "Foto-URL",
"Job Title": "Job Titel",
"Location": "Standort",
"Background": "Hintergrund",
"Age": "Alter",
"Gender": "Geschlecht",
"Organization": "Organisation",
"Social Profile URLs": "Social Profil-URLs",
"Customer": "Kunde",
"Customer Properties": "Kundeneigenschaften",
"Status": "Status",
"Custom Query": "Eigene Abfrage",
"Method": "Methode",
"Headers": "Kopfzeilen",
"Query Parameters": "Abfrageparameter",
"Response is Binary ?": "Antwort ist binär?",
"No Error on Failure": "Kein Fehler bei Fehler",
"Timeout (in seconds)": "Timeout (in Sekunden)",
"Customers age (string, e.g. \"30-35\")": "Alter des Kunden (String, z.B. \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs für soziale Profile (Typ wird auf \"Ander\")",
"Authorization headers are injected automatically from your connection.": "Autorisierungs-Header werden automatisch von Ihrer Verbindung injiziert.",
"Enable for files like PDFs, images, etc..": "Aktivieren für Dateien wie PDFs, Bilder, etc..",
"Chat": "Chat",
"Reply": "Antwort",
"Active": "Aktiv",
"Closed": "Geschlossen",
"Pending": "Ausstehend",
"Spam": "Spam",
"Male": "Mann",
"Female": "Weiblich",
"Unknown": "Unbekannt",
"Open": "Öffnen",
"All": "Alle",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"Conversation Created": "Unterhaltung erstellt",
"Conversation Assigned": "Unterhaltung zugewiesen",
"New Customer": "Neuer Kunde",
"Tags Updated": "Tags aktualisiert",
"Triggers when a new conversation is started in a mailbox.": "Wird ausgelöst, wenn eine neue Unterhaltung in einer Mailbox gestartet wird.",
"Triggers when a conversation is assigned to a user.": "Wird ausgelöst, wenn eine Unterhaltung einem Benutzer zugewiesen wird.",
"Triggers when a new customer is added.": "Wird ausgelöst, wenn ein neuer Kunde hinzugefügt wird.",
"Triggers when tags on a conversation are modified.": "Löst aus, wenn Tags in einer Unterhaltung geändert werden."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "Crear conversación",
"Send Reply": "Enviar respuesta",
"Add Note": "Añadir nota",
"Create Customer": "Crear cliente",
"Update Customer Properties": "Actualizar propiedades del cliente",
"Find Conversation": "Encontrar conversación",
"Find Customer": "Buscar cliente",
"Find User": "Buscar usuario",
"Custom API Call": "Llamada API personalizada",
"Start a new conversation.": "Iniciar una nueva conversación.",
"Sends a reply in an existing conversation.": "Envía una respuesta en una conversación existente.",
"Adds a note to a conversation.": "Añade una nota a una conversación.",
"Adds a new customer to Help Scout.": "Añade un nuevo cliente a Ayuda de exploración.",
"Updates customer's properties.": "Actualiza las propiedades del cliente.",
"Finds an existing conversation using provided filter.": "Encuentra una conversación existente usando el filtro proporcionado.",
"Finds a customer by email.": "Encuentra un cliente por correo electrónico.",
"Finds a user by email.": "Encuentra un usuario por correo electrónico.",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Mailbox": "Buzón",
"Subject": "Asunto",
"Customer Email": "Email del cliente",
"From User": "Del usuario",
"Thread Type": "Tipo de hilo",
"Conversation Status": "Estado de la conversación",
"Body": "Cuerpo",
"Assigned User": "Usuario asignado",
"Tags": "Etiquetas",
"CC": "CC",
"BCC": "CCO",
"Imported": "Importado",
"Conversation": "Conversación",
"Reply Text": "Responder texto",
"Draft": "Borrador",
"User (who adds the reply)": "Usuario (quien añade la respuesta)",
"CC (emails)": "CC (emails)",
"BCC (emails)": "BCC (emails)",
"Note Text": "Nota texto",
"User": "Usuario",
"Email": "E-mail",
"First Name": "Nombre",
"Last Name": "Apellido",
"Phone": "Teléfono",
"Photo URL": "URL de la foto",
"Job Title": "Trabajo",
"Location": "Ubicación",
"Background": "Fondo",
"Age": "Edad",
"Gender": "Sexo",
"Organization": "Organización",
"Social Profile URLs": "URL del perfil social",
"Customer": "Cliente",
"Customer Properties": "Propiedades del cliente",
"Status": "Estado",
"Custom Query": "Consulta personalizada",
"Method": "Método",
"Headers": "Encabezados",
"Query Parameters": "Parámetros de consulta",
"Response is Binary ?": "¿Respuesta es binaria?",
"No Error on Failure": "No hay ningún error en fallo",
"Timeout (in seconds)": "Tiempo de espera (en segundos)",
"Customers age (string, e.g. \"30-35\")": "Edad del cliente (cadena, p. ej., \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs para perfiles sociales (el tipo se establecerá en \"otro\")",
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
"Chat": "Chatear",
"Reply": "Responder",
"Active": "Activo",
"Closed": "Cerrado",
"Pending": "Pendiente",
"Spam": "Spam",
"Male": "Hombre",
"Female": "Mujer",
"Unknown": "Desconocido",
"Open": "Abrir",
"All": "Todos",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"Conversation Created": "Conversación creada",
"Conversation Assigned": "Conversación asignada",
"New Customer": "Nuevo cliente",
"Tags Updated": "Etiquetas actualizadas",
"Triggers when a new conversation is started in a mailbox.": "Dispara cuando se inicia una nueva conversación en un buzón.",
"Triggers when a conversation is assigned to a user.": "Dispara cuando una conversación es asignada a un usuario.",
"Triggers when a new customer is added.": "Se activa cuando se añade un nuevo cliente.",
"Triggers when tags on a conversation are modified.": "Dispara cuando se modifican las etiquetas en una conversación."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "Créer une conversation",
"Send Reply": "Envoyer la réponse",
"Add Note": "Ajouter une note",
"Create Customer": "Créer un client",
"Update Customer Properties": "Mettre à jour les propriétés du client",
"Find Conversation": "Trouver une conversation",
"Find Customer": "Trouver le client",
"Find User": "Trouver un utilisateur",
"Custom API Call": "Appel API personnalisé",
"Start a new conversation.": "Commencer une nouvelle conversation.",
"Sends a reply in an existing conversation.": "Envoie une réponse dans une conversation existante.",
"Adds a note to a conversation.": "Ajoute une note à une conversation.",
"Adds a new customer to Help Scout.": "Ajoute un nouveau client à l'aide de l'éclaireur.",
"Updates customer's properties.": "Met à jour les propriétés du client.",
"Finds an existing conversation using provided filter.": "Trouve une conversation existante en utilisant le filtre fourni.",
"Finds a customer by email.": "Trouve un client par email.",
"Finds a user by email.": "Trouve un utilisateur par email.",
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
"Mailbox": "Boîte aux lettres",
"Subject": "Sujet",
"Customer Email": "E-mail du client",
"From User": "De l'utilisateur",
"Thread Type": "Type de fil de discussion",
"Conversation Status": "Statut de la conversation",
"Body": "Corps",
"Assigned User": "Utilisateur assigné",
"Tags": "Tags",
"CC": "CC",
"BCC": "Cci",
"Imported": "Importé",
"Conversation": "Conversation",
"Reply Text": "Texte de réponse",
"Draft": "Brouillon",
"User (who adds the reply)": "Utilisateur (qui ajoute la réponse)",
"CC (emails)": "CC (emails)",
"BCC (emails)": "BCC (emails)",
"Note Text": "Texte de la note",
"User": "Utilisateur",
"Email": "Courriel",
"First Name": "First Name",
"Last Name": "Last Name",
"Phone": "Téléphone",
"Photo URL": "URL de la photo",
"Job Title": "Titre du poste",
"Location": "Localisation",
"Background": "Arrière-plan",
"Age": "Âge",
"Gender": "Sexe",
"Organization": "Organisation",
"Social Profile URLs": "URL du profil social",
"Customer": "Client",
"Customer Properties": "Propriétés du client",
"Status": "Statut",
"Custom Query": "Requête personnalisée",
"Method": "Méthode",
"Headers": "En-têtes",
"Query Parameters": "Paramètres de requête",
"Response is Binary ?": "La réponse est Binaire ?",
"No Error on Failure": "Aucune erreur en cas d'échec",
"Timeout (in seconds)": "Délai d'attente (en secondes)",
"Customers age (string, e.g. \"30-35\")": "Âge du client (chaîne, par exemple \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URL pour les profils sociaux (le type sera réglé sur \"autre\")",
"Authorization headers are injected automatically from your connection.": "Les en-têtes d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"Chat": "Discuter",
"Reply": "Répondre",
"Active": "Actif",
"Closed": "Fermé",
"Pending": "En attente",
"Spam": "Spam",
"Male": "Homme",
"Female": "Femme",
"Unknown": "Unknown",
"Open": "Ouvert",
"All": "Tous",
"GET": "OBTENIR",
"POST": "POSTER",
"PATCH": "PATCH",
"PUT": "EFFACER",
"DELETE": "SUPPRIMER",
"HEAD": "TÊTE",
"Conversation Created": "Conversation créée",
"Conversation Assigned": "Conversation assignée",
"New Customer": "Nouveau client",
"Tags Updated": "Tags mis à jour",
"Triggers when a new conversation is started in a mailbox.": "Déclenche quand une nouvelle conversation est lancée dans une boîte aux lettres.",
"Triggers when a conversation is assigned to a user.": "Déclenche lorsqu'une conversation est assignée à un utilisateur.",
"Triggers when a new customer is added.": "Déclenche lorsqu'un nouveau client est ajouté.",
"Triggers when tags on a conversation are modified.": "Déclenche lorsque les tags d'une conversation sont modifiés."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "会話を作成",
"Send Reply": "返信を送信",
"Add Note": "メモを追加",
"Create Customer": "顧客を作成",
"Update Customer Properties": "顧客プロパティを更新",
"Find Conversation": "会話を検索",
"Find Customer": "顧客検索",
"Find User": "ユーザーを検索",
"Custom API Call": "カスタムAPI通話",
"Start a new conversation.": "新しい会話を開始します。",
"Sends a reply in an existing conversation.": "既存の会話に返信を送信します。",
"Adds a note to a conversation.": "会話にメモを追加する。",
"Adds a new customer to Help Scout.": "偵察を助けるために新しい顧客を追加する。",
"Updates customer's properties.": "顧客のプロパティを更新",
"Finds an existing conversation using provided filter.": "提供されたフィルタを使用して既存の会話を検索します。",
"Finds a customer by email.": "メールで顧客を検索します。",
"Finds a user by email.": "メールでユーザーを検索します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Mailbox": "受信箱",
"Subject": "件名",
"Customer Email": "顧客のメールアドレス",
"From User": "ユーザーから",
"Thread Type": "スレッドの種類",
"Conversation Status": "会話の状態",
"Body": "本文",
"Assigned User": "割り当て済みユーザー",
"Tags": "タグ",
"CC": "CC",
"BCC": "BCC",
"Imported": "インポートしました",
"Conversation": "会話",
"Reply Text": "返信テキスト",
"Draft": "下書き",
"User (who adds the reply)": "ユーザー (返信を追加)",
"CC (emails)": "CC (メール)",
"BCC (emails)": "BCC (Eメール)",
"Note Text": "ノートテキスト",
"User": "ユーザー",
"Email": "Eメールアドレス",
"First Name": "名",
"Last Name": "姓",
"Phone": "電話番号",
"Photo URL": "写真 URL",
"Job Title": "役職名",
"Location": "場所",
"Background": "背景",
"Age": "年齢",
"Gender": "性別",
"Organization": "組織",
"Social Profile URLs": "ソーシャルプロフィールのURL",
"Customer": "顧客",
"Customer Properties": "顧客のプロパティ",
"Status": "ステータス",
"Custom Query": "カスタムクエリ",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"Customers age (string, e.g. \"30-35\")": "顧客の年齢 (文字列、例:\"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "ソーシャルプロファイルのURLタイプは「other」に設定されます",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"Chat": "チャット",
"Reply": "返信",
"Active": "有効",
"Closed": "クローズ済み",
"Pending": "処理待ち",
"Spam": "スパム",
"Male": "男性",
"Female": "女性",
"Unknown": "不明",
"Open": "開く",
"All": "すべて",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"Conversation Created": "会話を作成しました",
"Conversation Assigned": "会話が割り当てられました",
"New Customer": "新規顧客",
"Tags Updated": "タグが更新されました",
"Triggers when a new conversation is started in a mailbox.": "メールボックスで新しい会話が開始されたときにトリガーします。",
"Triggers when a conversation is assigned to a user.": "会話がユーザーに割り当てられたときにトリガーします。",
"Triggers when a new customer is added.": "新しい顧客が追加されたときにトリガーします。",
"Triggers when tags on a conversation are modified.": "会話上のタグが変更されたときにトリガーされます。"
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Klik op het profielpictogram rechtsboven en selecteer **jouw profiel**.\n 2. Ga naar **Mijn Apps** en klik op **Creëer App**.\n 3. Geef **App Naam** op en gebruik hieronder de redirect URL.\n 4. Kopieer de **App ID** en **App Secret**, en geef ze aan als **Client ID** en **Client Secret**.",
"Create Conversation": "Gesprek aanmaken",
"Send Reply": "Stuur antwoord",
"Add Note": "Notitie toevoegen",
"Create Customer": "Klant aanmaken",
"Update Customer Properties": "Klanteigenschappen bijwerken",
"Find Conversation": "Gesprek zoeken",
"Find Customer": "Klant zoeken",
"Find User": "Gebruiker zoeken",
"Custom API Call": "Custom API Call",
"Start a new conversation.": "Start een nieuw gesprek.",
"Sends a reply in an existing conversation.": "Verstuurt een antwoord in een bestaand gesprek.",
"Adds a note to a conversation.": "Voegt een notitie toe aan een gesprek.",
"Adds a new customer to Help Scout.": "Voegt een nieuwe klant toe om te helpen verkennen.",
"Updates customer's properties.": "Eigenschappen van klant bijwerken.",
"Finds an existing conversation using provided filter.": "Vindt een bestaand gesprek met behulp van opgegeven filter.",
"Finds a customer by email.": "Vindt een klant per e-mail.",
"Finds a user by email.": "Vindt een gebruiker per e-mail.",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Mailbox": "Brievenbus",
"Subject": "Onderwerp",
"Customer Email": "Klant e-mail",
"From User": "Van gebruiker",
"Thread Type": "Conversatie type",
"Conversation Status": "Gesprek status",
"Body": "Lichaam",
"Assigned User": "Toegewezen gebruiker",
"Tags": "Labels",
"CC": "CC",
"BCC": "Bcc",
"Imported": "Geïmporteerd",
"Conversation": "Gesprek",
"Reply Text": "Antwoord tekst",
"Draft": "Concept",
"User (who adds the reply)": "Gebruiker (voegt het antwoord toe)",
"CC (emails)": "CC (e-mails)",
"BCC (emails)": "BCC (e-mails)",
"Note Text": "Notitie tekst",
"User": "Gebruiker",
"Email": "E-mail",
"First Name": "Voornaam",
"Last Name": "Achternaam",
"Phone": "Telefoonnummer",
"Photo URL": "Foto URL",
"Job Title": "Job titel",
"Location": "Locatie",
"Background": "Achtergrond",
"Age": "Leeftijd",
"Gender": "Geslacht",
"Organization": "Rekening",
"Social Profile URLs": "Social profiel URL's",
"Customer": "Klant",
"Customer Properties": "Klant eigenschappen",
"Status": "status",
"Custom Query": "Aangepaste zoekopdracht",
"Method": "Methode",
"Headers": "Kopteksten",
"Query Parameters": "Query parameters",
"Response is Binary ?": "Antwoord is binair?",
"No Error on Failure": "Geen fout bij fout",
"Timeout (in seconds)": "Time-out (in seconden)",
"Customers age (string, e.g. \"30-35\")": "leeftijd van de klant (tekenreeks, bijv. \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URL's voor sociale profielen (type wordt ingesteld op \"ander\")",
"Authorization headers are injected automatically from your connection.": "Autorisatie headers worden automatisch geïnjecteerd vanuit uw verbinding.",
"Enable for files like PDFs, images, etc..": "Inschakelen voor bestanden zoals PDF's, afbeeldingen etc..",
"Chat": "Chatten",
"Reply": "Beantwoorden",
"Active": "Actief",
"Closed": "gesloten",
"Pending": "In behandeling",
"Spam": "Spam",
"Male": "Mannelijk",
"Female": "Vrouwelijk",
"Unknown": "Onbekend",
"Open": "Open",
"All": "Allemaal",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"Conversation Created": "Gesprek aangemaakt",
"Conversation Assigned": "Gesprek toegewezen",
"New Customer": "Nieuwe klant",
"Tags Updated": "Tags bijgewerkt",
"Triggers when a new conversation is started in a mailbox.": "Wordt uitgevoerd wanneer een nieuw gesprek wordt gestart in een mailbox.",
"Triggers when a conversation is assigned to a user.": "Triggert wanneer een gesprek aan een gebruiker is toegewezen.",
"Triggers when a new customer is added.": "Triggert wanneer een nieuwe klant wordt toegevoegd.",
"Triggers when tags on a conversation are modified.": "Triggert wanneer tags op een gesprek worden gewijzigd."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Clique no seu ícone de perfil no canto superior direito e selecione **Seu perfil**.\n 2. Vá para **Meus Aplicativos** e clique em **Criar Aplicativo**.\n 3. Forneça o **Nome do aplicativo** e use a URL de redirecionamento abaixo.\n 4. Copie o **App ID** e o **App Secret** e forneça-o como **Client ID** e o **Client Secret**, respectivamente.",
"Create Conversation": "Criar conversa",
"Send Reply": "Enviar resposta",
"Add Note": "Adicionar Nota",
"Create Customer": "Criar Cliente",
"Update Customer Properties": "Atualizar Propriedades do Cliente",
"Find Conversation": "Localizar Conversa",
"Find Customer": "Encontrar o cliente",
"Find User": "Localizar usuário",
"Custom API Call": "Chamada de API personalizada",
"Start a new conversation.": "Começar uma nova conversa.",
"Sends a reply in an existing conversation.": "Envia uma resposta em uma conversa existente.",
"Adds a note to a conversation.": "Adiciona uma nota a uma conversa.",
"Adds a new customer to Help Scout.": "Adiciona um novo cliente para Ajudar Patrulha.",
"Updates customer's properties.": "Atualiza propriedades do cliente.",
"Finds an existing conversation using provided filter.": "Encontra uma conversa existente usando o filtro fornecido.",
"Finds a customer by email.": "Encontra um cliente por e-mail.",
"Finds a user by email.": "Encontra um usuário por e-mail.",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Mailbox": "Caixa postal",
"Subject": "Cargo",
"Customer Email": "E-mail do Cliente",
"From User": "De Usuário",
"Thread Type": "Tipo de tópico",
"Conversation Status": "Status da conversa",
"Body": "Conteúdo",
"Assigned User": "Atribuído ao usuário",
"Tags": "Etiquetas",
"CC": "CC",
"BCC": "Cco",
"Imported": "Importado",
"Conversation": "Conversa",
"Reply Text": "Texto de Resposta",
"Draft": "Rascunho",
"User (who adds the reply)": "Usuário (que adiciona a resposta)",
"CC (emails)": "CC (e-mails)",
"BCC (emails)": "BCC (e-mails)",
"Note Text": "Texto da nota",
"User": "Usuário",
"Email": "e-mail",
"First Name": "Nome",
"Last Name": "Sobrenome",
"Phone": "Smartphone",
"Photo URL": "URL da Foto",
"Job Title": "Título do Cargo",
"Location": "Local:",
"Background": "Fundo",
"Age": "Idade",
"Gender": "Gênero",
"Organization": "Cliente",
"Social Profile URLs": "URLs do perfil social",
"Customer": "Cliente",
"Customer Properties": "Propriedades do cliente",
"Status": "Estado",
"Custom Query": "Consulta personalizada",
"Method": "Método",
"Headers": "Cabeçalhos",
"Query Parameters": "Parâmetros da consulta",
"Response is Binary ?": "A resposta é binária ?",
"No Error on Failure": "Nenhum erro no Failure",
"Timeout (in seconds)": "Tempo limite (em segundos)",
"Customers age (string, e.g. \"30-35\")": "Idade do cliente (string, ex.: \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs para perfis sociais (tipo será definido como \"outro\")",
"Authorization headers are injected automatically from your connection.": "Os cabeçalhos de autorização são inseridos automaticamente a partir da sua conexão.",
"Enable for files like PDFs, images, etc..": "Habilitar para arquivos como PDFs, imagens, etc..",
"Chat": "Bate-papo",
"Reply": "Responder",
"Active": "Ativo",
"Closed": "Fechado",
"Pending": "Pendente",
"Spam": "Spam",
"Male": "Masculino",
"Female": "Feminino",
"Unknown": "Desconhecido",
"Open": "Abertas",
"All": "TODOS",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"Conversation Created": "Conversa Criada",
"Conversation Assigned": "Conversa atribuída",
"New Customer": "Novo Cliente",
"Tags Updated": "Tags Atualizadas",
"Triggers when a new conversation is started in a mailbox.": "Aciona quando uma nova conversa é iniciada em uma caixa de correio.",
"Triggers when a conversation is assigned to a user.": "Dispara quando uma conversa é atribuída a um usuário.",
"Triggers when a new customer is added.": "Aciona quando um novo cliente é adicionado.",
"Triggers when tags on a conversation are modified.": "Dispara quando tags em uma conversa são modificados."
}

View File

@@ -0,0 +1,91 @@
{
"Help Scout": "Помощь Разведчика",
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Нажмите на иконку профиля в правом верхнем углу и выберите **Ваш профиль**.\n 2. Перейдите в **Мои приложения** и нажмите на **Создать приложение**.\n 3. Предоставьте **Имя приложения** и используйте ниже URL перенаправления.\n 4. Скопируйте **App ID** и **App Secret**, и предоставьте их соответственно **Client ID** и **Client Secret**.",
"Create Conversation": "Создать диалог",
"Send Reply": "Отправить ответ",
"Add Note": "Добавить заметку",
"Create Customer": "Создать клиента",
"Update Customer Properties": "Обновить свойства клиента",
"Find Conversation": "Найти разговор",
"Find Customer": "Найти клиента",
"Find User": "Найти пользователя",
"Custom API Call": "Пользовательский вызов API",
"Start a new conversation.": "Начать новый разговор.",
"Sends a reply in an existing conversation.": "Отправляет ответ в существующей беседе.",
"Adds a note to a conversation.": "Добавляет заметку к разговору.",
"Adds a new customer to Help Scout.": "Добавляет нового клиента в Помощь Скаута.",
"Updates customer's properties.": "Обновляет свойства клиента.",
"Finds an existing conversation using provided filter.": "Находит существующую беседу, используя указанный фильтр.",
"Finds a customer by email.": "Поиск клиента по электронной почте.",
"Finds a user by email.": "Поиск пользователя по электронной почте.",
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
"Mailbox": "Почтовый ящик",
"Subject": "Тема",
"Customer Email": "Email клиента",
"From User": "От пользователя",
"Thread Type": "Тип потока",
"Conversation Status": "Статус разговора",
"Body": "Тело",
"Assigned User": "Назначенный пользователь",
"Tags": "Теги",
"CC": "CC",
"BCC": "BCC",
"Imported": "Импортировано",
"Conversation": "Обсуждение",
"Reply Text": "Текст ответа",
"Draft": "Черновик",
"User (who adds the reply)": "Пользователь (кто добавляет ответ)",
"CC (emails)": "Копия (email)",
"BCC (emails)": "Скрытая копия (email)",
"Note Text": "Текст заметки",
"User": "Пользователь",
"Email": "Почта",
"First Name": "First Name",
"Last Name": "Last Name",
"Phone": "Телефон",
"Photo URL": "URL фото",
"Job Title": "Заголовок",
"Location": "Местоположение",
"Background": "Справочная информация",
"Age": "Возраст",
"Gender": "Гендерная проблематика",
"Organization": "Организация",
"Social Profile URLs": "URL-адреса социальных профилей",
"Customer": "Покупатель",
"Customer Properties": "Свойства клиента",
"Status": "Статус",
"Custom Query": "Пользовательский запрос",
"Method": "Метод",
"Headers": "Заголовки",
"Query Parameters": "Параметры запроса",
"No Error on Failure": "Нет ошибок при ошибке",
"Timeout (in seconds)": "Таймаут (в секундах)",
"Customers age (string, e.g. \"30-35\")": "Возраст клиента (строка, например \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URL-адреса для социальных профилей (тип будет установлен на \"другое\")",
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
"Chat": "Чат",
"Reply": "Ответ",
"Active": "Активен",
"Closed": "Закрыто",
"Pending": "В ожидании",
"Spam": "Спам",
"Male": "Муж",
"Female": "Женская",
"Unknown": "Неизвестен",
"Open": "Открыть",
"All": "Все",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"Conversation Created": "Разговор создан",
"Conversation Assigned": "Назначена беседа",
"New Customer": "Новый клиент",
"Tags Updated": "Теги обновлены",
"Triggers when a new conversation is started in a mailbox.": "Включает при запуске нового разговора в почтовом ящике.",
"Triggers when a conversation is assigned to a user.": "Срабатывает при назначении разговора пользователю.",
"Triggers when a new customer is added.": "Включает при добавлении нового клиента.",
"Triggers when tags on a conversation are modified.": "Включает при изменении тегов в разговоре."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "Create Conversation",
"Send Reply": "Send Reply",
"Add Note": "Add Note",
"Create Customer": "Create Customer",
"Update Customer Properties": "Update Customer Properties",
"Find Conversation": "Find Conversation",
"Find Customer": "Find Customer",
"Find User": "Find User",
"Custom API Call": "Custom API Call",
"Start a new conversation.": "Start a new conversation.",
"Sends a reply in an existing conversation.": "Sends a reply in an existing conversation.",
"Adds a note to a conversation.": "Adds a note to a conversation.",
"Adds a new customer to Help Scout.": "Adds a new customer to Help Scout.",
"Updates customer's properties.": "Updates customer's properties.",
"Finds an existing conversation using provided filter.": "Finds an existing conversation using provided filter.",
"Finds a customer by email.": "Finds a customer by email.",
"Finds a user by email.": "Finds a user by email.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Mailbox": "Mailbox",
"Subject": "Subject",
"Customer Email": "Customer Email",
"From User": "From User",
"Thread Type": "Thread Type",
"Conversation Status": "Conversation Status",
"Body": "Body",
"Assigned User": "Assigned User",
"Tags": "Tags",
"CC": "CC",
"BCC": "BCC",
"Imported": "Imported",
"Conversation": "Conversation",
"Reply Text": "Reply Text",
"Draft": "Draft",
"User (who adds the reply)": "User (who adds the reply)",
"CC (emails)": "CC (emails)",
"BCC (emails)": "BCC (emails)",
"Note Text": "Note Text",
"User": "User",
"Email": "Email",
"First Name": "First Name",
"Last Name": "Last Name",
"Phone": "Phone",
"Photo URL": "Photo URL",
"Job Title": "Job Title",
"Location": "Location",
"Background": "Background",
"Age": "Age",
"Gender": "Gender",
"Organization": "Organization",
"Social Profile URLs": "Social Profile URLs",
"Customer": "Customer",
"Customer Properties": "Customer Properties",
"Status": "Status",
"Custom Query": "Custom Query",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Customers age (string, e.g. \"30-35\")": "Customers age (string, e.g. \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs for social profiles (type will be set to \"other\")",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Chat": "Chat",
"Reply": "Reply",
"Active": "Active",
"Closed": "Closed",
"Pending": "Pending",
"Spam": "Spam",
"Male": "Male",
"Female": "Female",
"Unknown": "Unknown",
"Open": "Open",
"All": "All",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"Conversation Created": "Conversation Created",
"Conversation Assigned": "Conversation Assigned",
"New Customer": "New Customer",
"Tags Updated": "Tags Updated",
"Triggers when a new conversation is started in a mailbox.": "Triggers when a new conversation is started in a mailbox.",
"Triggers when a conversation is assigned to a user.": "Triggers when a conversation is assigned to a user.",
"Triggers when a new customer is added.": "Triggers when a new customer is added.",
"Triggers when tags on a conversation are modified.": "Triggers when tags on a conversation are modified."
}

View File

@@ -0,0 +1,91 @@
{
"Help Scout": "Help Scout",
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "Create Conversation",
"Send Reply": "Send Reply",
"Add Note": "Add Note",
"Create Customer": "Create Customer",
"Update Customer Properties": "Update Customer Properties",
"Find Conversation": "Find Conversation",
"Find Customer": "Find Customer",
"Find User": "Find User",
"Custom API Call": "Custom API Call",
"Start a new conversation.": "Start a new conversation.",
"Sends a reply in an existing conversation.": "Sends a reply in an existing conversation.",
"Adds a note to a conversation.": "Adds a note to a conversation.",
"Adds a new customer to Help Scout.": "Adds a new customer to Help Scout.",
"Updates customer's properties.": "Updates customer's properties.",
"Finds an existing conversation using provided filter.": "Finds an existing conversation using provided filter.",
"Finds a customer by email.": "Finds a customer by email.",
"Finds a user by email.": "Finds a user by email.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Mailbox": "Mailbox",
"Subject": "Subject",
"Customer Email": "Customer Email",
"From User": "From User",
"Thread Type": "Thread Type",
"Conversation Status": "Conversation Status",
"Body": "Body",
"Assigned User": "Assigned User",
"Tags": "Tags",
"CC": "CC",
"BCC": "BCC",
"Imported": "Imported",
"Conversation": "Conversation",
"Reply Text": "Reply Text",
"Draft": "Bản nháp",
"User (who adds the reply)": "User (who adds the reply)",
"CC (emails)": "CC (emails)",
"BCC (emails)": "BCC (emails)",
"Note Text": "Note Text",
"User": "User",
"Email": "Email",
"First Name": "First Name",
"Last Name": "Last Name",
"Phone": "Phone",
"Photo URL": "Photo URL",
"Job Title": "Job Title",
"Location": "Location",
"Background": "Background",
"Age": "Age",
"Gender": "Gender",
"Organization": "Organization",
"Social Profile URLs": "Social Profile URLs",
"Customer": "Customer",
"Customer Properties": "Customer Properties",
"Status": "Status",
"Custom Query": "Custom Query",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Customers age (string, e.g. \"30-35\")": "Customers age (string, e.g. \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs for social profiles (type will be set to \"other\")",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Chat": "Chat",
"Reply": "Reply",
"Active": "Tích cực",
"Closed": "Closed",
"Pending": "Đang chờ",
"Spam": "Spam",
"Male": "Male",
"Female": "Female",
"Unknown": "Unknown",
"Open": "Open",
"All": "Tất cả",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"Conversation Created": "Conversation Created",
"Conversation Assigned": "Conversation Assigned",
"New Customer": "New Customer",
"Tags Updated": "Tags Updated",
"Triggers when a new conversation is started in a mailbox.": "Triggers when a new conversation is started in a mailbox.",
"Triggers when a conversation is assigned to a user.": "Triggers when a conversation is assigned to a user.",
"Triggers when a new customer is added.": "Triggers when a new customer is added.",
"Triggers when tags on a conversation are modified.": "Triggers when tags on a conversation are modified."
}

View File

@@ -0,0 +1,92 @@
{
"\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.": "\n 1. Click on your profile icon at the top right and select **Your Profile**.\n 2. Go to **My Apps** and click on **Create App**.\n 3. Provide **App Name** and use below redirect URL.\n 4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.",
"Create Conversation": "Create Conversation",
"Send Reply": "Send Reply",
"Add Note": "Add Note",
"Create Customer": "Create Customer",
"Update Customer Properties": "Update Customer Properties",
"Find Conversation": "Find Conversation",
"Find Customer": "Find Customer",
"Find User": "Find User",
"Custom API Call": "自定义 API 呼叫",
"Start a new conversation.": "Start a new conversation.",
"Sends a reply in an existing conversation.": "Sends a reply in an existing conversation.",
"Adds a note to a conversation.": "Adds a note to a conversation.",
"Adds a new customer to Help Scout.": "Adds a new customer to Help Scout.",
"Updates customer's properties.": "Updates customer's properties.",
"Finds an existing conversation using provided filter.": "Finds an existing conversation using provided filter.",
"Finds a customer by email.": "Finds a customer by email.",
"Finds a user by email.": "Finds a user by email.",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Mailbox": "Mailbox",
"Subject": "Subject",
"Customer Email": "Customer Email",
"From User": "From User",
"Thread Type": "Thread Type",
"Conversation Status": "Conversation Status",
"Body": "正文内容",
"Assigned User": "Assigned User",
"Tags": "标签",
"CC": "CC",
"BCC": "BCC",
"Imported": "Imported",
"Conversation": "Conversation",
"Reply Text": "Reply Text",
"Draft": "草稿",
"User (who adds the reply)": "User (who adds the reply)",
"CC (emails)": "CC (emails)",
"BCC (emails)": "BCC (emails)",
"Note Text": "Note Text",
"User": "用户",
"Email": "电子邮件地址",
"First Name": "名字",
"Last Name": "名字",
"Phone": "Phone",
"Photo URL": "Photo URL",
"Job Title": "Job Title",
"Location": "Location",
"Background": "Background",
"Age": "Age",
"Gender": "Gender",
"Organization": "Organization",
"Social Profile URLs": "Social Profile URLs",
"Customer": "Customer",
"Customer Properties": "Customer Properties",
"Status": "状态",
"Custom Query": "Custom Query",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"Customers age (string, e.g. \"30-35\")": "Customers age (string, e.g. \"30-35\")",
"URLs for social profiles (type will be set to \"other\")": "URLs for social profiles (type will be set to \"other\")",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Chat": "Chat",
"Reply": "Reply",
"Active": "使用中",
"Closed": "Closed",
"Pending": "待處理",
"Spam": "Spam",
"Male": "Male",
"Female": "Female",
"Unknown": "未知的",
"Open": "Open",
"All": "所有的",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"Conversation Created": "Conversation Created",
"Conversation Assigned": "Conversation Assigned",
"New Customer": "New Customer",
"Tags Updated": "Tags Updated",
"Triggers when a new conversation is started in a mailbox.": "Triggers when a new conversation is started in a mailbox.",
"Triggers when a conversation is assigned to a user.": "Triggers when a conversation is assigned to a user.",
"Triggers when a new customer is added.": "Triggers when a new customer is added.",
"Triggers when tags on a conversation are modified.": "Triggers when tags on a conversation are modified."
}

View File

@@ -0,0 +1,49 @@
import {
createPiece,
OAuth2PropertyValue,
} from '@activepieces/pieces-framework';
import { helpScoutAuth } from './lib/common/auth';
import { createConversation } from './lib/actions/create-conversation';
import { sendReply } from './lib/actions/send-reply';
import { addNote } from './lib/actions/add-note';
import { createCustomer } from './lib/actions/create-customer';
import { findConversation } from './lib/actions/find-conversation';
import { findCustomer } from './lib/actions/find-customer';
import { findUser } from './lib/actions/find-user';
import { conversationCreated } from './lib/triggers/conversation-created';
import { conversationAssigned } from './lib/triggers/conversation-assigned';
import { newCustomer } from './lib/triggers/new-customer';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { BASE_URL } from './lib/common/api';
import { updateCustomerProperties } from './lib/actions/update-customer-properties';
import { tagsUpdated } from './lib/triggers/tags-updated';
import { PieceCategory } from '@activepieces/shared';
export const helpScout = createPiece({
displayName: 'Help Scout',
auth: helpScoutAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/help-scout.png',
categories:[PieceCategory.CUSTOMER_SUPPORT],
authors: ['sparkybug'],
actions: [
createConversation,
sendReply,
addNote,
createCustomer,
updateCustomerProperties,
findConversation,
findCustomer,
findUser,
createCustomApiCallAction({
auth: helpScoutAuth,
baseUrl: () => BASE_URL,
authMapping: async (auth) => {
return {
Authorization: `Bearer ${(auth).access_token}`,
};
},
}),
],
triggers: [conversationCreated, conversationAssigned, newCustomer,tagsUpdated],
});

View File

@@ -0,0 +1,45 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { conversationIdDropdown, userIdDropdown } from '../common/props';
export const addNote = createAction({
auth: helpScoutAuth,
name: 'add_note',
displayName: 'Add Note',
description: 'Adds a note to a conversation.',
props: {
conversationId: conversationIdDropdown,
text: Property.LongText({
displayName: 'Note Text',
required: true,
}),
userId: userIdDropdown('User'),
},
async run({ auth, propsValue }) {
const payload: Record<string, any> = {
text: propsValue.text,
};
if(propsValue.userId) {
payload['user'] = Number(propsValue.userId);
}
Object.keys(payload).forEach((key) => {
if (payload[key] === undefined || payload[key] === null) {
delete payload[key];
}
});
const response = await helpScoutApiRequest({
method: HttpMethod.POST,
url: `/conversations/${propsValue.conversationId}/notes`,
auth,
body: payload,
});
const noteId = response.headers?.['resource-id'];
return {
id: noteId,
};
},
});

View File

@@ -0,0 +1,146 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { mailboxIdDropdown, userIdDropdown } from '../common/props';
export const createConversation = createAction({
auth: helpScoutAuth,
name: 'create_conversation',
displayName: 'Create Conversation',
description: 'Start a new conversation.',
props: {
mailboxId: mailboxIdDropdown(true),
subject: Property.ShortText({
displayName: 'Subject',
required: true,
}),
customerEmail: Property.ShortText({
displayName: 'Customer Email',
required: true,
}),
fromUser: userIdDropdown('From User'),
threadType: Property.StaticDropdown({
displayName: 'Thread Type',
required: true,
options: {
disabled: false,
options: [
{ label: 'Chat', value: 'chat' },
{ label: 'Phone', value: 'phone' },
{ label: 'Reply', value: 'reply' },
{ label: 'Customer', value: 'customer' },
],
},
}),
status: Property.StaticDropdown({
displayName: 'Conversation Status',
required: true,
options: {
disabled: false,
options: [
{ label: 'Active', value: 'active' },
{ label: 'Closed', value: 'closed' },
{ label: 'Pending', value: 'pending' },
],
},
}),
body: Property.LongText({
displayName: 'Body',
required: true,
}),
assignTo: userIdDropdown('Assigned User'),
tags: Property.Array({
displayName: 'Tags',
required: false,
}),
cc: Property.Array({
displayName: 'CC',
required: false,
}),
bcc: Property.Array({
displayName: 'BCC',
required: false,
}),
imported: Property.Checkbox({
displayName: 'Imported',
required: false,
}),
},
async run({ auth, propsValue }) {
if (propsValue.tags) {
const uniqueTags = new Set(propsValue.tags);
if (uniqueTags.size !== propsValue.tags.length) {
throw new Error('Tags must be unique.');
}
}
if (propsValue.cc) {
const uniqueCC = new Set(propsValue.cc);
if (uniqueCC.size !== propsValue.cc.length) {
throw new Error('CC emails must be unique.');
}
}
if (propsValue.bcc) {
const uniqueBCC = new Set(propsValue.bcc);
if (uniqueBCC.size !== propsValue.bcc.length) {
throw new Error('BCC emails must be unique.');
}
}
const customer = { email: propsValue.customerEmail };
const payload: Record<string, any> = {
type: 'chat',
mailboxId: propsValue.mailboxId,
subject: propsValue.subject,
customer,
status: propsValue.status,
threads: [
{
type: propsValue.threadType,
text: propsValue.body,
customer,
imported: propsValue.imported,
...(propsValue.cc &&
propsValue.threadType === 'customer' &&
propsValue.cc.length > 0 && { cc: propsValue.cc }),
...(propsValue.bcc &&
propsValue.threadType === 'customer' &&
propsValue.bcc.length > 0 && { bcc: propsValue.bcc }),
},
],
tags: propsValue.tags,
};
if(propsValue.fromUser) {
payload['user'] = Number(propsValue.fromUser);
}
if(propsValue.assignTo) {
payload['assignTo'] = Number(propsValue.assignTo);
}
Object.keys(payload).forEach((key) => {
if (payload[key] === undefined || payload[key] === null) {
delete payload[key];
}
});
Object.keys(payload['threads'][0]).forEach((key) => {
if (
payload['threads'][0][key] === undefined ||
payload['threads'][0][key] === null
) {
delete payload['threads'][0][key];
}
});
const response = await helpScoutApiRequest({
method: HttpMethod.POST,
url: '/conversations',
auth,
body: payload,
});
const convoId = response.headers?.['resource-id'];
return {
id:convoId
}
},
});

View File

@@ -0,0 +1,122 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { propsValidation } from '@activepieces/pieces-common';
import { z } from 'zod';
import { HttpMethod } from '@activepieces/pieces-common';
import { HttpStatusCode } from 'axios';
export const createCustomer = createAction({
auth: helpScoutAuth,
name: 'create_customer',
displayName: 'Create Customer',
description: 'Adds a new customer to Help Scout.',
props: {
email: Property.ShortText({
displayName: 'Email',
required: true,
}),
firstName: Property.ShortText({
displayName: 'First Name',
required: false,
}),
lastName: Property.ShortText({
displayName: 'Last Name',
required: false,
}),
phone: Property.ShortText({
displayName: 'Phone',
required: false,
}),
photoUrl: Property.ShortText({
displayName: 'Photo URL',
required: false,
}),
jobTitle: Property.ShortText({
displayName: 'Job Title',
required: false,
}),
location: Property.ShortText({
displayName: 'Location',
required: false,
}),
background: Property.LongText({
displayName: 'Background',
required: false,
}),
age: Property.ShortText({
displayName: 'Age',
required: false,
description: 'Customers age (string, e.g. "30-35")',
}),
gender: Property.StaticDropdown({
displayName: 'Gender',
required: false,
options: {
options: [
{ label: 'Male', value: 'male' },
{ label: 'Female', value: 'female' },
{ label: 'Unknown', value: 'unknown' },
],
},
}),
organization: Property.ShortText({
displayName: 'Organization',
required: false,
}),
socialProfiles: Property.Array({
displayName: 'Social Profile URLs',
required: false,
description: 'URLs for social profiles (type will be set to "other")',
}),
},
async run({ auth, propsValue }){
await propsValidation.validateZod(propsValue, {
email: z.string().email('Please provide a valid email address.'),
firstName: z.string().optional(),
lastName: z.string().optional(),
phone: z.string().optional(),
photoUrl: z.string().url('Photo URL must be a valid URL.').optional(),
jobTitle: z.string().optional(),
location: z.string().optional(),
background: z.string().optional(),
age: z.string().optional(),
gender: z.enum(['male', 'female', 'unknown']).optional(),
organization: z.string().optional(),
socialProfiles: z.array(z.string().url('Each social profile must be a valid URL.')).optional(),
});
const payload: Record<string, any> = {
emails: [{ value: propsValue.email, type: 'work' }],
firstName: propsValue.firstName,
lastName: propsValue.lastName,
phones: propsValue.phone ? [{ value: propsValue.phone, type: 'work' }] : undefined,
photoUrl: propsValue.photoUrl,
jobTitle: propsValue.jobTitle,
location: propsValue.location,
background: propsValue.background,
age: propsValue.age,
gender: propsValue.gender,
organization: propsValue.organization,
socialProfiles: Array.isArray(propsValue.socialProfiles)
? propsValue.socialProfiles.filter((url): url is string => typeof url === 'string').map((url) => ({ value: url, type: 'other' }))
: undefined,
};
Object.keys(payload).forEach((key) => {
if (payload[key] === undefined || payload[key] === null) {
delete payload[key];
}
});
const response = await helpScoutApiRequest({
method: HttpMethod.POST,
url: '/customers',
auth,
body: payload,
});
const customerId = response.headers?.['resource-id'];
return {
id:customerId
}
},
});

View File

@@ -0,0 +1,99 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { mailboxIdDropdown, userIdDropdown } from '../common/props';
export const findConversation = createAction({
auth: helpScoutAuth,
name: 'find_conversation',
displayName: 'Find Conversation',
description: 'Finds an existing conversation using provided filter.',
props: {
subject: Property.ShortText({
displayName: 'Subject',
required: false,
}),
mailboxId: mailboxIdDropdown(false),
status: Property.StaticDropdown({
displayName: 'Status',
required: false,
options: {
options: [
{ label: 'Active', value: 'active' },
{ label: 'Open', value: 'open' },
{ label: 'Closed', value: 'closed' },
{ label: 'Pending', value: 'pending' },
{ label: 'Spam', value: 'spam' },
{ label: 'All', value: 'all' },
],
},
}),
assignTo: userIdDropdown('Assigned User'),
email: Property.ShortText({
displayName: 'Email',
required: false,
}),
tags: Property.Array({
displayName: 'Tags',
required: false,
}),
query: Property.ShortText({
displayName: 'Custom Query',
required: false,
}),
},
async run({ auth, propsValue }) {
if (
!propsValue.query &&
!propsValue.mailboxId &&
!propsValue.status &&
!propsValue.tags &&
!propsValue.assignTo &&
!propsValue.subject &&
!propsValue.email
) {
throw new Error('At least one search parameter must be provided.');
}
if (propsValue.tags) {
const uniqueTags = new Set(propsValue.tags);
if (uniqueTags.size !== propsValue.tags.length) {
throw new Error('Tags must be unique.');
}
}
const query = [];
if (propsValue.subject) query.push(`subject:"${propsValue.subject}"`);
if (propsValue.email) query.push(`email:"${propsValue.email}"`);
if (propsValue.query) query.push(propsValue.query);
const queryParams: Record<string, any> = {};
if (propsValue.mailboxId) queryParams['mailbox'] = propsValue.mailboxId;
if (propsValue.status) queryParams['status'] = propsValue.status;
if (propsValue.tags) queryParams['tags'] = propsValue.tags.join(',');
if (propsValue.assignTo) queryParams['assigned_to'] = propsValue.assignTo;
if (query.length > 0) {
queryParams['query'] = `(${query.join(' AND ')})`;
}
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/conversations',
auth,
queryParams,
});
const { _embedded } = response.body as {
_embedded: {
conversations: { id: number; subject: string }[];
};
};
return {
found: _embedded.conversations.length > 0,
data:
_embedded.conversations.length > 0 ? _embedded.conversations[0] : {},
};
},
});

View File

@@ -0,0 +1,42 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { propsValidation } from '@activepieces/pieces-common';
import { z } from 'zod';
import { HttpMethod } from '@activepieces/pieces-common';
export const findCustomer = createAction({
auth: helpScoutAuth,
name: 'find_customer',
displayName: 'Find Customer',
description: 'Finds a customer by email.',
props: {
email: Property.ShortText({
displayName: 'Email',
required: true,
}),
},
async run({ auth, propsValue }) {
await propsValidation.validateZod(propsValue, {
email: z.string().min(1, 'Please provide a email.'),
});
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: `/customers`,
auth,
queryParams: {
query: `(email:"${propsValue.email}")`,
},
});
const { _embedded } = response.body as {
_embedded: {
customers: { id: number; firstName: string; lastName: string }[];
};
};
return {
found: _embedded.customers.length > 0,
data: _embedded.customers.length > 0 ? _embedded.customers[0] : {},
};
},
});

View File

@@ -0,0 +1,40 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { propsValidation } from '@activepieces/pieces-common';
import { z } from 'zod';
import { HttpMethod } from '@activepieces/pieces-common';
export const findUser = createAction({
auth: helpScoutAuth,
name: 'find_user',
displayName: 'Find User',
description: 'Finds a user by email.',
props: {
email: Property.ShortText({
displayName: 'Email',
required: true,
}),
},
async run({ auth, propsValue }) {
await propsValidation.validateZod(propsValue, {
email: z.string().min(1, 'Please provide a valid email.'),
});
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: `/users?email=${propsValue.email}`,
auth,
});
const { _embedded } = response.body as {
_embedded: {
users: { id: number; firstName: string; lastName: string }[];
};
};
return {
found: _embedded.users.length > 0,
data: _embedded.users.length > 0 ? _embedded.users[0] : {},
};
},
});

View File

@@ -0,0 +1,76 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { conversationIdDropdown, userIdDropdown } from '../common/props';
export const sendReply = createAction({
auth: helpScoutAuth,
name: 'send_reply',
displayName: 'Send Reply',
description: 'Sends a reply in an existing conversation.',
props: {
conversationId: conversationIdDropdown,
text: Property.LongText({
displayName: 'Reply Text',
required: true,
}),
customerEmail: Property.ShortText({
displayName: 'Customer Email',
required: true,
}),
draft: Property.Checkbox({
displayName: 'Draft',
required: false,
}),
status: Property.StaticDropdown({
displayName: 'Conversation Status',
required: false,
options: {
options: [
{ label: 'Active', value: 'active' },
{ label: 'Pending', value: 'pending' },
{ label: 'Closed', value: 'closed' },
{ label: 'Spam', value: 'spam' },
],
},
}),
userId: userIdDropdown('User (who adds the reply)'),
cc: Property.Array({
displayName: 'CC (emails)',
required: false,
}),
bcc: Property.Array({
displayName: 'BCC (emails)',
required: false,
}),
},
async run({ auth, propsValue }) {
const payload: Record<string, any> = {
text: propsValue.text,
customer: { email: propsValue.customerEmail },
draft: propsValue.draft,
status: propsValue.status,
user: propsValue.userId,
cc: propsValue.cc,
bcc: propsValue.bcc,
};
Object.keys(payload).forEach((key) => {
if (payload[key] === undefined || payload[key] === null) {
delete payload[key];
}
});
const response = await helpScoutApiRequest({
method: HttpMethod.POST,
url: `/conversations/${propsValue.conversationId}/reply`,
auth,
body: payload,
});
const replyId = response.headers?.['resource-id'];
return {
id:replyId
}
},
});

View File

@@ -0,0 +1,41 @@
import { createAction } from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from '../common/api';
import { helpScoutAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { customerIdDropdown, customerProperties } from '../common/props';
import { isNil } from '@activepieces/shared';
import { HttpStatusCode } from 'axios';
export const updateCustomerProperties = createAction({
auth: helpScoutAuth,
name: 'update_customer_properties',
displayName: 'Update Customer Properties',
description: `Updates customer's properties.`,
props: {
customerId: customerIdDropdown,
fields: customerProperties,
},
async run({ auth, propsValue }) {
const { customerId } = propsValue;
const fields = propsValue.fields ?? {};
const updates = [];
for (const [key, value] of Object.entries(fields)) {
if (isNil(value) || value === '') continue;
updates.push({ op: 'replace', value: value, path: `/${key}` });
}
const response = await helpScoutApiRequest({
method: HttpMethod.PATCH,
url: `/customers/${customerId}/properties`,
auth,
body: updates,
});
return {
success: response.status === HttpStatusCode.NoContent ? true : false,
};
},
});

View File

@@ -0,0 +1,71 @@
import {
HttpRequest,
HttpMethod,
httpClient,
HttpError,
} from '@activepieces/pieces-common';
import crypto from 'crypto';
export const BASE_URL = 'https://api.helpscout.net/v2';
function getErrorMessage(error: any): string {
if (error?.response?.body?.message) return error.response.body.message;
if (error?.response?.body?.error) return error.response.body.error;
if (error?.message) return error.message;
return 'Unknown error occurred';
}
export async function helpScoutApiRequest(params: {
method: HttpMethod;
url: string;
auth: any;
body?: any;
queryParams?: Record<string, any>;
}) {
try {
const request: HttpRequest = {
method: params.method,
url: `${BASE_URL}${params.url}`,
headers: {
Authorization: `Bearer ${params.auth.access_token}`,
'Content-Type': 'application/json',
},
body: params.body,
queryParams: params.queryParams,
};
const response = await httpClient.sendRequest(request);
if (response.status >= 200 && response.status < 300) {
return response;
} else {
const errorMsg = getErrorMessage(response.body);
throw new Error(`Help Scout API Error (${response.status}): ${errorMsg}`);
}
} catch (error: any) {
console.error('Help Scout API Error:', error);
throw new Error(getErrorMessage(error));
}
}
export function verifyWebhookSignature(
webhookSecret?: string,
webhookSignatureHeader?: string,
webhookRawBody?: any,
): boolean {
if (!webhookSecret || !webhookSignatureHeader || !webhookRawBody) {
return false;
}
try {
const hmac = crypto.createHmac('sha1', webhookSecret);
hmac.update(webhookRawBody);
const expectedSignature = hmac.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(webhookSignatureHeader, 'hex'),
Buffer.from(expectedSignature, 'hex'),
);
} catch (error) {
return false;
}
}

View File

@@ -0,0 +1,13 @@
import { PieceAuth } from '@activepieces/pieces-framework';
export const helpScoutAuth = PieceAuth.OAuth2({
description: `
1. Click on your profile icon at the top right and select **Your Profile**.
2. Go to **My Apps** and click on **Create App**.
3. Provide **App Name** and use below redirect URL.
4. Copy the **App ID** and **App Secret**, and provide them as the **Client ID** and **Client Secret**, respectively.`,
authUrl: 'https://secure.helpscout.net/authentication/authorizeClientApplication',
tokenUrl: 'https://api.helpscout.net/v2/oauth2/token',
required: true,
scope:[]
});

View File

@@ -0,0 +1,231 @@
import {
DynamicPropsValue,
OAuth2PropertyValue,
Property,
} from '@activepieces/pieces-framework';
import { helpScoutApiRequest } from './api';
import { HttpMethod } from '@activepieces/pieces-common';
import { helpScoutAuth } from './auth';
export const customerIdDropdown = Property.Dropdown({
displayName: 'Customer',
refreshers: [],
auth: helpScoutAuth,
required: true,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: false,
options: [],
placeholder: 'Please connect your account first.',
};
}
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/customers',
auth: auth,
});
const { _embedded } = response.body as {
_embedded: {
customers: { id: number; firstName: string; lastName: string }[];
};
};
return {
disabled: false,
options: _embedded.customers.map((customer) => {
return {
label: `${customer.firstName} ${customer.lastName}`,
value: customer.id.toString(),
};
}),
};
},
});
export const userIdDropdown =(displayName:string)=> Property.Dropdown({
displayName,
refreshers: [],
auth: helpScoutAuth,
required: false,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: false,
options: [],
placeholder: 'Please connect your account first.',
};
}
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/users',
auth: auth,
});
const { _embedded } = response.body as {
_embedded: {
users: { id: number; firstName: string; lastName: string }[];
};
};
return {
disabled: false,
options: _embedded.users.map((user) => {
return {
label: `${user.firstName ?? ""} ${user.lastName ?? ""}` || user.id.toString(),
value: user.id.toString(),
};
}),
};
},
});
export const conversationIdDropdown = Property.Dropdown({
displayName:'Conversation',
refreshers: [],
required: false,
auth: helpScoutAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: false,
options: [],
placeholder: 'Please connect your account first.',
};
}
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/conversations',
auth: auth,
});
const { _embedded } = response.body as {
_embedded: {
conversations: { id: number; subject: string,primaryCustomer:{email:string} }[];
};
};
return {
disabled: false,
options: _embedded.conversations.map((convo) => {
return {
label: `${convo.subject} - ${convo.primaryCustomer.email}`,
value: convo.id.toString(),
};
}),
};
},
});
export const mailboxIdDropdown =(required=true)=> Property.Dropdown({
displayName: 'Mailbox',
refreshers: [],
required,
auth: helpScoutAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: false,
options: [],
placeholder: 'Please connect your account first.',
};
}
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/mailboxes ',
auth: auth,
});
const { _embedded } = response.body as {
_embedded: {
mailboxes : { id: number; name: string }[];
};
};
return {
disabled: false,
options: _embedded.mailboxes .map((mailbox) => {
return {
label: mailbox.name,
value: mailbox.id.toString(),
};
}),
};
},
});
export const customerProperties = Property.DynamicProperties({
displayName: 'Customer Properties',
refreshers: [],
required: true,
auth: helpScoutAuth,
props: async ({ auth }) => {
if (!auth) return {};
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/customer-properties',
auth: auth,
});
const { _embedded } = response.body as {
_embedded: {
'customer-properties': {
type: string;
slug: string;
name: string;
options: { id: string; label: string }[];
}[];
};
};
const props: DynamicPropsValue = {};
for (const field of _embedded['customer-properties']) {
switch (field.type) {
case 'text':
case 'url':
props[field.slug] = Property.ShortText({
displayName: field.name,
required: false,
});
break;
case 'number':
props[field.slug] = Property.Number({
displayName: field.name,
required: false,
});
break;
case 'date':
props[field.slug] = Property.ShortText({
displayName: field.name,
description: 'Provide date in YYYY-MM-DD format.',
required: false,
});
break;
case 'dropdown':
props[field.slug] = Property.StaticDropdown({
displayName: field.name,
required: false,
options: {
disabled: false,
options: field.options.map((option) => ({
label: option.label,
value: option.label,
})),
},
});
}
}
return props;
},
});

View File

@@ -0,0 +1,102 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { helpScoutAuth } from '../common/auth';
import { helpScoutApiRequest, verifyWebhookSignature } from '../common/api';
import { HttpMethod } from '@activepieces/pieces-common';
import crypto from 'crypto';
import { mailboxIdDropdown, userIdDropdown } from '../common/props';
const WEBHOOK_KEY = 'helpscout_conversation-assigned';
export const conversationAssigned = createTrigger({
auth: helpScoutAuth,
name: 'conversation_assigned',
displayName: 'Conversation Assigned',
description: 'Triggers when a conversation is assigned to a user.',
type: TriggerStrategy.WEBHOOK,
props: {
mailboxId: mailboxIdDropdown(true),
assignedTo: userIdDropdown('Assigned User'),
},
sampleData: {},
async onEnable(context) {
const secret = crypto.randomBytes(20).toString('hex');
const response = await helpScoutApiRequest({
auth: context.auth,
method: HttpMethod.POST,
url: '/webhooks',
body: {
url: context.webhookUrl,
events: ['convo.assigned'],
secret,
mailboxIds: [context.propsValue.mailboxId],
},
});
const webhookId = response.headers?.['resource-id'] as string;
await context.store.put<{ webhookId: string; WebhookSecret: string }>(
WEBHOOK_KEY,
{ webhookId: webhookId, WebhookSecret: secret }
);
},
async onDisable(context) {
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
if (webhookData?.webhookId) {
await helpScoutApiRequest({
method: HttpMethod.DELETE,
url: `/webhooks/${webhookData.webhookId}`,
auth: context.auth,
});
}
},
async run(context) {
const { assignedTo } = context.propsValue;
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
const webhookSecret = webhookData?.WebhookSecret;
const webhookSignatureHeader =
context.payload.headers['x-helpscout-signature'];
const rawBody = context.payload.rawBody;
if (
!verifyWebhookSignature(webhookSecret, webhookSignatureHeader, rawBody)
) {
return [];
}
const payload = context.payload.body as { assignee: { id: number } };
if (assignedTo && payload.assignee.id.toString() !== assignedTo) return [];
return [context.payload.body];
},
async test(context) {
const { mailboxId, assignedTo } = context.propsValue;
const queryParams: Record<string, any> = {embed:'threads'};
if (mailboxId) queryParams['mailbox'] = mailboxId;
if (assignedTo) queryParams['assigned_to'] = assignedTo;
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/conversations',
auth: context.auth,
queryParams,
});
const { _embedded } = response.body as {
_embedded: {
conversations: { id: number; subject: string }[];
};
};
return _embedded.conversations;
},
});

View File

@@ -0,0 +1,102 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { helpScoutAuth } from '../common/auth';
import { mailboxIdDropdown, userIdDropdown } from '../common/props';
import crypto from 'crypto';
import { helpScoutApiRequest, verifyWebhookSignature } from '../common/api';
import { HttpMethod } from '@activepieces/pieces-common';
const WEBHOOK_KEY = 'helpscout_conversation_created';
export const conversationCreated = createTrigger({
auth: helpScoutAuth,
name: 'conversation_created',
displayName: 'Conversation Created',
description: 'Triggers when a new conversation is started in a mailbox.',
type: TriggerStrategy.WEBHOOK,
props: {
mailboxId: mailboxIdDropdown(true),
assignedTo: userIdDropdown('Assigned User'),
},
sampleData: {},
async onEnable(context) {
const secret = crypto.randomBytes(20).toString('hex');
const response = await helpScoutApiRequest({
auth: context.auth,
method: HttpMethod.POST,
url: '/webhooks',
body: {
url: context.webhookUrl,
events: ['convo.created'],
secret,
mailboxIds: [context.propsValue.mailboxId],
},
});
const webhookId = response.headers?.['resource-id'] as string;
await context.store.put<{ webhookId: string; WebhookSecret: string }>(
WEBHOOK_KEY,
{ webhookId: webhookId, WebhookSecret: secret }
);
},
async onDisable(context) {
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
if (webhookData?.webhookId) {
await helpScoutApiRequest({
method: HttpMethod.DELETE,
url: `/webhooks/${webhookData.webhookId}`,
auth: context.auth,
});
}
},
async run(context) {
const { assignedTo } = context.propsValue;
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
const webhookSecret = webhookData?.WebhookSecret;
const webhookSignatureHeader =
context.payload.headers['x-helpscout-signature'];
const rawBody = context.payload.rawBody;
if (
!verifyWebhookSignature(webhookSecret, webhookSignatureHeader, rawBody)
) {
return [];
}
const payload = context.payload.body as { assignee: { id: number } };
if (assignedTo && payload.assignee.id.toString() !== assignedTo) return [];
return [context.payload.body];
},
async test(context) {
const { mailboxId, assignedTo } = context.propsValue;
const queryParams: Record<string, any> = { embed: 'threads' };
if (mailboxId) queryParams['mailbox'] = mailboxId;
if (assignedTo) queryParams['assigned_to'] = assignedTo;
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/conversations',
auth: context.auth,
queryParams,
});
const { _embedded } = response.body as {
_embedded: {
conversations: { id: number; subject: string }[];
};
};
return _embedded.conversations;
},
});

View File

@@ -0,0 +1,85 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { helpScoutAuth } from '../common/auth';
import crypto from 'crypto';
import { helpScoutApiRequest, verifyWebhookSignature } from '../common/api';
import { HttpMethod } from '@activepieces/pieces-common';
const WEBHOOK_KEY = 'helpscout_new_customer';
export const newCustomer = createTrigger({
auth: helpScoutAuth,
name: 'new_customer',
displayName: 'New Customer',
description: 'Triggers when a new customer is added.',
type: TriggerStrategy.WEBHOOK,
props: {},
sampleData: {},
async onEnable(context) {
const secret = crypto.randomBytes(20).toString('hex');
const response = await helpScoutApiRequest({
auth: context.auth,
method: HttpMethod.POST,
url: '/webhooks',
body: {
url: context.webhookUrl,
events: ['customer.created'],
secret,
},
});
const webhookId = response.headers?.['resource-id'] as string;
await context.store.put<{ webhookId: string; WebhookSecret: string }>(
WEBHOOK_KEY,
{ webhookId: webhookId, WebhookSecret: secret }
);
},
async onDisable(context) {
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
if (webhookData?.webhookId) {
await helpScoutApiRequest({
method: HttpMethod.DELETE,
url: `/webhooks/${webhookData.webhookId}`,
auth: context.auth,
});
}
},
async run(context) {
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
const webhookSecret = webhookData?.WebhookSecret;
const webhookSignatureHeader =
context.payload.headers['x-helpscout-signature'];
const rawBody = context.payload.rawBody;
if (
!verifyWebhookSignature(webhookSecret, webhookSignatureHeader, rawBody)
) {
return [];
}
return [context.payload.body];
},
async test(context) {
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/customers ',
auth: context.auth,
});
const { _embedded } = response.body as {
_embedded: {
customers: { id: number }[];
};
};
return _embedded.customers;
},
});

View File

@@ -0,0 +1,102 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { helpScoutAuth } from '../common/auth';
import crypto from 'crypto';
import { helpScoutApiRequest, verifyWebhookSignature } from '../common/api';
import { HttpMethod } from '@activepieces/pieces-common';
import { mailboxIdDropdown, userIdDropdown } from '../common/props';
const WEBHOOK_KEY = 'helpscout_tags_updated';
export const tagsUpdated = createTrigger({
auth: helpScoutAuth,
name: 'tags_updated',
displayName: 'Tags Updated',
description: 'Triggers when tags on a conversation are modified.',
type: TriggerStrategy.WEBHOOK,
props: {
mailboxId: mailboxIdDropdown(true),
assignedTo: userIdDropdown('Assigned User'),
},
sampleData: {},
async onEnable(context) {
const secret = crypto.randomBytes(20).toString('hex');
const response = await helpScoutApiRequest({
auth: context.auth,
method: HttpMethod.POST,
url: '/webhooks',
body: {
url: context.webhookUrl,
events: ['convo.tags'],
secret,
mailboxIds: [context.propsValue.mailboxId],
},
});
const webhookId = response.headers?.['resource-id'] as string;
await context.store.put<{ webhookId: string; WebhookSecret: string }>(
WEBHOOK_KEY,
{ webhookId: webhookId, WebhookSecret: secret }
);
},
async onDisable(context) {
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
if (webhookData?.webhookId) {
await helpScoutApiRequest({
method: HttpMethod.DELETE,
url: `/webhooks/${webhookData.webhookId}`,
auth: context.auth,
});
}
},
async run(context) {
const { assignedTo } = context.propsValue;
const webhookData = await context.store.get<{
webhookId: string;
WebhookSecret: string;
}>(WEBHOOK_KEY);
const webhookSecret = webhookData?.WebhookSecret;
const webhookSignatureHeader =
context.payload.headers['x-helpscout-signature'];
const rawBody = context.payload.rawBody;
if (
!verifyWebhookSignature(webhookSecret, webhookSignatureHeader, rawBody)
) {
return [];
}
const payload = context.payload.body as { assignee: { id: number } };
if (assignedTo && payload.assignee.id.toString() !== assignedTo) return [];
return [context.payload.body];
},
async test(context) {
const { mailboxId, assignedTo } = context.propsValue;
const queryParams: Record<string, any> = { embed: 'threads' };
if (mailboxId) queryParams['mailbox'] = mailboxId;
if (assignedTo) queryParams['assigned_to'] = assignedTo;
const response = await helpScoutApiRequest({
method: HttpMethod.GET,
url: '/conversations',
auth: context.auth,
queryParams,
});
const { _embedded } = response.body as {
_embedded: {
conversations: { id: number; subject: string }[];
};
};
return _embedded.conversations;
},
});

View File

@@ -0,0 +1,20 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}