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:
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Vertriebsautomatisierung und CRM-Integration für Schließen",
|
||||
"Your Close CRM API key for authentication.": "Ihr Schließen CRM API Schlüssel für die Authentifizierung.",
|
||||
"Create Lead": "Lead erstellen",
|
||||
"Create Contact": "Kontakt erstellen",
|
||||
"Find Lead": "Lead finden",
|
||||
"Create Opportunity": "Verkaufschance erstellen",
|
||||
"Find Contact": "Kontakt finden",
|
||||
"Custom API Call": "Eigener API-Aufruf",
|
||||
"Creates a new lead.": "Erstellt einen neuen Vorsprung.",
|
||||
"Creates a new contact.": "Erstellt einen neuen Kontakt.",
|
||||
"Search for leads with advanced filtering options": "Suche nach Leads mit erweiterten Filteroptionen",
|
||||
"Create a new opportunity.": "Erstelle eine neue Chance.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Suche nach Kontakten nach Namen, E-Mail oder anderen Kriterien mit erweiterter Filterung",
|
||||
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
|
||||
"Lead Name": "Leadname",
|
||||
"URL": "URL",
|
||||
"Description": "Beschreibung",
|
||||
"Contacts": "Kontakte",
|
||||
"Status": "Status",
|
||||
"Custom Fields": "Eigene Felder",
|
||||
"Lead": "Lead",
|
||||
"Name": "Name",
|
||||
"Title": "Titel",
|
||||
"Office Phone": "Bürotelefon",
|
||||
"Mobile Phone": "Handy",
|
||||
"Home Phone": "Telefon privat",
|
||||
"Direct Phone": "Direktes Telefon",
|
||||
"Fax Phone": "Faxtelefon",
|
||||
"Other Phone": "Anderes Telefon",
|
||||
"Office Email": "Büro-E-Mail",
|
||||
"Home Email": "Home-E-Mail",
|
||||
"Direct Email": "Direkte E-Mail",
|
||||
"Other Email": "Andere E-Mail",
|
||||
"Search Type": "Suchtyp",
|
||||
"Search Query": "Suchanfrage",
|
||||
"Match Type": "Match-Typ",
|
||||
"Opportunity Name": "Opportunity Name",
|
||||
"Notes": "Notizen",
|
||||
"Confidence %": "Vertrauen %",
|
||||
"Value": "Wert",
|
||||
"Value Period": "Wertezeitraum",
|
||||
"Contact ID": "Kontakt-ID",
|
||||
"User": "Benutzer",
|
||||
"Method": "Methode",
|
||||
"Headers": "Kopfzeilen",
|
||||
"Query Parameters": "Abfrageparameter",
|
||||
"Body": "Körper",
|
||||
"Response is Binary ?": "Antwort ist binär?",
|
||||
"No Error on Failure": "Kein Fehler bei Fehler",
|
||||
"Timeout (in seconds)": "Timeout (in Sekunden)",
|
||||
"The name of the lead/company.": "Der Name der Blei/Firma.",
|
||||
"Array of contact details for this lead": "Anordnung der Kontaktdaten für diesen Lead",
|
||||
"A descriptive name for the opportunity.": "Ein beschreibender Name für die Gelegenheit.",
|
||||
"Additional details about the opportunity.": "Weitere Details zur Chance.",
|
||||
"The probability of winning this opportunity (0-100).": "Die Wahrscheinlichkeit, diese Chance zu gewinnen (0-100).",
|
||||
"The period for the opportunity value.": "Der Zeitraum für den Opportunitätswert.",
|
||||
"The ID of the contact associated with this opportunity.": "Die ID des Kontakts, der mit dieser Möglichkeit verbunden ist.",
|
||||
"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..",
|
||||
"By Name": "Nach Name",
|
||||
"By Contact Email": "Per Kontakt E-Mail",
|
||||
"By Status": "Nach Status",
|
||||
"Contains": "Enthält",
|
||||
"Exact Match": "Genaues Match",
|
||||
"Starts With": "Beginnt mit",
|
||||
"Ends With": "Endet mit",
|
||||
"One-Time": "Einmal",
|
||||
"Monthly": "Monatlich",
|
||||
"Annual": "Jährlich",
|
||||
"By Email": "Per E-Mail",
|
||||
"By Phone": "Per Telefon",
|
||||
"By Lead ID": "Nach Lead-ID",
|
||||
"GET": "ERHALTEN",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "LÖSCHEN",
|
||||
"HEAD": "HEAD",
|
||||
"New Lead Created": "Neuer Lead erstellt",
|
||||
"New Contact Added": "Neuer Kontakt hinzugefügt",
|
||||
"New Opportunity Added": "Neue Chance hinzugefügt",
|
||||
"Triggers when a new lead is created.": "Wird ausgelöst, wenn ein neuer Lead erstellt wird.",
|
||||
"Triggers when a new contact is created.": "Wird ausgelöst, wenn ein neuer Kontakt erstellt wird.",
|
||||
"Triggers when a new opportunity is created.": "Wird ausgelöst, wenn eine neue Chance geschaffen wird."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Automatización de ventas e integración CRM para cerrar",
|
||||
"Your Close CRM API key for authentication.": "Su clave API de cierre para autenticación.",
|
||||
"Create Lead": "Crear plomo",
|
||||
"Create Contact": "Crear contacto",
|
||||
"Find Lead": "Buscar plomo",
|
||||
"Create Opportunity": "Crear Oportunidad",
|
||||
"Find Contact": "Encontrar contacto",
|
||||
"Custom API Call": "Llamada API personalizada",
|
||||
"Creates a new lead.": "Crea un nuevo cliente potencial.",
|
||||
"Creates a new contact.": "Crea un nuevo contacto.",
|
||||
"Search for leads with advanced filtering options": "Buscar clientes potenciales con opciones avanzadas de filtrado",
|
||||
"Create a new opportunity.": "Crear una nueva oportunidad.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Buscar contactos por nombre, correo electrónico u otros criterios con filtrado avanzado",
|
||||
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
|
||||
"Lead Name": "Nombre del jefe",
|
||||
"URL": "URL",
|
||||
"Description": "Descripción",
|
||||
"Contacts": "Contactos",
|
||||
"Status": "Estado",
|
||||
"Custom Fields": "Campos personalizados",
|
||||
"Lead": "Plomo",
|
||||
"Name": "Nombre",
|
||||
"Title": "Título",
|
||||
"Office Phone": "Teléfono de oficina",
|
||||
"Mobile Phone": "Teléfono móvil",
|
||||
"Home Phone": "Teléfono",
|
||||
"Direct Phone": "Teléfono directo",
|
||||
"Fax Phone": "Teléfono fax",
|
||||
"Other Phone": "Otro teléfono",
|
||||
"Office Email": "Email de oficina",
|
||||
"Home Email": "Email de inicio",
|
||||
"Direct Email": "Email directo",
|
||||
"Other Email": "Otro Email",
|
||||
"Search Type": "Tipo de búsqueda",
|
||||
"Search Query": "Buscar consulta",
|
||||
"Match Type": "Tipo de partida",
|
||||
"Opportunity Name": "Nombre de la oportunidad",
|
||||
"Notes": "Notas",
|
||||
"Confidence %": "% de confianza",
|
||||
"Value": "Valor",
|
||||
"Value Period": "Valor del período",
|
||||
"Contact ID": "ID de contacto",
|
||||
"User": "Usuario",
|
||||
"Method": "Método",
|
||||
"Headers": "Encabezados",
|
||||
"Query Parameters": "Parámetros de consulta",
|
||||
"Body": "Cuerpo",
|
||||
"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)",
|
||||
"The name of the lead/company.": "El nombre de la lead/empresa.",
|
||||
"Array of contact details for this lead": "Arreglo de datos de contacto para este cliente",
|
||||
"A descriptive name for the opportunity.": "Un nombre descriptivo para la oportunidad.",
|
||||
"Additional details about the opportunity.": "Más detalles sobre la oportunidad.",
|
||||
"The probability of winning this opportunity (0-100).": "La probabilidad de ganar esta oportunidad (0-100).",
|
||||
"The period for the opportunity value.": "El período para el valor de la oportunidad.",
|
||||
"The ID of the contact associated with this opportunity.": "El ID del contacto asociado con esta oportunidad.",
|
||||
"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.",
|
||||
"By Name": "Por nombre",
|
||||
"By Contact Email": "Por Email de Contacto",
|
||||
"By Status": "Por Estado",
|
||||
"Contains": "Contiene",
|
||||
"Exact Match": "Partida exacta",
|
||||
"Starts With": "Comienza por",
|
||||
"Ends With": "Termina con",
|
||||
"One-Time": "Una vez",
|
||||
"Monthly": "Mensual",
|
||||
"Annual": "Anual",
|
||||
"By Email": "Por Email",
|
||||
"By Phone": "Por teléfono",
|
||||
"By Lead ID": "Por ID de plomo",
|
||||
"GET": "RECOGER",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "BORRAR",
|
||||
"HEAD": "LIMPIO",
|
||||
"New Lead Created": "Nuevo plomo creado",
|
||||
"New Contact Added": "Nuevo contacto añadido",
|
||||
"New Opportunity Added": "Nueva oportunidad añadida",
|
||||
"Triggers when a new lead is created.": "Dispara cuando se crea un nuevo plomo.",
|
||||
"Triggers when a new contact is created.": "Dispara cuando se crea un nuevo contacto.",
|
||||
"Triggers when a new opportunity is created.": "Dispara cuando se crea una nueva oportunidad."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Automatisation des ventes et intégration CRM pour la fermeture",
|
||||
"Your Close CRM API key for authentication.": "Fermer la clé d'API CRM pour l'authentification.",
|
||||
"Create Lead": "Créer Prospect",
|
||||
"Create Contact": "Créer un contact",
|
||||
"Find Lead": "Trouver un prospect",
|
||||
"Create Opportunity": "Créer une Affaire",
|
||||
"Find Contact": "Trouver un contact",
|
||||
"Custom API Call": "Appel API personnalisé",
|
||||
"Creates a new lead.": "Crée un nouveau prospect.",
|
||||
"Creates a new contact.": "Crée un nouveau contact.",
|
||||
"Search for leads with advanced filtering options": "Rechercher des prospects avec des options de filtrage avancées",
|
||||
"Create a new opportunity.": "Créer une nouvelle opportunité.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Rechercher des contacts par nom, e-mail ou autres critères de filtrage avancé",
|
||||
"Make a custom API call to a specific endpoint": "Passez un appel API personnalisé à un point de terminaison spécifique",
|
||||
"Lead Name": "Nom du prospect",
|
||||
"URL": "URL",
|
||||
"Description": "Libellé",
|
||||
"Contacts": "Contacts",
|
||||
"Status": "Statut",
|
||||
"Custom Fields": "Champs personnalisés",
|
||||
"Lead": "Prospect",
|
||||
"Name": "Nom",
|
||||
"Title": "Titre de la page",
|
||||
"Office Phone": "Téléphone de bureau",
|
||||
"Mobile Phone": "Téléphone mobile",
|
||||
"Home Phone": "Téléphone de la maison",
|
||||
"Direct Phone": "Téléphone direct",
|
||||
"Fax Phone": "Téléphone Fax",
|
||||
"Other Phone": "Autre téléphone",
|
||||
"Office Email": "E-mail du bureau",
|
||||
"Home Email": "E-mail de la maison",
|
||||
"Direct Email": "E-mail direct",
|
||||
"Other Email": "Autre Email",
|
||||
"Search Type": "Type de recherche",
|
||||
"Search Query": "Requête de recherche",
|
||||
"Match Type": "Type de correspondance",
|
||||
"Opportunity Name": "Nom de l'opportunité",
|
||||
"Notes": "Notes",
|
||||
"Confidence %": "% de confiance",
|
||||
"Value": "Valeur",
|
||||
"Value Period": "Période de valeur",
|
||||
"Contact ID": "ID du contact",
|
||||
"User": "Utilisateur",
|
||||
"Method": "Méthode",
|
||||
"Headers": "En-têtes",
|
||||
"Query Parameters": "Paramètres de requête",
|
||||
"Body": "Corps",
|
||||
"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)",
|
||||
"The name of the lead/company.": "Le nom du plomb/de la société.",
|
||||
"Array of contact details for this lead": "Tableau des coordonnées pour ce prospect",
|
||||
"A descriptive name for the opportunity.": "Un nom descriptif pour l'opportunité.",
|
||||
"Additional details about the opportunity.": "Plus de détails sur l'opportunité.",
|
||||
"The probability of winning this opportunity (0-100).": "La probabilité de gagner cette opportunité (0-100).",
|
||||
"The period for the opportunity value.": "La période pour la valeur de l'opportunité.",
|
||||
"The ID of the contact associated with this opportunity.": "L'ID du contact associé à cette opportunité.",
|
||||
"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.",
|
||||
"By Name": "Par nom",
|
||||
"By Contact Email": "Par e-mail de contact",
|
||||
"By Status": "Par statut",
|
||||
"Contains": "Contient",
|
||||
"Exact Match": "Correspondance exacte",
|
||||
"Starts With": "Commence avec",
|
||||
"Ends With": "Se termine par",
|
||||
"One-Time": "Une fois",
|
||||
"Monthly": "Mensuel",
|
||||
"Annual": "Annuel",
|
||||
"By Email": "Par e-mail",
|
||||
"By Phone": "Par téléphone",
|
||||
"By Lead ID": "Par ID de prospect",
|
||||
"GET": "OBTENIR",
|
||||
"POST": "POSTER",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "EFFACER",
|
||||
"DELETE": "SUPPRIMER",
|
||||
"HEAD": "TÊTE",
|
||||
"New Lead Created": "Nouveau prospect créé",
|
||||
"New Contact Added": "Nouveau contact ajouté",
|
||||
"New Opportunity Added": "Nouvelle opportunité ajoutée",
|
||||
"Triggers when a new lead is created.": "Déclenche lorsqu'un nouveau prospect est créé.",
|
||||
"Triggers when a new contact is created.": "Déclenche lorsqu'un nouveau contact est créé.",
|
||||
"Triggers when a new opportunity is created.": "Déclenche quand une nouvelle opportunité est créée."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "閉じるためのセールスオートメーションとCRM統合",
|
||||
"Your Close CRM API key for authentication.": "認証のためにCRMを閉じるAPIキー",
|
||||
"Create Lead": "リードを作成",
|
||||
"Create Contact": "連絡先を作成",
|
||||
"Find Lead": "リードを見つける",
|
||||
"Create Opportunity": "案件を作成",
|
||||
"Find Contact": "連絡先を探す",
|
||||
"Custom API Call": "カスタムAPI通話",
|
||||
"Creates a new lead.": "新しいリードを作成します。",
|
||||
"Creates a new contact.": "新しい連絡先を作成します。",
|
||||
"Search for leads with advanced filtering options": "高度なフィルタリングオプションでリードを検索",
|
||||
"Create a new opportunity.": "新しい機会を作りましょう。",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "詳細なフィルタリングで名前、電子メール、またはその他の条件で連絡先を検索します",
|
||||
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
|
||||
"Lead Name": "リード名",
|
||||
"URL": "URL",
|
||||
"Description": "説明",
|
||||
"Contacts": "連絡先",
|
||||
"Status": "ステータス",
|
||||
"Custom Fields": "カスタムフィールド",
|
||||
"Lead": "リード",
|
||||
"Name": "名前",
|
||||
"Title": "タイトル",
|
||||
"Office Phone": "勤務先電話番号",
|
||||
"Mobile Phone": "携帯電話",
|
||||
"Home Phone": "自宅電話",
|
||||
"Direct Phone": "直接電話",
|
||||
"Fax Phone": "FAX電話",
|
||||
"Other Phone": "その他の電話",
|
||||
"Office Email": "オフィスのメールアドレス",
|
||||
"Home Email": "ホームメール",
|
||||
"Direct Email": "ダイレクトメール",
|
||||
"Other Email": "その他のメール",
|
||||
"Search Type": "検索タイプ",
|
||||
"Search Query": "検索クエリ",
|
||||
"Match Type": "一致するタイプ",
|
||||
"Opportunity Name": "商談名",
|
||||
"Notes": "メモ",
|
||||
"Confidence %": "自信度%",
|
||||
"Value": "値",
|
||||
"Value Period": "値の期間",
|
||||
"Contact ID": "連絡先ID",
|
||||
"User": "ユーザー",
|
||||
"Method": "方法",
|
||||
"Headers": "ヘッダー",
|
||||
"Query Parameters": "クエリパラメータ",
|
||||
"Body": "本文",
|
||||
"Response is Binary ?": "応答はバイナリですか?",
|
||||
"No Error on Failure": "失敗時にエラーはありません",
|
||||
"Timeout (in seconds)": "タイムアウト(秒)",
|
||||
"The name of the lead/company.": "リード/会社の名前。",
|
||||
"Array of contact details for this lead": "このリードの連絡先詳細の配列",
|
||||
"A descriptive name for the opportunity.": "機会の説明的な名前。",
|
||||
"Additional details about the opportunity.": "機会に関する追加の詳細。",
|
||||
"The probability of winning this opportunity (0-100).": "この機会に勝つ確率(0-100)。",
|
||||
"The period for the opportunity value.": "商談値の期間。",
|
||||
"The ID of the contact associated with this opportunity.": "この商談に関連付けられている連絡先のID。",
|
||||
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
|
||||
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
|
||||
"By Name": "名前順",
|
||||
"By Contact Email": "連絡先のメールアドレスによって",
|
||||
"By Status": "ステータス順",
|
||||
"Contains": "以下を含む",
|
||||
"Exact Match": "完全一致",
|
||||
"Starts With": "で始まる",
|
||||
"Ends With": "で終了",
|
||||
"One-Time": "ワンタイム",
|
||||
"Monthly": "月ごと",
|
||||
"Annual": "年間",
|
||||
"By Email": "メール順",
|
||||
"By Phone": "電話",
|
||||
"By Lead ID": "見込み客ID",
|
||||
"GET": "取得",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "削除",
|
||||
"HEAD": "頭",
|
||||
"New Lead Created": "新しいリードが作成されました",
|
||||
"New Contact Added": "新しい連絡先が追加されました",
|
||||
"New Opportunity Added": "新しい商談が追加されました",
|
||||
"Triggers when a new lead is created.": "新しいリードが作成されたときにトリガーします。",
|
||||
"Triggers when a new contact is created.": "新しい連絡先が作成されたときにトリガーします.",
|
||||
"Triggers when a new opportunity is created.": "新しい商談が作成されたときにトリガーします。"
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Verkoopautomatisering en CRM-integratie voor sluiten",
|
||||
"Your Close CRM API key for authentication.": "Uw SluitCRM API-sleutel voor authenticatie.",
|
||||
"Create Lead": "Maak Lead",
|
||||
"Create Contact": "Contactpersoon aanmaken",
|
||||
"Find Lead": "Zoek Lead",
|
||||
"Create Opportunity": "Verkoopkans creëren",
|
||||
"Find Contact": "Contactpersoon zoeken",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Creates a new lead.": "Maakt een nieuwe lood.",
|
||||
"Creates a new contact.": "Maakt een nieuw contact aan.",
|
||||
"Search for leads with advanced filtering options": "Zoeken naar leads met geavanceerde filteropties",
|
||||
"Create a new opportunity.": "Maak een nieuwe kans.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Zoek naar contactpersonen op naam, e-mail of andere criteria met geavanceerde filtering",
|
||||
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
|
||||
"Lead Name": "Lead naam",
|
||||
"URL": "URL",
|
||||
"Description": "Beschrijving",
|
||||
"Contacts": "Contactpersonen",
|
||||
"Status": "status",
|
||||
"Custom Fields": "Aangepaste velden",
|
||||
"Lead": "Lood",
|
||||
"Name": "Naam",
|
||||
"Title": "Aanspreektitel",
|
||||
"Office Phone": "Telefoon Kantoor",
|
||||
"Mobile Phone": "Telefoon (mobiel)",
|
||||
"Home Phone": "Telefoon (thuis)",
|
||||
"Direct Phone": "Directe telefoon",
|
||||
"Fax Phone": "Fax Telefoon",
|
||||
"Other Phone": "Telefoon (over)",
|
||||
"Office Email": "Kantoor E-mail",
|
||||
"Home Email": "Thuis e-mail",
|
||||
"Direct Email": "Directe e-mail",
|
||||
"Other Email": "Andere E-mail",
|
||||
"Search Type": "Type zoeken",
|
||||
"Search Query": "Zoek query",
|
||||
"Match Type": "Wedstrijd Type",
|
||||
"Opportunity Name": "Verkoopkans naam",
|
||||
"Notes": "Opmerkingen",
|
||||
"Confidence %": "Vertrouwen %",
|
||||
"Value": "Waarde",
|
||||
"Value Period": "Waarde periode",
|
||||
"Contact ID": "Contact ID",
|
||||
"User": "Gebruiker",
|
||||
"Method": "Methode",
|
||||
"Headers": "Kopteksten",
|
||||
"Query Parameters": "Query parameters",
|
||||
"Body": "Lichaam",
|
||||
"Response is Binary ?": "Antwoord is binair?",
|
||||
"No Error on Failure": "Geen fout bij fout",
|
||||
"Timeout (in seconds)": "Time-out (in seconden)",
|
||||
"The name of the lead/company.": "De naam van het lead/bedrijf.",
|
||||
"Array of contact details for this lead": "Reeks van contactgegevens voor deze lead",
|
||||
"A descriptive name for the opportunity.": "Een beschrijvende naam voor de kans.",
|
||||
"Additional details about the opportunity.": "Aanvullende details over de mogelijkheid.",
|
||||
"The probability of winning this opportunity (0-100).": "De kans dat deze kans wordt gewonnen (0-100).",
|
||||
"The period for the opportunity value.": "De periode voor de opportuniteitswaarde.",
|
||||
"The ID of the contact associated with this opportunity.": "Het ID van het contact dat is gekoppeld aan deze mogelijkheid.",
|
||||
"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..",
|
||||
"By Name": "Op naam",
|
||||
"By Contact Email": "Per contact e-mail",
|
||||
"By Status": "door Status",
|
||||
"Contains": "Bevat",
|
||||
"Exact Match": "Exacte overeenkomst",
|
||||
"Starts With": "Begint met",
|
||||
"Ends With": "Eindigt met",
|
||||
"One-Time": "Eenmalig",
|
||||
"Monthly": "maandelijks",
|
||||
"Annual": "Jaarlijks",
|
||||
"By Email": "Per e-mail",
|
||||
"By Phone": "Per telefoon",
|
||||
"By Lead ID": "Op Lead ID",
|
||||
"GET": "KRIJG",
|
||||
"POST": "POSTE",
|
||||
"PATCH": "BEKIJK",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "VERWIJDEREN",
|
||||
"HEAD": "HOOFD",
|
||||
"New Lead Created": "Nieuwe Lead aangemaakt",
|
||||
"New Contact Added": "Nieuwe contactpersoon toegevoegd",
|
||||
"New Opportunity Added": "Nieuwe kans toegevoegd",
|
||||
"Triggers when a new lead is created.": "Triggert wanneer een nieuwe lead wordt gemaakt.",
|
||||
"Triggers when a new contact is created.": "Triggert wanneer een nieuw contact wordt aangemaakt.",
|
||||
"Triggers when a new opportunity is created.": "Triggert wanneer een nieuwe kans wordt gecreëerd."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Automação de Vendas e Integração CRM para Fechar",
|
||||
"Your Close CRM API key for authentication.": "Sua chave API Close CRM para autenticação.",
|
||||
"Create Lead": "Criar Potencial",
|
||||
"Create Contact": "Criar contato",
|
||||
"Find Lead": "Encontrar Potencial",
|
||||
"Create Opportunity": "Criar Oportunidade",
|
||||
"Find Contact": "Localizar contato",
|
||||
"Custom API Call": "Chamada de API personalizada",
|
||||
"Creates a new lead.": "Cria um novo lead.",
|
||||
"Creates a new contact.": "Cria um novo contato.",
|
||||
"Search for leads with advanced filtering options": "Procurar por leads com opções de filtragem avançadas",
|
||||
"Create a new opportunity.": "Crie uma nova oportunidade.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Procurar contatos por nome, email ou outro critério com filtragem avançada",
|
||||
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
|
||||
"Lead Name": "Nome do Potencial",
|
||||
"URL": "URL:",
|
||||
"Description": "Descrição",
|
||||
"Contacts": "CONTATOS",
|
||||
"Status": "Estado",
|
||||
"Custom Fields": "Campos Personalizados",
|
||||
"Lead": "Conduzir",
|
||||
"Name": "Nome",
|
||||
"Title": "Título",
|
||||
"Office Phone": "Telefone Escritório",
|
||||
"Mobile Phone": "Telefone Celular",
|
||||
"Home Phone": "Telefone Residencial",
|
||||
"Direct Phone": "Telefone Direto",
|
||||
"Fax Phone": "Telefone do Fax",
|
||||
"Other Phone": "Telefone Alternativo",
|
||||
"Office Email": "E-mail do Escritório",
|
||||
"Home Email": "E-mail Residencial",
|
||||
"Direct Email": "Email Direto",
|
||||
"Other Email": "E-mail Alternativo",
|
||||
"Search Type": "Pesquisar Tipo",
|
||||
"Search Query": "Consulta de Pesquisa",
|
||||
"Match Type": "Tipo de correspondência",
|
||||
"Opportunity Name": "Oportunidade Nome",
|
||||
"Notes": "Observações",
|
||||
"Confidence %": "% de confiança",
|
||||
"Value": "Valor",
|
||||
"Value Period": "Período do Valor",
|
||||
"Contact ID": "ID do contato",
|
||||
"User": "Usuário",
|
||||
"Method": "Método",
|
||||
"Headers": "Cabeçalhos",
|
||||
"Query Parameters": "Parâmetros da consulta",
|
||||
"Body": "Conteúdo",
|
||||
"Response is Binary ?": "A resposta é binária ?",
|
||||
"No Error on Failure": "Nenhum erro no Failure",
|
||||
"Timeout (in seconds)": "Tempo limite (em segundos)",
|
||||
"The name of the lead/company.": "Por favor, forneça um nome.",
|
||||
"Array of contact details for this lead": "Array de detalhes de contato para este lead",
|
||||
"A descriptive name for the opportunity.": "Um nome descritivo para a oportunidade.",
|
||||
"Additional details about the opportunity.": "Detalhes adicionais sobre a oportunidade.",
|
||||
"The probability of winning this opportunity (0-100).": "A probabilidade de ganhar esta oportunidade (0-100).",
|
||||
"The period for the opportunity value.": "O período para o valor de oportunidade.",
|
||||
"The ID of the contact associated with this opportunity.": "O ID do contato associado a esta oportunidade.",
|
||||
"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..",
|
||||
"By Name": "Por Nome",
|
||||
"By Contact Email": "Por e-mail de contato",
|
||||
"By Status": "Por status",
|
||||
"Contains": "contém",
|
||||
"Exact Match": "Partida exata",
|
||||
"Starts With": "Começa com",
|
||||
"Ends With": "Termina com",
|
||||
"One-Time": "Única",
|
||||
"Monthly": "Mensual",
|
||||
"Annual": "Anual",
|
||||
"By Email": "Por E-mail",
|
||||
"By Phone": "Por telefone",
|
||||
"By Lead ID": "Por ID do Lead",
|
||||
"GET": "OBTER",
|
||||
"POST": "POSTAR",
|
||||
"PATCH": "COMPRAR",
|
||||
"PUT": "COLOCAR",
|
||||
"DELETE": "EXCLUIR",
|
||||
"HEAD": "CABEÇA",
|
||||
"New Lead Created": "Novo Potencial Criado",
|
||||
"New Contact Added": "Novo contato adicionado",
|
||||
"New Opportunity Added": "Nova Oportunidade Adicionado",
|
||||
"Triggers when a new lead is created.": "Dispara quando um novo lead é criado.",
|
||||
"Triggers when a new contact is created.": "Dispara quando um novo contato é criado.",
|
||||
"Triggers when a new opportunity is created.": "Dispara quando uma nova oportunidade é criada."
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"Close": "Close",
|
||||
"Sales automation and CRM integration for Close": "Автоматизация продаж и интеграция CRM для закрытия",
|
||||
"Your Close CRM API key for authentication.": "Ваш закрытый API ключ для аутентификации.",
|
||||
"Create Lead": "Создать предв. контакт",
|
||||
"Create Contact": "Создать контакт",
|
||||
"Find Lead": "Найти предв. контакт",
|
||||
"Create Opportunity": "Создать сделку",
|
||||
"Find Contact": "Найти контакт",
|
||||
"Custom API Call": "Пользовательский вызов API",
|
||||
"Creates a new lead.": "Создает нового лидера.",
|
||||
"Creates a new contact.": "Создает новый контакт.",
|
||||
"Search for leads with advanced filtering options": "Поиск проводов с расширенными опциями фильтрации",
|
||||
"Create a new opportunity.": "Создать новую возможность.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Поиск контактов по имени, электронной почте или по другим критериям с расширенной фильтрацией",
|
||||
"Make a custom API call to a specific endpoint": "Сделать пользовательский API вызов к определенной конечной точке",
|
||||
"Lead Name": "Имя предварительного контакта",
|
||||
"URL": "URL",
|
||||
"Description": "Описание",
|
||||
"Contacts": "Контакты",
|
||||
"Status": "Статус",
|
||||
"Custom Fields": "Пользовательские поля",
|
||||
"Lead": "Предв. контакт",
|
||||
"Name": "Наименование",
|
||||
"Title": "Заголовок",
|
||||
"Office Phone": "Тел. (раб.)",
|
||||
"Mobile Phone": "Мобильный телефон",
|
||||
"Home Phone": "Домашний телефон",
|
||||
"Direct Phone": "Прямой телефон",
|
||||
"Fax Phone": "Телефон факса",
|
||||
"Other Phone": "Другой телефон",
|
||||
"Office Email": "Почта офиса",
|
||||
"Home Email": "Домашняя почта",
|
||||
"Direct Email": "Прямая почта",
|
||||
"Other Email": "Другой Email",
|
||||
"Search Type": "Тип поиска",
|
||||
"Search Query": "Поисковый запрос",
|
||||
"Match Type": "Тип матча",
|
||||
"Opportunity Name": "Название Сделки",
|
||||
"Notes": "Примечания",
|
||||
"Confidence %": "% доверия",
|
||||
"Value": "Значение",
|
||||
"Value Period": "Период стоимости",
|
||||
"Contact ID": "ID контакта",
|
||||
"User": "Пользователь",
|
||||
"Method": "Метод",
|
||||
"Headers": "Заголовки",
|
||||
"Query Parameters": "Параметры запроса",
|
||||
"Body": "Тело",
|
||||
"No Error on Failure": "Нет ошибок при ошибке",
|
||||
"Timeout (in seconds)": "Таймаут (в секундах)",
|
||||
"The name of the lead/company.": "Название свинца/компании.",
|
||||
"Array of contact details for this lead": "Массив контактных данных для этого провода",
|
||||
"A descriptive name for the opportunity.": "Описательное название возможности.",
|
||||
"Additional details about the opportunity.": "Дополнительная информация о возможности.",
|
||||
"The probability of winning this opportunity (0-100).": "Вероятность выиграть эту возможность (0-100).",
|
||||
"The period for the opportunity value.": "Период для стоимости сделки.",
|
||||
"The ID of the contact associated with this opportunity.": "ID контакта, связанного с этой возможностью.",
|
||||
"Authorization headers are injected automatically from your connection.": "Заголовки авторизации включаются автоматически из вашего соединения.",
|
||||
"By Name": "По имени",
|
||||
"By Contact Email": "По электронной почте",
|
||||
"By Status": "По статусу",
|
||||
"Contains": "Содержит",
|
||||
"Exact Match": "Точное совпадение",
|
||||
"Starts With": "Начинается с",
|
||||
"Ends With": "Заканчивается с",
|
||||
"One-Time": "Одноразовое",
|
||||
"Monthly": "Ежемесячно",
|
||||
"Annual": "Годовой",
|
||||
"By Email": "По электронной почте",
|
||||
"By Phone": "По телефону",
|
||||
"By Lead ID": "По Lead ID",
|
||||
"GET": "ПОЛУЧИТЬ",
|
||||
"POST": "ПОСТ",
|
||||
"PATCH": "ПАТЧ",
|
||||
"PUT": "ПОКУПИТЬ",
|
||||
"DELETE": "УДАЛИТЬ",
|
||||
"HEAD": "HEAD",
|
||||
"New Lead Created": "Создан новый контакт",
|
||||
"New Contact Added": "Добавлен новый контакт",
|
||||
"New Opportunity Added": "Новая сделка Добавлена",
|
||||
"Triggers when a new lead is created.": "Триггеры при создании нового свинца.",
|
||||
"Triggers when a new contact is created.": "Включает при создании нового контакта.",
|
||||
"Triggers when a new opportunity is created.": "Триггеры при создании новой возможности."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Sales automation and CRM integration for Close",
|
||||
"Your Close CRM API key for authentication.": "Your Close CRM API key for authentication.",
|
||||
"Create Lead": "Create Lead",
|
||||
"Create Contact": "Create Contact",
|
||||
"Find Lead": "Find Lead",
|
||||
"Create Opportunity": "Create Opportunity",
|
||||
"Find Contact": "Find Contact",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Creates a new lead.": "Creates a new lead.",
|
||||
"Creates a new contact.": "Creates a new contact.",
|
||||
"Search for leads with advanced filtering options": "Search for leads with advanced filtering options",
|
||||
"Create a new opportunity.": "Create a new opportunity.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Search for contacts by name, email, or other criteria with advanced filtering",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"Lead Name": "Lead Name",
|
||||
"URL": "URL",
|
||||
"Description": "Description",
|
||||
"Contacts": "Contacts",
|
||||
"Status": "Status",
|
||||
"Custom Fields": "Custom Fields",
|
||||
"Lead": "Lead",
|
||||
"Name": "Name",
|
||||
"Title": "Title",
|
||||
"Office Phone": "Office Phone",
|
||||
"Mobile Phone": "Mobile Phone",
|
||||
"Home Phone": "Home Phone",
|
||||
"Direct Phone": "Direct Phone",
|
||||
"Fax Phone": "Fax Phone",
|
||||
"Other Phone": "Other Phone",
|
||||
"Office Email": "Office Email",
|
||||
"Home Email": "Home Email",
|
||||
"Direct Email": "Direct Email",
|
||||
"Other Email": "Other Email",
|
||||
"Search Type": "Search Type",
|
||||
"Search Query": "Search Query",
|
||||
"Match Type": "Match Type",
|
||||
"Opportunity Name": "Opportunity Name",
|
||||
"Notes": "Notes",
|
||||
"Confidence %": "Confidence %",
|
||||
"Value": "Value",
|
||||
"Value Period": "Value Period",
|
||||
"Contact ID": "Contact ID",
|
||||
"User": "User",
|
||||
"Method": "Method",
|
||||
"Headers": "Headers",
|
||||
"Query Parameters": "Query Parameters",
|
||||
"Body": "Body",
|
||||
"Response is Binary ?": "Response is Binary ?",
|
||||
"No Error on Failure": "No Error on Failure",
|
||||
"Timeout (in seconds)": "Timeout (in seconds)",
|
||||
"The name of the lead/company.": "The name of the lead/company.",
|
||||
"Array of contact details for this lead": "Array of contact details for this lead",
|
||||
"A descriptive name for the opportunity.": "A descriptive name for the opportunity.",
|
||||
"Additional details about the opportunity.": "Additional details about the opportunity.",
|
||||
"The probability of winning this opportunity (0-100).": "The probability of winning this opportunity (0-100).",
|
||||
"The period for the opportunity value.": "The period for the opportunity value.",
|
||||
"The ID of the contact associated with this opportunity.": "The ID of the contact associated with this opportunity.",
|
||||
"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..",
|
||||
"By Name": "By Name",
|
||||
"By Contact Email": "By Contact Email",
|
||||
"By Status": "By Status",
|
||||
"Contains": "Contains",
|
||||
"Exact Match": "Exact Match",
|
||||
"Starts With": "Starts With",
|
||||
"Ends With": "Ends With",
|
||||
"One-Time": "One-Time",
|
||||
"Monthly": "Monthly",
|
||||
"Annual": "Annual",
|
||||
"By Email": "By Email",
|
||||
"By Phone": "By Phone",
|
||||
"By Lead ID": "By Lead ID",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Lead Created": "New Lead Created",
|
||||
"New Contact Added": "New Contact Added",
|
||||
"New Opportunity Added": "New Opportunity Added",
|
||||
"Triggers when a new lead is created.": "Triggers when a new lead is created.",
|
||||
"Triggers when a new contact is created.": "Triggers when a new contact is created.",
|
||||
"Triggers when a new opportunity is created.": "Triggers when a new opportunity is created."
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"Close": "Close",
|
||||
"Sales automation and CRM integration for Close": "Sales automation and CRM integration for Close",
|
||||
"Your Close CRM API key for authentication.": "Your Close CRM API key for authentication.",
|
||||
"Create Lead": "Create Lead",
|
||||
"Create Contact": "Create Contact",
|
||||
"Find Lead": "Find Lead",
|
||||
"Create Opportunity": "Create Opportunity",
|
||||
"Find Contact": "Find Contact",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Creates a new lead.": "Creates a new lead.",
|
||||
"Creates a new contact.": "Creates a new contact.",
|
||||
"Search for leads with advanced filtering options": "Search for leads with advanced filtering options",
|
||||
"Create a new opportunity.": "Create a new opportunity.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Search for contacts by name, email, or other criteria with advanced filtering",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"Lead Name": "Lead Name",
|
||||
"URL": "URL",
|
||||
"Description": "Description",
|
||||
"Contacts": "Contacts",
|
||||
"Status": "Status",
|
||||
"Custom Fields": "Custom Fields",
|
||||
"Lead": "Lead",
|
||||
"Name": "Name",
|
||||
"Title": "Title",
|
||||
"Office Phone": "Office Phone",
|
||||
"Mobile Phone": "Mobile Phone",
|
||||
"Home Phone": "Home Phone",
|
||||
"Direct Phone": "Direct Phone",
|
||||
"Fax Phone": "Fax Phone",
|
||||
"Other Phone": "Other Phone",
|
||||
"Office Email": "Office Email",
|
||||
"Home Email": "Home Email",
|
||||
"Direct Email": "Direct Email",
|
||||
"Other Email": "Other Email",
|
||||
"Search Type": "Search Type",
|
||||
"Search Query": "Search Query",
|
||||
"Match Type": "Match Type",
|
||||
"Opportunity Name": "Opportunity Name",
|
||||
"Notes": "Notes",
|
||||
"Confidence %": "Confidence %",
|
||||
"Value": "Value",
|
||||
"Value Period": "Value Period",
|
||||
"Contact ID": "Contact ID",
|
||||
"User": "User",
|
||||
"Method": "Method",
|
||||
"Headers": "Headers",
|
||||
"Query Parameters": "Query Parameters",
|
||||
"Body": "Body",
|
||||
"No Error on Failure": "No Error on Failure",
|
||||
"Timeout (in seconds)": "Timeout (in seconds)",
|
||||
"The name of the lead/company.": "The name of the lead/company.",
|
||||
"Array of contact details for this lead": "Array of contact details for this lead",
|
||||
"A descriptive name for the opportunity.": "A descriptive name for the opportunity.",
|
||||
"Additional details about the opportunity.": "Additional details about the opportunity.",
|
||||
"The probability of winning this opportunity (0-100).": "The probability of winning this opportunity (0-100).",
|
||||
"The period for the opportunity value.": "The period for the opportunity value.",
|
||||
"The ID of the contact associated with this opportunity.": "The ID of the contact associated with this opportunity.",
|
||||
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
|
||||
"By Name": "By Name",
|
||||
"By Contact Email": "By Contact Email",
|
||||
"By Status": "By Status",
|
||||
"Contains": "Contains",
|
||||
"Exact Match": "Exact Match",
|
||||
"Starts With": "Starts With",
|
||||
"Ends With": "Ends With",
|
||||
"One-Time": "One-Time",
|
||||
"Monthly": "Monthly",
|
||||
"Annual": "Annual",
|
||||
"By Email": "By Email",
|
||||
"By Phone": "By Phone",
|
||||
"By Lead ID": "By Lead ID",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD",
|
||||
"New Lead Created": "New Lead Created",
|
||||
"New Contact Added": "New Contact Added",
|
||||
"New Opportunity Added": "New Opportunity Added",
|
||||
"Triggers when a new lead is created.": "Triggers when a new lead is created.",
|
||||
"Triggers when a new contact is created.": "Triggers when a new contact is created.",
|
||||
"Triggers when a new opportunity is created.": "Triggers when a new opportunity is created."
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"Sales automation and CRM integration for Close": "Sales automation and CRM integration for Close",
|
||||
"Your Close CRM API key for authentication.": "Your Close CRM API key for authentication.",
|
||||
"Create Lead": "Create Lead",
|
||||
"Create Contact": "Create Contact",
|
||||
"Find Lead": "Find Lead",
|
||||
"Create Opportunity": "Create Opportunity",
|
||||
"Find Contact": "Find Contact",
|
||||
"Custom API Call": "自定义 API 呼叫",
|
||||
"Creates a new lead.": "Creates a new lead.",
|
||||
"Creates a new contact.": "Creates a new contact.",
|
||||
"Search for leads with advanced filtering options": "Search for leads with advanced filtering options",
|
||||
"Create a new opportunity.": "Create a new opportunity.",
|
||||
"Search for contacts by name, email, or other criteria with advanced filtering": "Search for contacts by name, email, or other criteria with advanced filtering",
|
||||
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
|
||||
"Lead Name": "Lead Name",
|
||||
"URL": "URL",
|
||||
"Description": "描述",
|
||||
"Contacts": "Contacts",
|
||||
"Status": "状态",
|
||||
"Custom Fields": "Custom Fields",
|
||||
"Lead": "Lead",
|
||||
"Name": "名称",
|
||||
"Title": "标题",
|
||||
"Office Phone": "Office Phone",
|
||||
"Mobile Phone": "Mobile Phone",
|
||||
"Home Phone": "Home Phone",
|
||||
"Direct Phone": "Direct Phone",
|
||||
"Fax Phone": "Fax Phone",
|
||||
"Other Phone": "Other Phone",
|
||||
"Office Email": "Office Email",
|
||||
"Home Email": "Home Email",
|
||||
"Direct Email": "Direct Email",
|
||||
"Other Email": "Other Email",
|
||||
"Search Type": "Search Type",
|
||||
"Search Query": "Search Query",
|
||||
"Match Type": "Match Type",
|
||||
"Opportunity Name": "Opportunity Name",
|
||||
"Notes": "Notes",
|
||||
"Confidence %": "Confidence %",
|
||||
"Value": "值",
|
||||
"Value Period": "Value Period",
|
||||
"Contact ID": "Contact ID",
|
||||
"User": "用户",
|
||||
"Method": "方法",
|
||||
"Headers": "信头",
|
||||
"Query Parameters": "查询参数",
|
||||
"Body": "正文内容",
|
||||
"Response is Binary ?": "Response is Binary ?",
|
||||
"No Error on Failure": "失败时没有错误",
|
||||
"Timeout (in seconds)": "超时(秒)",
|
||||
"The name of the lead/company.": "The name of the lead/company.",
|
||||
"Array of contact details for this lead": "Array of contact details for this lead",
|
||||
"A descriptive name for the opportunity.": "A descriptive name for the opportunity.",
|
||||
"Additional details about the opportunity.": "Additional details about the opportunity.",
|
||||
"The probability of winning this opportunity (0-100).": "The probability of winning this opportunity (0-100).",
|
||||
"The period for the opportunity value.": "The period for the opportunity value.",
|
||||
"The ID of the contact associated with this opportunity.": "The ID of the contact associated with this opportunity.",
|
||||
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
|
||||
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
|
||||
"By Name": "By Name",
|
||||
"By Contact Email": "By Contact Email",
|
||||
"By Status": "By Status",
|
||||
"Contains": "Contains",
|
||||
"Exact Match": "精确匹配",
|
||||
"Starts With": "Starts With",
|
||||
"Ends With": "Ends With",
|
||||
"One-Time": "One-Time",
|
||||
"Monthly": "Monthly",
|
||||
"Annual": "Annual",
|
||||
"By Email": "By Email",
|
||||
"By Phone": "By Phone",
|
||||
"By Lead ID": "By Lead ID",
|
||||
"GET": "获取",
|
||||
"POST": "帖子",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "弹出",
|
||||
"DELETE": "删除",
|
||||
"HEAD": "黑色",
|
||||
"New Lead Created": "New Lead Created",
|
||||
"New Contact Added": "New Contact Added",
|
||||
"New Opportunity Added": "New Opportunity Added",
|
||||
"Triggers when a new lead is created.": "Triggers when a new lead is created.",
|
||||
"Triggers when a new contact is created.": "Triggers when a new contact is created.",
|
||||
"Triggers when a new opportunity is created.": "Triggers when a new opportunity is created."
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
createCustomApiCallAction,
|
||||
HttpMethod,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { createLead } from './lib/actions/create-lead';
|
||||
import { findLead } from './lib/actions/find-lead';
|
||||
import { newLeadAdded } from './lib/triggers/new-lead-added';
|
||||
import { createOpportunity } from './lib/actions/create-opportunity';
|
||||
import { createContact } from './lib/actions/create-contact';
|
||||
import { newContactAdded } from './lib/triggers/new-contact-added';
|
||||
import { findContact } from './lib/actions/find-contact';
|
||||
import { CLOSE_API_URL, closeApiCall } from './lib/common/client';
|
||||
import { newOpportunityAdded } from './lib/triggers/new-opportunity';
|
||||
|
||||
export const closeAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description: 'Your Close CRM API key for authentication.',
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
await closeApiCall({
|
||||
accessToken: auth,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/me/',
|
||||
});
|
||||
|
||||
return { valid: true };
|
||||
} catch {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API key.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const close = createPiece({
|
||||
displayName: 'Close',
|
||||
description: 'Sales automation and CRM integration for Close',
|
||||
auth: closeAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/close.png',
|
||||
authors: ['Ani-4x', 'kishanprmr'],
|
||||
actions: [
|
||||
createLead,
|
||||
createContact,
|
||||
findLead,
|
||||
createOpportunity,
|
||||
findContact,
|
||||
createCustomApiCallAction({
|
||||
baseUrl: () => CLOSE_API_URL,
|
||||
auth: closeAuth,
|
||||
authMapping: async (auth) => {
|
||||
return {
|
||||
Authorization: `Basic ${Buffer.from(`${auth}:`).toString('base64')}`,
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
triggers: [newLeadAdded, newContactAdded, newOpportunityAdded],
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { CloseCRMContact } from '../common/types';
|
||||
import { customFields, leadId } from '../common/props';
|
||||
import { closeApiCall } from '../common/client';
|
||||
|
||||
export const createContact = createAction({
|
||||
auth: closeAuth,
|
||||
name: 'create_contact',
|
||||
displayName: 'Create Contact',
|
||||
description: 'Creates a new contact.',
|
||||
props: {
|
||||
lead_id: leadId(),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
required: true,
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
required: false,
|
||||
}),
|
||||
officePhone: Property.ShortText({
|
||||
displayName: 'Office Phone',
|
||||
required: false,
|
||||
}),
|
||||
mobilePhone: Property.ShortText({
|
||||
displayName: 'Mobile Phone',
|
||||
required: false,
|
||||
}),
|
||||
homePhone: Property.ShortText({
|
||||
displayName: 'Home Phone',
|
||||
required: false,
|
||||
}),
|
||||
directPhone: Property.ShortText({
|
||||
displayName: 'Direct Phone',
|
||||
required: false,
|
||||
}),
|
||||
faxPhone: Property.ShortText({
|
||||
displayName: 'Fax Phone',
|
||||
required: false,
|
||||
}),
|
||||
otherPhone: Property.ShortText({
|
||||
displayName: 'Other Phone',
|
||||
required: false,
|
||||
}),
|
||||
officeEmail: Property.ShortText({
|
||||
displayName: 'Office Email',
|
||||
required: false,
|
||||
}),
|
||||
homeEmail: Property.ShortText({
|
||||
displayName: 'Home Email',
|
||||
required: false,
|
||||
}),
|
||||
directEmail: Property.ShortText({
|
||||
displayName: 'Direct Email',
|
||||
required: false,
|
||||
}),
|
||||
otherEmail: Property.ShortText({
|
||||
displayName: 'Other Email',
|
||||
required: false,
|
||||
}),
|
||||
url: Property.ShortText({
|
||||
displayName: 'URL',
|
||||
required: false,
|
||||
}),
|
||||
customFields: customFields('contact'),
|
||||
},
|
||||
async run(context) {
|
||||
const {
|
||||
lead_id,
|
||||
name,
|
||||
title,
|
||||
officeEmail,
|
||||
officePhone,
|
||||
otherEmail,
|
||||
otherPhone,
|
||||
mobilePhone,
|
||||
homeEmail,
|
||||
url,
|
||||
homePhone,
|
||||
directEmail,
|
||||
directPhone,
|
||||
faxPhone,
|
||||
} = context.propsValue;
|
||||
|
||||
const customFields = context.propsValue.customFields ?? {};
|
||||
|
||||
const transformedCustomFields = Object.fromEntries(
|
||||
Object.entries(customFields)
|
||||
.filter(([, v]) => v !== '' && v != null && !(Array.isArray(v) && v.length === 0))
|
||||
.map(([key, value]) => [`custom.${key}`, value]),
|
||||
);
|
||||
|
||||
const payload: Partial<CloseCRMContact> = {
|
||||
lead_id: lead_id as string,
|
||||
title: title,
|
||||
name: name,
|
||||
...transformedCustomFields,
|
||||
phones: [],
|
||||
emails: [],
|
||||
urls: [],
|
||||
};
|
||||
|
||||
// Add emails if present
|
||||
if (officeEmail) payload.emails?.push({ email: officeEmail.trim(), type: 'office' });
|
||||
if (otherEmail) payload.emails?.push({ email: otherEmail.trim(), type: 'other' });
|
||||
if (homeEmail) payload.emails?.push({ email: homeEmail.trim(), type: 'home' });
|
||||
if (directEmail) payload.emails?.push({ email: directEmail.trim(), type: 'direct' });
|
||||
|
||||
// Add phones if present
|
||||
if (officePhone) payload.phones?.push({ phone: officePhone.trim(), type: 'office' });
|
||||
if (otherPhone) payload.phones?.push({ phone: otherPhone.trim(), type: 'other' });
|
||||
if (mobilePhone) payload.phones?.push({ phone: mobilePhone.trim(), type: 'mobile' });
|
||||
if (homePhone) payload.phones?.push({ phone: homePhone.trim(), type: 'home' });
|
||||
if (directPhone) payload.phones?.push({ phone: directPhone.trim(), type: 'direct' });
|
||||
if (faxPhone) payload.phones?.push({ phone: faxPhone.trim(), type: 'fax' });
|
||||
|
||||
if (url) payload.urls?.push({ url, type: 'url' });
|
||||
|
||||
try {
|
||||
const response = await closeApiCall({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/contact/',
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 400) {
|
||||
throw new Error(`Bad request: ${JSON.stringify(error.response.body)}`);
|
||||
}
|
||||
if (error.response?.status === 404) {
|
||||
throw new Error(`Lead not found with ID: ${lead_id}`);
|
||||
}
|
||||
throw new Error(`Error creating contact: ${error.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,177 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { closeAuth } from './../../index';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeApiCall } from '../common/client';
|
||||
import { customFields, statusId } from '../common/props';
|
||||
|
||||
export const createLead = createAction({
|
||||
auth: closeAuth,
|
||||
name: 'create_lead',
|
||||
displayName: 'Create Lead',
|
||||
description: 'Creates a new lead.',
|
||||
props: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Lead Name',
|
||||
description: 'The name of the lead/company.',
|
||||
required: true,
|
||||
}),
|
||||
url: Property.ShortText({
|
||||
displayName: 'URL',
|
||||
required: false,
|
||||
}),
|
||||
description: Property.LongText({
|
||||
displayName: 'Description',
|
||||
required: false,
|
||||
}),
|
||||
contacts: Property.Array({
|
||||
displayName: 'Contacts',
|
||||
description: 'Array of contact details for this lead',
|
||||
required: false,
|
||||
properties: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Contact Name',
|
||||
required: true,
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Contact Title',
|
||||
required: false,
|
||||
}),
|
||||
officePhone: Property.ShortText({
|
||||
displayName: 'Contact Office Phone',
|
||||
required: false,
|
||||
}),
|
||||
mobilePhone: Property.ShortText({
|
||||
displayName: 'Contact Mobile Phone',
|
||||
required: false,
|
||||
}),
|
||||
homePhone: Property.ShortText({
|
||||
displayName: 'Contact Home Phone',
|
||||
required: false,
|
||||
}),
|
||||
directPhone: Property.ShortText({
|
||||
displayName: 'Contact Direct Phone',
|
||||
required: false,
|
||||
}),
|
||||
faxPhone: Property.ShortText({
|
||||
displayName: 'Contact Fax Phone',
|
||||
required: false,
|
||||
}),
|
||||
otherPhone: Property.ShortText({
|
||||
displayName: 'Contact Other Phone',
|
||||
required: false,
|
||||
}),
|
||||
officeEmail: Property.ShortText({
|
||||
displayName: 'Contact Office Email',
|
||||
required: false,
|
||||
}),
|
||||
homeEmail: Property.ShortText({
|
||||
displayName: 'Contact Home Email',
|
||||
required: false,
|
||||
}),
|
||||
directEmail: Property.ShortText({
|
||||
displayName: 'Contact Direct Email',
|
||||
required: false,
|
||||
}),
|
||||
otherEmail: Property.ShortText({
|
||||
displayName: 'Contact Other Email',
|
||||
required: false,
|
||||
}),
|
||||
url: Property.ShortText({
|
||||
displayName: 'Contact URL',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
statusId: statusId('lead', false),
|
||||
customFields: customFields('lead'),
|
||||
},
|
||||
async run(context) {
|
||||
const { name, url, description, statusId } = context.propsValue;
|
||||
const contacts = (context.propsValue.contacts as ContactInfo[]) ?? [];
|
||||
const customFields = context.propsValue.customFields ?? {};
|
||||
|
||||
const transformedCustomFields = Object.fromEntries(
|
||||
Object.entries(customFields)
|
||||
.filter(([, v]) => v !== '' && v != null && !(Array.isArray(v) && v.length === 0))
|
||||
.map(([key, value]) => [`custom.${key}`, value]),
|
||||
);
|
||||
|
||||
const transformedContacts = contacts.map((contact) => {
|
||||
const phoneTypes = [
|
||||
'officePhone',
|
||||
'mobilePhone',
|
||||
'homePhone',
|
||||
'directPhone',
|
||||
'faxPhone',
|
||||
'otherPhone',
|
||||
] as const;
|
||||
|
||||
const emailTypes = ['officeEmail', 'homeEmail', 'directEmail', 'otherEmail'] as const;
|
||||
|
||||
const phones = phoneTypes
|
||||
.filter((key) => contact[key]?.trim())
|
||||
.map((key) => ({
|
||||
type: key.replace('Phone', ''),
|
||||
phone: contact[key]!.trim(),
|
||||
}));
|
||||
|
||||
const emails = emailTypes
|
||||
.filter((key) => contact[key]?.trim())
|
||||
.map((key) => ({
|
||||
type: key.replace('Email', ''),
|
||||
email: contact[key]!.trim(),
|
||||
}));
|
||||
|
||||
return {
|
||||
name: contact.name?.trim(),
|
||||
title: contact.title?.trim(),
|
||||
phones: phones.length > 0 ? phones : undefined,
|
||||
emails: emails.length > 0 ? emails : undefined,
|
||||
urls: contact.url
|
||||
? [
|
||||
{
|
||||
type: 'url',
|
||||
url: contact.url,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
};
|
||||
});
|
||||
|
||||
const payload: Record<string, any> = {
|
||||
name,
|
||||
url,
|
||||
description,
|
||||
status_id: statusId,
|
||||
contacts: transformedContacts,
|
||||
...transformedCustomFields,
|
||||
};
|
||||
|
||||
const response = await closeApiCall({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/lead/',
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
type ContactInfo = {
|
||||
name?: string;
|
||||
title?: string;
|
||||
officePhone?: string;
|
||||
mobilePhone?: string;
|
||||
homePhone?: string;
|
||||
directPhone?: string;
|
||||
faxPhone?: string;
|
||||
otherPhone?: string;
|
||||
officeEmail?: string;
|
||||
mobileEmail?: string;
|
||||
homeEmail?: string;
|
||||
directEmail?: string;
|
||||
faxEmail?: string;
|
||||
otherEmail?: string;
|
||||
url?: string;
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { customFields, leadId, statusId, userId } from '../common/props';
|
||||
import { closeApiCall } from '../common/client';
|
||||
|
||||
export const createOpportunity = createAction({
|
||||
auth: closeAuth,
|
||||
name: 'create_opportunity',
|
||||
displayName: 'Create Opportunity',
|
||||
description: 'Create a new opportunity.',
|
||||
props: {
|
||||
lead_id: leadId(),
|
||||
status_id: statusId('opportunity', true),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Opportunity Name',
|
||||
description: 'A descriptive name for the opportunity.',
|
||||
required: false,
|
||||
}),
|
||||
note: Property.LongText({
|
||||
displayName: 'Notes',
|
||||
description: 'Additional details about the opportunity.',
|
||||
required: false,
|
||||
}),
|
||||
confidence: Property.Number({
|
||||
displayName: 'Confidence %',
|
||||
description: 'The probability of winning this opportunity (0-100).',
|
||||
required: false,
|
||||
}),
|
||||
value: Property.Number({
|
||||
displayName: 'Value',
|
||||
required: false,
|
||||
}),
|
||||
value_period: Property.StaticDropdown({
|
||||
displayName: 'Value Period',
|
||||
description: 'The period for the opportunity value.',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'One-Time', value: 'one_time' },
|
||||
{ label: 'Monthly', value: 'monthly' },
|
||||
{ label: 'Annual', value: 'annual' },
|
||||
],
|
||||
},
|
||||
defaultValue: 'one_time',
|
||||
}),
|
||||
contact_id: Property.ShortText({
|
||||
displayName: 'Contact ID',
|
||||
description: 'The ID of the contact associated with this opportunity.',
|
||||
required: false,
|
||||
}),
|
||||
user_id: userId(),
|
||||
custom_fields: customFields('opportunity'),
|
||||
},
|
||||
async run(context) {
|
||||
const { lead_id, name, note, status_id, confidence, value, value_period, contact_id, user_id } =
|
||||
context.propsValue;
|
||||
|
||||
const customFields = context.propsValue.custom_fields ?? {};
|
||||
|
||||
const transformedCustomFields = Object.fromEntries(
|
||||
Object.entries(customFields)
|
||||
.filter(([, v]) => v !== '' && v != null && !(Array.isArray(v) && v.length === 0))
|
||||
.map(([key, value]) => [`custom.${key}`, value]),
|
||||
);
|
||||
|
||||
const opportunityData = {
|
||||
lead_id,
|
||||
status_id,
|
||||
name,
|
||||
note,
|
||||
confidence,
|
||||
value,
|
||||
value_period,
|
||||
contact_id,
|
||||
user_id,
|
||||
...transformedCustomFields,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await closeApiCall({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/opportunity/',
|
||||
body: opportunityData,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 400) {
|
||||
throw new Error(`Invalid request: ${JSON.stringify(error.response.body)}`);
|
||||
}
|
||||
if (error.response?.status === 404) {
|
||||
throw new Error(`Lead or related resource not found`);
|
||||
}
|
||||
throw new Error(`Failed to create opportunity: ${error.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,202 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { CloseCRMSearchQuery } from '../common/types';
|
||||
import { closeApiCall } from '../common/client';
|
||||
|
||||
export const findContact = createAction({
|
||||
auth: closeAuth,
|
||||
name: 'find_contact',
|
||||
displayName: 'Find Contact',
|
||||
description: 'Search for contacts by name, email, or other criteria with advanced filtering',
|
||||
props: {
|
||||
search_type: Property.StaticDropdown({
|
||||
displayName: 'Search Type',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'By Name', value: 'name' },
|
||||
{ label: 'By Email', value: 'email' },
|
||||
{ label: 'By Phone', value: 'phone' },
|
||||
{ label: 'By Lead ID', value: 'lead_id' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
search_query: Property.ShortText({
|
||||
displayName: 'Search Query',
|
||||
required: true,
|
||||
}),
|
||||
match_type: Property.StaticDropdown({
|
||||
displayName: 'Match Type',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Contains', value: 'contains' },
|
||||
{ label: 'Exact Match', value: 'exact' },
|
||||
{ label: 'Starts With', value: 'starts' },
|
||||
{ label: 'Ends With', value: 'ends' },
|
||||
],
|
||||
},
|
||||
defaultValue: 'contains',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { search_type, search_query, match_type } = context.propsValue;
|
||||
|
||||
try {
|
||||
// Build the search query
|
||||
const searchQuery = buildSearchQuery({
|
||||
search_type,
|
||||
search_query,
|
||||
match_type: match_type || 'contains',
|
||||
include_fields: ['title', 'id', 'name', 'emails'],
|
||||
});
|
||||
|
||||
let cursor: string | undefined;
|
||||
|
||||
const result = [];
|
||||
|
||||
do {
|
||||
const response = await closeApiCall<{
|
||||
cursor?: string;
|
||||
data: Record<string, any>[];
|
||||
}>({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/data/search/',
|
||||
body: {
|
||||
_limit: 100,
|
||||
cursor,
|
||||
...searchQuery,
|
||||
},
|
||||
});
|
||||
|
||||
const { data } = response;
|
||||
if (!data || data.length === 0) break;
|
||||
|
||||
result.push(...data);
|
||||
cursor = response.cursor;
|
||||
} while (cursor);
|
||||
|
||||
return {
|
||||
found: result.length > 0,
|
||||
result,
|
||||
};
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 400) {
|
||||
throw new Error(`Invalid search query: ${error.response.body?.error || 'Unknown error'}`);
|
||||
}
|
||||
if (error.response?.status === 401) {
|
||||
throw new Error('Authentication failed. Please check your API key.');
|
||||
}
|
||||
throw new Error(`Failed to search contacts: ${error.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Helper function to build the search query
|
||||
function buildSearchQuery(params: {
|
||||
search_type: string;
|
||||
search_query: string;
|
||||
match_type: string;
|
||||
include_fields: string[];
|
||||
}): CloseCRMSearchQuery {
|
||||
const { search_type, search_query, match_type, include_fields } = params;
|
||||
|
||||
const baseQuery = {
|
||||
type: 'object_type',
|
||||
object_type: 'contact',
|
||||
};
|
||||
|
||||
let fieldCondition;
|
||||
|
||||
switch (search_type) {
|
||||
case 'name':
|
||||
fieldCondition = {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'contact',
|
||||
field_name: 'name',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'full_words',
|
||||
value: search_query,
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
fieldCondition = {
|
||||
type: 'has_related',
|
||||
this_object_type: 'contact',
|
||||
related_object_type: 'contact_email',
|
||||
related_query: {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'contact_email',
|
||||
field_name: 'email',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'phrase',
|
||||
value: search_query,
|
||||
},
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'phone':
|
||||
fieldCondition = {
|
||||
type: 'has_related',
|
||||
this_object_type: 'contact',
|
||||
related_object_type: 'contact_phone',
|
||||
related_query: {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'contact_phone',
|
||||
field_name: 'phone',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'phrase',
|
||||
value: search_query,
|
||||
},
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'lead_id':
|
||||
fieldCondition = {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'contact',
|
||||
field_name: 'lead_id',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'phrase', // Always exact match for IDs
|
||||
value: search_query,
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported search type: ${search_type}`);
|
||||
}
|
||||
|
||||
return {
|
||||
query: {
|
||||
type: 'and',
|
||||
queries: [baseQuery, fieldCondition],
|
||||
},
|
||||
_fields: {
|
||||
lead: ['id', 'name', 'status_label', 'contacts'],
|
||||
contact: ['id', 'name', 'emails', 'phones'],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { CloseCRMSearchQuery } from '../common/types';
|
||||
import { closeApiCall } from '../common/client';
|
||||
|
||||
export const findLead = createAction({
|
||||
auth: closeAuth,
|
||||
name: 'find_lead',
|
||||
displayName: 'Find Lead',
|
||||
description: 'Search for leads with advanced filtering options',
|
||||
props: {
|
||||
search_type: Property.StaticDropdown({
|
||||
displayName: 'Search Type',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'By Name', value: 'name' },
|
||||
{ label: 'By Contact Email', value: 'contact_email' },
|
||||
{ label: 'By Status', value: 'status' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
search_query: Property.ShortText({
|
||||
displayName: 'Search Query',
|
||||
required: true,
|
||||
}),
|
||||
match_type: Property.StaticDropdown({
|
||||
displayName: 'Match Type',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Contains', value: 'contains' },
|
||||
{ label: 'Exact Match', value: 'exact' },
|
||||
{ label: 'Starts With', value: 'starts' },
|
||||
{ label: 'Ends With', value: 'ends' },
|
||||
],
|
||||
},
|
||||
defaultValue: 'contains',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { search_type, search_query, match_type } = context.propsValue;
|
||||
|
||||
try {
|
||||
// Build the search query
|
||||
const searchQuery = buildLeadSearchQuery({
|
||||
search_type,
|
||||
search_query,
|
||||
match_type: match_type || 'contains',
|
||||
});
|
||||
|
||||
let cursor: string | undefined;
|
||||
|
||||
const result = [];
|
||||
|
||||
do {
|
||||
const response = await closeApiCall<{
|
||||
cursor?: string;
|
||||
data: Record<string, any>[];
|
||||
}>({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/data/search/',
|
||||
body: {
|
||||
_limit: 100,
|
||||
cursor,
|
||||
...searchQuery,
|
||||
},
|
||||
});
|
||||
|
||||
const { data } = response;
|
||||
if (!data || data.length === 0) break;
|
||||
|
||||
result.push(...data);
|
||||
cursor = response.cursor;
|
||||
} while (cursor);
|
||||
|
||||
return {
|
||||
found: result.length > 0,
|
||||
result,
|
||||
};
|
||||
} catch (error: any) {
|
||||
if (error.response?.status === 400) {
|
||||
throw new Error(`Invalid search query: ${error.response.body?.error || 'Unknown error'}`);
|
||||
}
|
||||
if (error.response?.status === 401) {
|
||||
throw new Error('Authentication failed. Please check your API key.');
|
||||
}
|
||||
if (error.response?.status === 404) {
|
||||
throw new Error('No leads found matching your criteria.');
|
||||
}
|
||||
throw new Error(`Failed to search leads: ${error.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Helper function to build the lead search query
|
||||
function buildLeadSearchQuery(params: {
|
||||
search_type: string;
|
||||
search_query: string;
|
||||
match_type: string;
|
||||
custom_field_name?: string;
|
||||
}): CloseCRMSearchQuery {
|
||||
const { search_type, search_query, match_type, custom_field_name } = params;
|
||||
|
||||
const baseQuery = {
|
||||
type: 'object_type',
|
||||
object_type: 'lead',
|
||||
};
|
||||
|
||||
let fieldCondition;
|
||||
|
||||
switch (search_type) {
|
||||
case 'name':
|
||||
fieldCondition = {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'lead',
|
||||
field_name: 'name',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'full_words',
|
||||
value: search_query,
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'contact_email':
|
||||
fieldCondition = {
|
||||
type: 'has_related',
|
||||
this_object_type: 'lead',
|
||||
related_object_type: 'contact',
|
||||
related_query: {
|
||||
type: 'has_related',
|
||||
this_object_type: 'contact',
|
||||
related_object_type: 'contact_email',
|
||||
related_query: {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'contact_email',
|
||||
field_name: 'email',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'phrase',
|
||||
value: search_query,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
fieldCondition = {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'lead',
|
||||
field_name: 'status_label',
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'phrase',
|
||||
value: search_query,
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
case 'custom_field':
|
||||
fieldCondition = {
|
||||
type: 'field_condition',
|
||||
field: {
|
||||
type: 'regular_field',
|
||||
object_type: 'lead',
|
||||
field_name: custom_field_name!,
|
||||
},
|
||||
condition: {
|
||||
type: 'text',
|
||||
mode: 'full_words',
|
||||
value: search_query,
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported search type: ${search_type}`);
|
||||
}
|
||||
|
||||
return {
|
||||
query: {
|
||||
type: 'and',
|
||||
queries: [baseQuery, fieldCondition],
|
||||
},
|
||||
_fields: {
|
||||
lead: ['id', 'name', 'status_label', 'contacts'],
|
||||
contact: ['id', 'name', 'emails', 'phones'],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMessageBody,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
export type CloseApiCallParams = {
|
||||
accessToken: string;
|
||||
method: HttpMethod;
|
||||
resourceUri: string;
|
||||
query?: Record<string, string | number | string[] | undefined>;
|
||||
body?: any;
|
||||
};
|
||||
|
||||
export const CLOSE_API_URL = 'https://api.close.com/api/v1';
|
||||
|
||||
export async function closeApiCall<T extends HttpMessageBody>({
|
||||
accessToken,
|
||||
method,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
}: CloseApiCallParams): Promise<T> {
|
||||
const qs: QueryParams = {};
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
qs[key] = String(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: CLOSE_API_URL + resourceUri,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username: accessToken,
|
||||
password: '',
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function closePaginatedApiCall<T extends HttpMessageBody>({
|
||||
accessToken,
|
||||
method,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
}: CloseApiCallParams): Promise<T[]> {
|
||||
const resultData: T[] = [];
|
||||
const limit = 100;
|
||||
let skip = 0;
|
||||
let hasMore = true;
|
||||
|
||||
do {
|
||||
const response = await closeApiCall<{ data: T[]; has_more: boolean }>({
|
||||
accessToken,
|
||||
method,
|
||||
resourceUri,
|
||||
query: { ...query, _limit: limit, _skip: skip },
|
||||
body,
|
||||
});
|
||||
const { data, has_more } = response;
|
||||
if (!data || data.length === 0) break;
|
||||
|
||||
resultData.push(...data);
|
||||
hasMore = has_more;
|
||||
skip += limit;
|
||||
} while (hasMore);
|
||||
|
||||
return resultData;
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import { DynamicPropsValue, Property } from '@activepieces/pieces-framework';
|
||||
import { closePaginatedApiCall } from './client';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../..';
|
||||
|
||||
export const customFields = (objectType: string) =>
|
||||
Property.DynamicProperties({
|
||||
displayName: 'Custom Fields',
|
||||
refreshers: [],
|
||||
required: false,
|
||||
auth: closeAuth,
|
||||
props: async ({ auth }) => {
|
||||
if (!auth) return {};
|
||||
|
||||
const fields: DynamicPropsValue = {};
|
||||
|
||||
const response = await closePaginatedApiCall<{
|
||||
id: string;
|
||||
type: string;
|
||||
choices?: string[];
|
||||
accepts_multiple_values: boolean;
|
||||
name: string;
|
||||
}>({
|
||||
accessToken: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/custom_field/${objectType}/`,
|
||||
});
|
||||
|
||||
for (const field of response) {
|
||||
switch (field.type) {
|
||||
case 'number':
|
||||
fields[field.id] = Property.Number({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
});
|
||||
break;
|
||||
case 'text':
|
||||
fields[field.id] = Property.ShortText({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
});
|
||||
break;
|
||||
case 'textarea':
|
||||
fields[field.id] = Property.LongText({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
});
|
||||
break;
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
fields[field.id] = Property.DateTime({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
});
|
||||
break;
|
||||
case 'choices': {
|
||||
const fieldType = field.accepts_multiple_values
|
||||
? Property.StaticMultiSelectDropdown
|
||||
: Property.StaticDropdown;
|
||||
fields[field.id] = fieldType({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: field.choices
|
||||
? field.choices.map((choice) => ({
|
||||
label: choice,
|
||||
value: choice,
|
||||
}))
|
||||
: [],
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'contact':
|
||||
case 'user': {
|
||||
const fieldType = field.accepts_multiple_values ? Property.Array : Property.ShortText;
|
||||
fields[field.id] = fieldType({
|
||||
displayName: field.name,
|
||||
required: false,
|
||||
description: `Provide ${field.type} ID.`,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
});
|
||||
|
||||
export const statusId = (objectType: string, required = false) =>
|
||||
Property.Dropdown({
|
||||
auth: closeAuth,
|
||||
displayName: 'Status',
|
||||
refreshers: [],
|
||||
required,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const response = await closePaginatedApiCall<{
|
||||
id: string;
|
||||
label: string;
|
||||
}>({
|
||||
accessToken: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/status/${objectType}/`,
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.map((status) => ({
|
||||
label: status.label,
|
||||
value: status.id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const leadId = (required = false) =>
|
||||
Property.Dropdown({
|
||||
auth: closeAuth,
|
||||
displayName: 'Lead',
|
||||
required,
|
||||
refreshers: ['auth'],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please authenticate first.',
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await closePaginatedApiCall<{
|
||||
id: string;
|
||||
name: string;
|
||||
}>({
|
||||
accessToken: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/lead/?_fields=id,name',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.map((lead) => ({
|
||||
label: lead.name,
|
||||
value: lead.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Could not fetch leads. Check your connection.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const userId = (required = false) =>
|
||||
Property.Dropdown({
|
||||
auth: closeAuth,
|
||||
displayName: 'User',
|
||||
required,
|
||||
refreshers: ['auth'],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please authenticate first.',
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await closePaginatedApiCall<{
|
||||
id: string;
|
||||
email: string;
|
||||
}>({
|
||||
accessToken: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/user/?_fields=id,email',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.map((user) => ({
|
||||
label: user.email,
|
||||
value: user.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Could not fetch uers. Check your connection.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,194 @@
|
||||
export interface CloseCRMLead {
|
||||
id: string;
|
||||
contacts?: {
|
||||
name: string;
|
||||
emails?: { email: string }[];
|
||||
phones?: { phone: string }[];
|
||||
}[];
|
||||
[key: string]: unknown; // For custom fields
|
||||
}
|
||||
|
||||
export interface CloseCRMClient {
|
||||
post(endpoint: string, data: unknown): Promise<{ data: unknown }>;
|
||||
// Add other methods as needed
|
||||
}
|
||||
|
||||
export interface CloseCRMEmailActivity {
|
||||
lead_id: string;
|
||||
direction: 'outgoing' | 'incoming';
|
||||
note: string;
|
||||
date_created: string;
|
||||
_type: 'email';
|
||||
email: {
|
||||
subject: string;
|
||||
body: string;
|
||||
sender?: string;
|
||||
to: Array<{
|
||||
email: string;
|
||||
name?: string;
|
||||
}>;
|
||||
attachments?: Array<{
|
||||
name: string;
|
||||
url: string;
|
||||
size?: number;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CloseCRMLeadWebhookPayload {
|
||||
subscription_id: string;
|
||||
event: {
|
||||
id: string;
|
||||
action: 'created' | 'updated' | 'deleted';
|
||||
object_type: 'lead';
|
||||
object_id: string;
|
||||
date_created: string;
|
||||
data: {
|
||||
id: string;
|
||||
name: string;
|
||||
status_label?: string;
|
||||
status_id?: string;
|
||||
contacts?: Array<string | ContactDetails>;
|
||||
date_created: string;
|
||||
date_updated: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface ContactDetails {
|
||||
id: string;
|
||||
name: string;
|
||||
emails?: Array<{ email: string; type?: string }>;
|
||||
phones?: Array<{ phone: string; type?: string }>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
//Contact name
|
||||
export interface CloseCRMContact {
|
||||
lead_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
emails?: {
|
||||
email: string;
|
||||
type?: 'direct' | 'home' | 'other' | 'office';
|
||||
}[];
|
||||
phones?: {
|
||||
phone: string;
|
||||
type?: 'mobile' | 'office' | 'home' | 'fax' | 'other' | 'direct';
|
||||
}[];
|
||||
urls?: {
|
||||
url: string;
|
||||
type?: 'website' | 'linkedin' | 'twitter' | 'other' | 'url';
|
||||
}[];
|
||||
[key: string]: unknown; // For custom fields
|
||||
}
|
||||
|
||||
//contact search query
|
||||
export interface CloseCRMSearchQuery {
|
||||
query: {
|
||||
type: string;
|
||||
queries: any[];
|
||||
};
|
||||
_fields: {
|
||||
contact: string[];
|
||||
lead: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface CloseCRMSearchQuery {
|
||||
query: {
|
||||
type: string;
|
||||
queries: any[];
|
||||
};
|
||||
}
|
||||
|
||||
//NEW-CONTACT-ADDED
|
||||
|
||||
export interface CloseCRMContactWebhookPayload {
|
||||
subscription_id: string;
|
||||
event: {
|
||||
id: string;
|
||||
action: 'created' | 'updated' | 'deleted';
|
||||
object_type: 'contact';
|
||||
object_id: string;
|
||||
lead_id: string;
|
||||
date_created: string;
|
||||
data: {
|
||||
id: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
lead_id: string;
|
||||
emails?: Array<{ email: string; type?: string }>;
|
||||
phones?: Array<{ phone: string; type?: string }>;
|
||||
date_created: string;
|
||||
date_updated: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//find opportunity
|
||||
|
||||
export interface CloseCRMOpportunity {
|
||||
lead_id: string;
|
||||
lead_name?: string;
|
||||
status_id?: string;
|
||||
status_label?: string;
|
||||
status_type?: 'active' | 'won' | 'lost' | 'archived';
|
||||
pipeline_id?: string;
|
||||
pipeline_name?: string;
|
||||
user_id?: string;
|
||||
user_name?: string;
|
||||
contact_id?: string;
|
||||
value?: number;
|
||||
value_period?: 'one_time' | 'monthly' | 'annual';
|
||||
value_formatted?: string;
|
||||
expected_value?: number;
|
||||
annualized_value?: number;
|
||||
annualized_expected_value?: number;
|
||||
confidence?: number;
|
||||
note?: string;
|
||||
date_created?: string;
|
||||
date_updated?: string;
|
||||
date_won?: string;
|
||||
}
|
||||
|
||||
//opportunity-status changed
|
||||
export interface CloseCRMOpportunityWebhookPayload {
|
||||
subscription_id: string;
|
||||
event: {
|
||||
id: string;
|
||||
action: 'created' | 'updated' | 'deleted';
|
||||
object_type: 'opportunity';
|
||||
object_id: string;
|
||||
lead_id: string;
|
||||
payload_id: string;
|
||||
date_created: string;
|
||||
changed_fields: string[];
|
||||
previous_data?: {
|
||||
status_type?: string;
|
||||
status_label?: string;
|
||||
status_id?: string;
|
||||
value?: number;
|
||||
confidence?: number;
|
||||
};
|
||||
data: {
|
||||
id: string;
|
||||
lead_id: string;
|
||||
status_type: 'active' | 'won' | 'lost' | 'archived';
|
||||
status_label: string;
|
||||
status_id: string;
|
||||
value?: number;
|
||||
value_currency?: string;
|
||||
value_formatted?: string;
|
||||
contact_id?: string;
|
||||
contact_name?: string;
|
||||
lead_name?: string;
|
||||
date_won?: string;
|
||||
date_lost?: string;
|
||||
confidence?: number;
|
||||
date_created: string;
|
||||
date_updated: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
export const verifySignature = (
|
||||
signatureKey?: string, // hex-encoded key
|
||||
timestamp?: string, // 'close-sig-timestamp' header
|
||||
rawBody?: any, // raw body as string
|
||||
signatureHash?: string, // 'close-sig-hash' header
|
||||
): boolean => {
|
||||
if (!signatureKey || !timestamp || !rawBody || !signatureHash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const dataToHmac = timestamp + rawBody;
|
||||
|
||||
const generatedHash = crypto
|
||||
.createHmac('sha256', Buffer.from(signatureKey, 'hex'))
|
||||
.update(dataToHmac, 'utf8')
|
||||
.digest('hex');
|
||||
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(generatedHash, 'hex'),
|
||||
Buffer.from(signatureHash, 'hex'),
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
import { TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { CloseCRMContactWebhookPayload } from '../common/types';
|
||||
import { closeApiCall } from '../common/client';
|
||||
import { verifySignature } from './helpers';
|
||||
|
||||
const TRIGGER_KEY = 'new-contact-trigger';
|
||||
|
||||
export const newContactAdded = createTrigger({
|
||||
auth: closeAuth,
|
||||
name: 'new_contact_added',
|
||||
displayName: 'New Contact Added',
|
||||
description: 'Triggers when a new contact is created.',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
async onEnable(context) {
|
||||
const response = await closeApiCall<{ id: string; signature_key: string }>({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/webhook/',
|
||||
body: {
|
||||
url: context.webhookUrl,
|
||||
events: [
|
||||
{
|
||||
object_type: 'contact',
|
||||
action: 'created',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const { id, signature_key: signatureKey } = response;
|
||||
await context.store.put<{ id: string; signatureKey: string }>(TRIGGER_KEY, {
|
||||
id,
|
||||
signatureKey,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
if (triggerData?.id) {
|
||||
await closeApiCall({
|
||||
method: HttpMethod.DELETE,
|
||||
accessToken: context.auth.secret_text,
|
||||
resourceUri: `/webhook/${triggerData.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
const signatureKey = triggerData?.signatureKey;
|
||||
const signatureHash = context.payload.headers['close-sig-hash'];
|
||||
const timestamp = context.payload.headers['close-sig-timestamp'];
|
||||
const rawBody = context.payload.rawBody;
|
||||
|
||||
if (!verifySignature(signatureKey, timestamp, rawBody, signatureHash)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const payload = context.payload.body as CloseCRMContactWebhookPayload;
|
||||
|
||||
// Verify this is a lead creation event
|
||||
if (payload.event.object_type !== 'contact' || payload.event.action !== 'created') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const contact = await closeApiCall({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/contact/${payload.event.data.id}/`,
|
||||
});
|
||||
|
||||
return [contact];
|
||||
},
|
||||
|
||||
sampleData: {
|
||||
created_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
date_created: '2025-05-30T15:29:16.048000+00:00',
|
||||
date_updated: '2025-05-30T15:29:16.048000+00:00',
|
||||
display_name: 'John Doe',
|
||||
emails: [
|
||||
{
|
||||
email: 'johndoe@gmail.com',
|
||||
is_unsubscribed: false,
|
||||
type: 'office',
|
||||
},
|
||||
{
|
||||
email: 'johndoe@gmail.com',
|
||||
is_unsubscribed: false,
|
||||
type: 'direct',
|
||||
},
|
||||
],
|
||||
id: 'cont_SNLEuIxMqrgu23m1D63rnE84ivTYlXm3pPRJXHWhGqn',
|
||||
integration_links: [
|
||||
{
|
||||
name: 'LinkedIn Search',
|
||||
url: 'https://www.linkedin.com/search/results/people/?keywords=JohnDoe',
|
||||
},
|
||||
],
|
||||
lead_id: 'lead_Tn9KvxpJ2InYrwOb81TIoOuAoEchLPFJS72i0xMK2vj',
|
||||
name: 'John Doe',
|
||||
organization_id: 'orga_qwPaunJJ8R6NPPVQj6Q0KicVJQtyWM45dMnH9HsWZBl',
|
||||
phones: [
|
||||
{
|
||||
country: 'IN',
|
||||
phone: '',
|
||||
phone_formatted: '+911541',
|
||||
type: 'mobile',
|
||||
},
|
||||
],
|
||||
title: 'Test',
|
||||
updated_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
urls: [
|
||||
{
|
||||
type: 'url',
|
||||
url: 'https://www.github.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import { TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../../';
|
||||
import { CloseCRMLeadWebhookPayload } from '../common/types';
|
||||
import { closeApiCall } from '../common/client';
|
||||
import { verifySignature } from './helpers';
|
||||
|
||||
const TRIGGER_KEY = 'new-lead-trigger';
|
||||
|
||||
export const newLeadAdded = createTrigger({
|
||||
auth: closeAuth,
|
||||
name: 'new_lead_created',
|
||||
displayName: 'New Lead Created',
|
||||
description: 'Triggers when a new lead is created.',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
async onEnable(context) {
|
||||
const response = await closeApiCall<{ id: string; signature_key: string }>({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/webhook/',
|
||||
body: {
|
||||
url: context.webhookUrl,
|
||||
events: [
|
||||
{
|
||||
object_type: 'lead',
|
||||
action: 'created',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const { id, signature_key: signatureKey } = response;
|
||||
await context.store.put<{ id: string; signatureKey: string }>(TRIGGER_KEY, {
|
||||
id,
|
||||
signatureKey,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
if (triggerData?.id) {
|
||||
await closeApiCall({
|
||||
method: HttpMethod.DELETE,
|
||||
accessToken: context.auth.secret_text,
|
||||
resourceUri: `/webhook/${triggerData.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
const signatureKey = triggerData?.signatureKey;
|
||||
const signatureHash = context.payload.headers['close-sig-hash'];
|
||||
const timestamp = context.payload.headers['close-sig-timestamp'];
|
||||
const rawBody = context.payload.rawBody;
|
||||
|
||||
if (!verifySignature(signatureKey, timestamp, rawBody, signatureHash)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const payload = context.payload.body as CloseCRMLeadWebhookPayload;
|
||||
|
||||
// Verify this is a lead creation event
|
||||
if (payload.event.object_type !== 'lead' || payload.event.action !== 'created') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const lead = await closeApiCall({
|
||||
accessToken: context.auth.secret_text ,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/lead/${payload.event.data.id}/`,
|
||||
});
|
||||
|
||||
return [lead];
|
||||
},
|
||||
|
||||
sampleData: {
|
||||
addresses: [],
|
||||
contacts: [
|
||||
{
|
||||
created_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
date_created: '2025-05-30T15:30:40.148000+00:00',
|
||||
date_updated: '2025-05-30T15:30:40.148000+00:00',
|
||||
display_name: 'John Doe',
|
||||
emails: [
|
||||
{
|
||||
email: 'johndoe@gmail.com',
|
||||
is_unsubscribed: false,
|
||||
type: 'office',
|
||||
},
|
||||
],
|
||||
id: 'cont_p9jX6fiJ0AryAx06CwT9SY8OyA9PX29zmwXBw9ct3TR',
|
||||
lead_id: 'lead_fy3zdUuEFQ1WJEi846CGSvpePgzqm0P6XTPRDtSBFTC',
|
||||
name: 'John Doe',
|
||||
organization_id: 'orga_qwPaunJJ8R6NPPVQj6Q0KicVJQtyWM45dMnH9HsWZBl',
|
||||
phones: [
|
||||
{
|
||||
country: 'IN',
|
||||
phone: '+91754',
|
||||
phone_formatted: '+91754',
|
||||
type: 'office',
|
||||
},
|
||||
],
|
||||
title: 'SDE',
|
||||
updated_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
urls: [
|
||||
{
|
||||
type: 'url',
|
||||
url: 'https://www.github.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
created_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
created_by_name: 'John Doe',
|
||||
custom: {
|
||||
'Current Vendor/Software': 'Close',
|
||||
'Custom Field': 'test',
|
||||
Industry: 'Healthcare',
|
||||
date: '2025-05-30',
|
||||
datetime: '2025-05-30T00:00:00+00:00',
|
||||
},
|
||||
date_created: '2025-05-30T15:30:40.122000+00:00',
|
||||
date_updated: '2025-05-30T15:35:33.131000+00:00',
|
||||
description: 'TESTING',
|
||||
display_name: 'John Doe',
|
||||
id: 'lead_fy3zdUuEFQ1WJEi846CGSvpePgzqm0P6XTPRDtSBFTC',
|
||||
integration_links: [
|
||||
{
|
||||
name: 'Google Search',
|
||||
url: 'https://google.com/search?q=HEllo%20KNOW',
|
||||
},
|
||||
],
|
||||
name: 'John Doe',
|
||||
opportunities: [],
|
||||
organization_id: 'orga_qwPaunJJ8R6NPPVQj6Q0KicVJQtyWM45dMnH9HsWZBl',
|
||||
status_id: 'stat_piNPXI7AsUxHHwhPJKdCTiQtZsRP96HGb088FzJCgEJ',
|
||||
status_label: 'Potential',
|
||||
tasks: [],
|
||||
updated_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
updated_by_name: 'John Doe',
|
||||
url: 'https://www.github.com',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import { TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { closeAuth } from '../..';
|
||||
import { CloseCRMOpportunityWebhookPayload } from '../common/types';
|
||||
import { closeApiCall } from '../common/client';
|
||||
import { verifySignature } from './helpers';
|
||||
|
||||
const TRIGGER_KEY = 'new-opportunity-trigger';
|
||||
|
||||
export const newOpportunityAdded = createTrigger({
|
||||
auth: closeAuth,
|
||||
name: 'new_opportunity_added',
|
||||
displayName: 'New Opportunity Added',
|
||||
description: 'Triggers when a new opportunity is created.',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
async onEnable(context) {
|
||||
const response = await closeApiCall<{ id: string; signature_key: string }>({
|
||||
accessToken: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/webhook/',
|
||||
body: {
|
||||
url: context.webhookUrl,
|
||||
events: [
|
||||
{
|
||||
object_type: 'opportunity',
|
||||
action: 'created',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const { id, signature_key: signatureKey } = response;
|
||||
await context.store.put<{ id: string; signatureKey: string }>(TRIGGER_KEY, {
|
||||
id,
|
||||
signatureKey,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
if (triggerData?.id) {
|
||||
await closeApiCall({
|
||||
method: HttpMethod.DELETE,
|
||||
accessToken: context.auth.secret_text,
|
||||
resourceUri: `/webhook/${triggerData.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const triggerData = await context.store.get<{
|
||||
id: string;
|
||||
signatureKey: string;
|
||||
}>(TRIGGER_KEY);
|
||||
|
||||
const signatureKey = triggerData?.signatureKey;
|
||||
const signatureHash = context.payload.headers['close-sig-hash'];
|
||||
const timestamp = context.payload.headers['close-sig-timestamp'];
|
||||
const rawBody = context.payload.rawBody;
|
||||
|
||||
if (!verifySignature(signatureKey, timestamp, rawBody, signatureHash)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const payload = context.payload.body as CloseCRMOpportunityWebhookPayload;
|
||||
|
||||
// Verify this is a lead creation event
|
||||
if (payload.event.object_type !== 'opportunity' || payload.event.action !== 'created') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const opportunity = await closeApiCall({
|
||||
accessToken: context.auth.secret_text ,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/opportunity/${payload.event.data.id}/`,
|
||||
});
|
||||
|
||||
return [opportunity];
|
||||
},
|
||||
|
||||
sampleData: {
|
||||
annualized_expected_value: 500,
|
||||
annualized_value: 1000,
|
||||
attachments: [],
|
||||
confidence: 50,
|
||||
contact_id: null,
|
||||
contact_name: null,
|
||||
created_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
created_by_name: 'john doe',
|
||||
'custom.cf_cJd1lRfCdIWTgJGLQ84lQZXiGw7ufhdXA2F907z9Mk8': 1,
|
||||
'custom.cf_gOgoyjtw8iShE434uBERAEcR6wFoacUtlVPWcPA2EXS': 'Basic',
|
||||
'custom.cf_lHRMHDYJVogylPbe6v0DCGcU7kMqz2RJUYnAhntKOOn': 10,
|
||||
'custom.cf_usm3RdC8hm7Pb6pYo9M8lKCN1h06Edij9OdzHphwAkM': [
|
||||
'Premium support',
|
||||
'Professional services',
|
||||
'Subscription',
|
||||
],
|
||||
date_created: '2025-05-30T15:53:52.829000+00:00',
|
||||
date_lost: null,
|
||||
date_updated: '2025-05-30T15:53:52.829000+00:00',
|
||||
date_won: null,
|
||||
expected_value: 500,
|
||||
id: 'oppo_NkuyMMFjRDaY5mYQ7bywfpOmiHWPQ0h02bxJoZGwTOS',
|
||||
integration_links: [],
|
||||
lead_id: 'lead_Tn9KvxpJ2InYrwOb81TIoOuAoEchLPFJS72i0xMK2vj',
|
||||
lead_name: 'TEST LEAD',
|
||||
note: 'Test',
|
||||
organization_id: 'orga_qwPaunJJ8R6NPPVQj6Q0KicVJQtyWM45dMnH9HsWZBl',
|
||||
pipeline_id: 'pipe_2kHJXqFpYKmONEWPQijcit',
|
||||
pipeline_name: 'Sales',
|
||||
status_display_name: 'Demo Completed',
|
||||
status_id: 'stat_uqaIpeqabvBXW32bpLZkcD7mhTRvCXqEF0oGQDvOKMG',
|
||||
status_label: 'Demo Completed',
|
||||
status_type: 'active',
|
||||
updated_by: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
updated_by_name: 'john doe',
|
||||
user_id: 'user_QO3f0LQE6fMbrokdE2awZLgT7pRv57S1C8Zv5Uo30TN',
|
||||
user_name: 'john doe',
|
||||
value: 1000,
|
||||
value_currency: 'USD',
|
||||
value_formatted: '$10',
|
||||
value_period: 'one_time',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user