Actions de workflow personnalisées

Utilisez l'outil Workflows de HubSpot pour automatiser les processus commerciaux et permettre à votre équipe d'être plus efficace. Vous pouvez créer des actions de workflow personnalisées pour intégrer votre service aux workflows de HubSpot.

Après avoir configuré votre action personnalisée, lorsque les utilisateurs installeront votre application, ils pourront ajouter l'action personnalisée à leurs workflows. 

Lorsque ces workflows seront exécutés, les demandes HTTPS seront envoyées à l'URL configurée avec la charge utile définie. Les demandes effectuées pour votre action personnalisée utiliseront la version 2 de X-HubSpot-Signature. Découvrez-en davantage sur la validation des demandes de HubSpot.

Vous pouvez également passer aux sections suivantes :

Avant de commencer

https://api.hubspot.com/automation/v4/actions/{appId}?hapikey={developer_API_key}

Définir votre action personnalisée

Pour créer une action de workflow personnalisée, vous devez définir l'action à l'aide des champs suivants. Cela indique également le format de demande pour les demandes provenant de HubSpot, ainsi que le traitement des réponses par votre service.

  • actionUrl : l'URL vers laquelle une demande HTTPS est envoyée lorsque l'action est exécutée. Le corps de la demande contient des informations sur l'utilisateur au nom duquel l'action est exécutée et sur les valeurs saisies pour les champs de saisie.
  • objectTypes : les objets CRM avec lesquels cette action peut être utilisée.
  • published : par défaut, les actions personnalisées sont créées dans un état non publié. Les actions non publiées ne sont visibles que dans le portail de développeur associé à votre application HubSpot. Pour rendre votre action personnalisée visible par les utilisateurs, mettez à jour l'indicateur published de votre définition d'action et définissez-le sur true.
  • inputFields : les entrées reçues par l'action. Celles-ci seront renseignées par l'utilisateur.
  • inputFieldDependencies : ces règles permettent de griser les champs jusqu'à ce que les autres champs répondent à des conditions spécifiques.
  • outboundFields : les valeurs résultantes de l'action qui peuvent être utilisées par des actions suivantes dans le workflow. Une action personnalisée peut avoir aucun, un ou plusieurs résultats.
  • objectRequestOptions : propriétés de l'objet inscrit incluses dans la charge utile de actionUrl.
  • labels : une copie qui décrit pour l'utilisateur ce que représentent les champs de l'action et ce que fait l'action. Des libellés en anglais sont requis, mais les libellés peuvent également être indiqués dans l'une de ces langues prises en charge : français (fr), allemand (de), japonais (ja), espagnol (es), portugais du Brésil (pt-br) et néerlandais (nl).
  • executionRules : une liste des définitions que vous pouvez spécifier pour identifier les erreurs de votre service vers l'utilisateur qui crée le workflow.
  • functions : les blocs de code qui sont exécutés afin de transformer la charge utile envoyée vers une URL et/ou de transformer la réponse à partir de cette URL.

Exemple de définition d'action personnalisée

// { "actionUrl":"https://webhook.site/94d09471-6f4c-4a7f-bae2-c9a585dd41e0", "objectTypes":[ "CONTACT" ], "inputFields":[ { "typeDefinition":{ "name":"staticInput", "type":"string", "fieldType":"text" }, "supportedValueTypes":[ "STATIC_VALUE" ], "isRequired":true }, { "typeDefinition":{ "name":"objectInput", "type":"string", "fieldType":"text" }, "supportedValueTypes":[ "OBJECT_PROPERTY" ], "isRequired":true }, { "typeDefinition":{ "name":"optionsInput", "type":"enumeration", "fieldType":"select", "optionsUrl":"https://webhook.site/94d09471-6f4c-4a7f-bae2-c9a585dd41e0" }, "supportedValueTypes":[ "STATIC_VALUE" ] } ], "inputFieldDependencies":[ { "dependencyType":"SINGLE_FIELD", "dependentFieldNames":[ "objectInput" ], "controllingFieldName":"staticInput" } ], "outputFields":[ { "typeDefinition":{ "name":"myOutput", "type":"string", "fieldType":"text" }, "supportedValueTypes":[ "STATIC_VALUE" ] } ], "objectRequestOptions":{ "properties":[ "email" ] }, "labels":{ "en":{ "inputFieldLabels":{ "staticInput":"Static Input", "objectInput":"Object Property Input", "optionsInput":"External Options Input" }, "actionName":"My Extension", "actionDescription":"My Extension Description", "appDisplayName":"My App Display Name", "actionCardContent":"My Action Card Content" } }, "functions":[ { "functionType":"POST_ACTION_EXECUTION", "functionSource":"exports.main = (event, callback) => {\r\n callback({\r\n outputFields: {\r\n myOutput: \"example output value\"\r\n }\r\n });\r\n}" }, { "functionType":"POST_FETCH_OPTIONS", "functionSource":"exports.main = (event, callback) => {\r\n callback({\r\n \"options\": [{\r\n \"label\": \"Big Widget\",\r\n \"description\": \"Big Widget\",\r\n \"value\": \"10\"\r\n },\r\n {\r\n \"label\": \"Small Widget\",\r\n \"description\": \"Small Widget\",\r\n \"value\": \"1\"\r\n }\r\n ]\r\n });\r\n}" } ] }

La définition ci-dessus restituera ce qui suit dans l'outil Workflows :

 

Il existe deux types d'appels effectués pour les actions de workflow personnalisées :

  • Récupérations d'options de champ : renseignez une liste des options valides lorsqu'un utilisateur configure un champ. Découvrez-en davantage sur l'utilisation des options de champ pour récupérer des champs de données externes. 
  • Demandes d'exécution d'action : effectué lorsqu'une action est exécutée par un workflow qui comprend votre action personnalisée. 

Fonctions

Les fonctions sont des blocs de code utilisés pour modifier les charges utiles avant de les envoyer à une API. Vous pouvez également utiliser des fonctions pour analyser les résultats d'une API. Les fonctions de HubSpot reposent sur AWS Lambda. Dans le code suivant :

  • event contient les données qui sont transmises à la fonction. 
  • exports.main est la méthode qui sera appelée lors de l'exécution de la fonction. 
  • La fonction callback peut être utilisée pour renvoyer un résultat.

Le code doit être formaté comme suit :

exports.main = (event, callback) => { callback({ "data": { "field": "email", "phone": "1234567890" } }); }

Lors de la configuration d'une fonction, le format functionSource sera dans la chaîne. Assurez-vous que les caractères du code ont été échappés.

Généralement, la définition d'une fonction suit le format suivant : 

// { "functionType":"PRE_ACTION_EXECUTION", "functionSource":"exports.main = (event, callback) => {\r\n callback({\r\n \"data\": {\r\n \"field\": \"email\",\r\n \"phone\": \"1234567890\" \r\n }\r\n });\r\n" }

Exemple de fonction

Dans l'exemple ci-dessous, examinez le code saisi, la fonction utilisée et le résultat.  

Saisie de fonction : 

// { "callbackId": "ap-102670506-56777914962-11-0", "origin": { "portalId": 102670506, "actionDefinitionId": 10860211, "actionDefinitionVersion": 1, "extensionDefinitionId": 10860211, "extensionDefinitionVersionId": 1 }, "context": { "source": "WORKFLOWS", "workflowId": 192814114 }, "object": { "objectId": 614, "objectType": "CONTACT" }, "inputFields": { "widgetOwner": "10887165", "widgetName": "My Widget Name" } }

Fonction utilisée : 

// exports.main = (event, callback) => { callback({ "data": { "myObjectId": event["object"]["objectId"], "myField": event["inputFields"]["widgetName"] } }); }

Résultats escomptés :

// { "data":{ "myObjectId":614, "myField":"My Widget Name" } }

Champs de saisie

Les définitions des champs de saisie seront conformes au format suivant :

  • name : le nom interne du champ de saisie, différent de son libellé. Le libellé affiché dans l'interface utilisateur doit être défini à l'aide de la section Libellés de la définition d'action personnalisée.
  • type : le type de valeur requis par la saisie.
  • fieldType : comment le champ de saisie doit être rendu dans l'interface utilisateur.  Les champs de saisie imitent les propriétés CRM. Découvrez-en davantage sur les combinaisons valides entre type et fieldType.
  • supportedValueTypes compte deux valeurs valides :
    • OBJECT_PROPERTY : l'utilisateur peut sélectionner une propriété à partir de l'objet inscrit ou un résultat d'une action précédente à utiliser comme valeur du champ.
    • STATIC_VALUE : doit être utilisé dans tous les autres cas. Cela signifie que l'utilisateur doit saisir lui-même une valeur. 
  • isRequired : cela détermine si l'utilisateur doit donner ou non une valeur pour cette entrée.

Les définitions des champs de saisie doivent être formatées comme suit : 

// { "typeDefinition":{ "name":"staticInput", "type":"string", "fieldType":"text" }, "supportedValueTypes":[ "STATIC_VALUE" ], "isRequired":true }

Vous pouvez également coder des options en dur pour l'utilisateur : 

// { "typeDefinition":{ "name":"widgetColor", "type":"enumeration", "fieldType":"select", "options":[ { "value":"red", "label":"Red" }, { "value":"blue", "label":"Blue" }, { "value":"green", "label":"Green" } ] }, "supportedValueTypes":[ "STATIC_VALUE" ] }

Utiliser des données externes

Au lieu de coder des options de champ en dur, vous pouvez également récupérer des données externes avec des champs de données externes. Par exemple, vous pouvez récupérer une liste de projets de réunion ou une liste de produits pour vos saisies. Le champ de saisie doit être formaté comme suit : 

// { "typeDefinition":{ "name":"optionsInput", "type":"enumeration", "fieldType":"select", "optionsUrl":"https://your-url-here.com" }, "supportedValueTypes":[ "STATIC_VALUE" ] }

La charge utile envoyée à optionsURL sera formatée comme suit :

// { "origin": { // The customer's portal ID "portalId": 1, // Your custom action definition ID "actionDefinitionId": 2, // Your custom action definition version "actionDefinitionVersion": 3 }, // The workflow object type the action is being used in "objectTypeId" : "0-1" // The input field you are fetching options for "inputFieldName": "optionsInput", // The values for the fields that have already been filled out by the workflow user "inputFields": { "widgetName": { "type": "OBJECT_PROPERTY", "propertyName": "widget_name" }, "widgetColor": { "type": "STATIC_VALUE", "value": "blue" } }, "fetchOptions": { // The search query provided by the user. This should be used to filter the returned // options. This will only be included if the previous option fetch returned // `searchable: true` and the user has entered a search query. "q": "option label", // The pagination cursor. This will be the same pagination cursor that was returned by // the previous option fetch; it can be used to keep track of which options have already // been fetched. "after": "1234=" } }

La réponse attendue devrait être formatée comme suit : 

// { "options": [ { "label": "Big Widget", "description": "Big Widget", "value": "10" }, { "label": "Small Widget", "description": "Small Widget", "value": "1" } ], // Optional. The pagination cursor. If this is provided, the Workflows app will render // a button to load more results at the bottom of the list of options when a user is // selecting an option, and when the next page is loaded this value will be included in // the request payload under `fetchOptions.after`. "after": "1234=", // Optional. Default is false. If this is true, the Workflows app will render a search // field to allow a user to filter the available options by a search query, and when // a search query is entered by the user, options will be re-fetched with that search // term in the request payload under `fetchOptions.q`. "searchable": true }

Dans le code ci-dessus, notez qu'une pagination est définie pour limiter le nombre d'options renvoyées. Cela indique au workflow que davantage d'options peuvent être chargées.

De plus, la liste des options est consultable en incluant le code searchable:true.

Modifier des données externes

Pour gérer les données externes, vous pouvez inclure deux hooks pour personnaliser le cycle de vie de la récupération d'options de champ :

  • PRE_FETCH_OPTIONS : une fonction qui configure la charge utile envoyée depuis HubSpot.
  • POST_FETCH_OPTIONS : une fonction qui transforme la réponse de votre service dans un format pris en charge par HubSpot.

 

PRE_FETCH_OPTIONS

Lorsqu'elle est incluse, cette fonction s'appliquera à chaque champ de saisie. Vous pouvez l'appliquer à un champ de saisie spécifique en spécifiant un id dans la définition de fonction.

// { "functionType":"PRE_FETCH_OPTIONS", "functionSource":"...", id: "inputField" }

La charge utile envoyée depuis HubSpot sera formatée comme suit :

// { "origin": { // The customer's portal ID "portalId": 1, // Your custom action definition ID "actionDefinitionId": 2, // Your custom action definition version "actionDefinitionVersion": 3 }, // The input field you are fetching options for "inputFieldName": "optionsInput", // Your configured external data field webhook URL "webhookUrl": "https://myapi.com/hubspot/widget-sizes", // The values for the fields that have already been filled out by the workflow user "inputFields": { "widgetName": { "type": "OBJECT_PROPERTY", "propertyName": "widget_name" }, "widgetColor": { "type": "STATIC_VALUE", "value": "blue" }, "fetchOptions": { // The search query provided by the user. This should be used to filter the returned // options. This will only be included if the previous option fetch returned // `searchable: true` and the user has entered a search query. "q": "option label", // The pagination cursor. This will be the same pagination cursor that was returned by // the previous option fetch; it can be used to keep track of which options have already // been fetched. "after": "1234=" } } }

La réponse doit ensuite être formatée comme suit :

// { // The webhook URL for HubSpot to call "webhookUrl": "https://myapi.com/hubspot", // Optional. The request body. "body": "{\"widgetName\": \"My new widget\", \"widgetColor\": \"blue\"}", // Optional. A map of custom request headers to add. "httpHeaders": { "My-Custom-Header": "header value" }, // Optional. The Content-Type of the request. Default is application/json. "contentType": "application/json", // Optional. The Accept type of the request. Default is application/json. "accept": "application/json", // Optional. The HTTP method with which to make the request. // Valid values are GET, POST, PUT, PATCH, and DELETE. // Default is POST. "httpMethod": "POST" }

POST_FETCH_OPTIONS

Pour analyser la réponse dans un format attendu, en fonction des champs de données externes, utilisez une fonction POST_FETCH_OPTIONS. La définition d'une fonction POST_FETCH_OPTIONS est identique à celle d'une fonction PRE_FETCH_OPTIONS.  Lorsque des options de récupération de données externes sont définies, un menu déroulant sera affiché dans les options de saisie pour l'action. 

// { "functionType":"POST_FETCH_OPTIONS", "functionSource":"...", id: "inputField" }

La saisie de fonction sera formatée comme suit :

// { // The requested field key "fieldKey": "widgetSize", // The webhook response body from your service "responseBody": "{\"widgetSizes\": [10, 1]}" }

La sortie de fonction sera formatée comme suit :

// { "options": [ { "label": "Big Widget", "description": "Big Widget", "value": "10" }, { "label": "Small Widget", "description": "Small Widget", "value": "1" } ] }

Champs de sortie

Utilisez les champs de sortie pour générer des valeurs de votre action personnalisée à utiliser dans d'autres actions. La définition des champs de sortie est similaire à la définition des champs de saisie : 

  • name : référencement de ce champ dans d'autres parties de l'action personnalisée. Le libellé affiché dans l'interface utilisateur doit être défini à l'aide de la section Libellés de l'action personnalisée. 
  • type : le type de valeur requis par la saisie.
  • fieldType : comment le champ de saisie doit être rendu dans l'interface utilisateur. Les champs de saisie imitent les propriétés CRM. Découvrez-en davantage sur les combinaisons valides entre type et fieldType.

Le champ de sortie doit être formaté comme suit : 

// { "outputFields":[ { "typeDefinition":{ "name":"myOutput", "type":"string", "fieldType":"text" } } ] }

Lors de l'utilisation d'un champ de sortie, les valeurs sont analysées à partir de la réponse de actionURL. Par exemple, vous pouvez copier des champs de sortie dans une propriété existante dans HubSpot.  

Libellés

Utilisez des libellés pour ajouter du texte à vos sorties ou entrées dans l'éditeur de workflow. Les libellés sont chargés dans le service de langue de HubSpot et leur affichage peut prendre quelques minutes. Les portails configurés pour différentes régions ou langues afficheront le libellé dans la langue correspondante, le cas échéant. 

  • labels : une copie qui décrit ce que représentent les champs de l'action et ce que fait l'action. Des libellés en anglais sont requis, mais les libellés peuvent également être indiqués dans l'une de ces langues prises en charge : français (fr), allemand (de), japonais (ja), espagnol (es), portugais du Brésil (pt-br) et néerlandais (nl).
  • actionName : nom de l'action affiché dans le panneau Sélectionner une action de l'éditeur de workflow.
  • actionDescription : une description détaillée de l'action affichée lorsque l'utilisateur configure l'action personnalisée.
  • actionCardContent : une description récapitulative affichée dans la carte de l'action.
  • appDisplayName : le nom de la section du panneau Choisir une action où toutes les actions de l'application sont affichées. Si appDisplayName est défini pour plusieurs actions, la première trouvée est utilisée.  
  • inputFieldLabels : un objet qui regroupe les définitions de inputFields vers les libellés correspondants que l'utilisateur verra lors de la configuration de l'action.
  • outputFieldLabels : un objet qui regroupe les définitions de outputFields vers les libellés correspondants indiqués dans l'outil Workflows.
  • inputFieldDescriptions : un objet qui regroupe les définitions de inputFields vers les descriptions sous les libellés correspondants.
  • executionRules : un objet qui regroupe les définitions de executionRules vers des messages qui seront affichés pour les résultats d'exécution d'action dans l'historique du workflow. Il existe une section distincte dans ces documents pour les règles d'exécution. 

Les définitions des libellés doivent être formatées comme suit :

// { "labels":{ "en":{ "actionName":"Create Widget", "actionDescription":"This action will create a new widget in our system. So cool!", "actionCardContent":"Create widget {{widgetName}}", "appDisplayName":"My App Display Name", "inputFieldLabels":{ "widgetName":"Widget Name", "widgetOwner":"Widget Owner" }, "outputFieldLabels":{ "outputOne":"First Output" }, "inputFieldDescriptions":{ "widgetName":"Enter the full widget name. I support <a href=\"https://hubspot.com\">links</a> too." }, "executionRules":{ "alreadyExists":"The widget with name {{ widgetName }} already exists" } } } }

Exécution

Lorsqu'une exécution survient, une demande HTTPM est envoyée à actionUrl.

  • callbackId : un ID unique pour l'exécution spécifique. Si l'exécution de l'action personnalisée est bloquée, utilisez cet ID. 
  • objet : les valeurs des propriétés demandées dans objectRequestOptions.
  • InputFields : les valeurs pour les saisies que l'utilisateur a renseignées. 

La charge utile d'exécution sera formatée comme suit : 

// { "callbackId": "ap-102670506-56776413549-7-0", "origin": { "portalId": 102670506, "actionDefinitionId": 10646377, "actionDefinitionVersion": 1 }, "context": { "source": "WORKFLOWS", "workflowId": 192814114 }, "object": { "objectId": 904, "properties": { "email": "ajenkenbb@gnu.org" }, "objectType": "CONTACT" }, "inputFields": { "staticInput": "My Static Input", "objectInput": "995", "optionsInput": "1" } }

La réponse attendue devrait être formatée comme suit : 

// { "outputFields":{ "myOutput":"Some value", "hs_execution_state": "SUCCESS" } }

Lors de l'examen de la réponse d'exécution : 

  • outputFields : les valeurs des champs de sortie définis précédemment. Ces valeurs peuvent être utilisées dans des actions ultérieures. 
  • hs_execution_state : une valeur spéciale facultative qui peut être ajoutée à outputFields.  Il n'est pas possible de spécifier une nouvelle tentative. Seules les valeurs suivantes peuvent être ajoutées :
    • RÉSULTATS
    • FAIL_CONTINUE
    • BLOCK
    • ASYNC

SUCCESS et FAIL_CONTINUE indiquent que l'action est terminée et que le workflow doit passer à l'action suivante à exécuter. Si aucun statut d'exécution n'est spécifié, des codes de statut seront utilisés pour déterminer le résultat d'une action : 

  • Codes de statut 2xx : l'action a été correctement effectuée.
  • Codes de statut 4xx : l'action a échoué. Les codes de statut Taux limité 429 sont l'exception. Ces derniers sont traités comme des nouvelles tentatives et l'en-tête Retry-After est respecté.
  • Codes de statut 5xx : un problème temporaire est survenu avec le service et l'action sera relancée ultérieurement. Un système d'intervalle exponentiel est utilisé pour les nouvelles tentatives, qui se poursuivront pendant 3 jours au maximum avant d'échouer. 

Fonctions d'exécution

Utilisez les fonctions d'exécution pour formater les données avant de les envoyer vers actionURL et analysez les données de actionURL. Il existe deux types de fonctions d'exécution :

  • PRE_ACTION_EXECUTION
  • POST_ACTION_EXECUTION

Fonction PRE_ACTION_EXECUTION

Utilisez les fonctions PRE_ACTION_EXECUTION pour formater les données avant de les envoyer vers actionURL.

La définition de la fonction sera formatée comme suit :

// { "functionType":"PRE_ACTION_EXECUTION", "functionSource":"..." }

La saisie de fonction doit être formatée comme suit :

// { "webhookUrl": "https://actionurl.com/", "callbackId": "ap-102670506-56776413549-7-0", "origin": { "portalId": 102670506, "actionDefinitionId": 10646377, "actionDefinitionVersion": 1 }, "context": { "source": "WORKFLOWS", "workflowId": 192814114 }, "object": { "objectId": 904, "properties": { "email": "ajenkenbb@gnu.org" }, "objectType": "CONTACT" }, "inputFields": { "staticInput": "My Static Input", "objectInput": "995", "optionsInput": "1" } }

La sortie de fonction doit être formatée comme suit :

// { // The webhook URL for HubSpot to call "webhookUrl": "https://myapi.com/hubspot", // Optional. The request body. "body": "{\"widgetName\": \"My new widget\", \"widgetColor\": \"blue\"}", // Optional. A map of custom request headers to add. "httpHeaders": { "My-Custom-Header": "header value" }, // Optional. The Content-Type of the request. Default is application/json. "contentType": "application/json", // Optional. The Accept type of the request. Default is application/json. "accept": "application/json", // Optional. The HTTP method with which to make the request. // Valid values are GET, POST, PUT, PATCH, and DELETE. // Default is POST. "httpMethod": "POST" }

Fonction POST_ACTION_EXECUTION 

Après avoir reçu une réponse de actionURL, utilisez une fonction POST_ACTION_EXECUTION pour formater les données pour HubSpot.

La définition de la fonction sera formatée comme suit :

// { "functionType":"POST_ACTION_EXECUTION", "functionSource":"..." }

La saisie de fonction doit être formatée comme suit :

// { "responseBody": "{\r\n \"returnValue\":\"Hello World!\"\r\n}" }

The function output should be formatted as follows:

// { "outputFields":{ "myOutput":"Some value", "hs_execution_state": "SUCCESS" } }

Exécution asynchrone

Exécutez des actions de workflow personnalisées de manière asynchrone en bloquant, puis en finalisant l'action.

Bloquer l'exécution de l'action

Utilisez des actions personnalisées pour bloquer l'exécution du workflow. Au lieu d'exécuter l'action suivante dans le workflow une fois que votre action personnalisée a reçu une réponse completed (code de statut 2xx ou 4xx) de votre service, le workflow cessera d'exécuter (« bloquera ») cette inscription tant que vous n'indiquerez pas au workflow de poursuivre.

Lors du blocage, vous pouvez spécifier une valeur pour le champ hs_default_expiration, après quoi votre action personnalisée sera considérée comme expirée. L'exécution du workflow reprendra alors et l'action suivant votre action personnalisée sera exécutée, même si l'action n'est pas terminée. 

Pour bloquer une action personnalisée, la réponse de l'exécution de votre action doit avoir le format suivant :

// { "outputFields": { // Required. Must be BLOCK for your custom action to block execution. "hs_execution_state": "BLOCK", // Optional. If not provided, a default expiration of 1 week is used. // Must be specified in ISO 8601 Duration format. // See https://en.wikipedia.org/wiki/ISO_8601#Durations "hs_expiration_duration": "P1WT1H" } }

Terminer une exécution bloquée

Pour terminer une exécution d'action personnalisée bloquée, utilisez le point de terminaison suivant : /callbacks/{callbackId}/complete.

Formatez le corps de la demande comme suit :

// { "outputFields": { // Required. The final execution state. Valid values are SUCCESS // (to indicate that your custom action completed successfully) or // FAIL_CONTINUE (to indicate that there was a problem with your // custom action execution) "hs_execution_state": "SUCCESS" } }

Ajouter des messages d'exécution personnalisés avec des règles

Spécifiez des règles sur votre action qui déterminent le message à afficher sur la page d'historique des workflows lorsque l'action est exécutée.

Les règles seront associées aux valeurs de sortie de votre action.  Ces valeurs de sortie doivent être fournies dans le corps de réponse de actionURL, au format suivant :

// { "outputFields": { "errorCode": "ALREADY_EXISTS", "widgetName": "Test widget" } }

Les véritables messages peuvent être spécifiés dans la section Libellés de l'action personnalisée :

// { "labels": { "executionRules": { "alreadyExists": "The widget with name {{ widgetName }} already exists", "widgetWrongSize": "Wrong widget size", "widgetInvalidSize": "Invalid widget size" } } } }

Les règles executionRules seront testées dans l'ordre indiqué. S'il existe plusieurs correspondances, seul le message de la première règle correspondante s'affichera pour l'utilisateur.

La règle est associée lorsque le résultat d'exécution correspond à une valeur spécifique dans la règle. Prenons l'exemple de cet ensemble de règles executionRules :

// [ { // This matches the key of a label on the action's `labels.LANGUAGE.executionRules` map "labelName": "alreadyExists", "conditions": { "errorCode": "ALREADY_EXISTS" } }, { "labelName": "widgetWrongSize", "conditions": { "errorCode": "WIDGET_SIZE", "sizeError": ["TOO_SMALL", "TOO_BIG"] } }, { "labelName": "widgetInvalidSize", "conditions": { "errorCode": "WIDGET_SIZE" } } ]

Les correspondances suivantes se produiront :

  • {"errorCode": "ALREADY_EXISTS", "widgetName": "Test widget"} : cela correspond à la première règle, car errorCode équivaut à ALREADY_EXISTS. Dans cet exemple, même s'il y a un résultat widgetName, il ne sera pas utilisé dans la définition de la règle. Ainsi, toute valeur sera autorisée.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "TOO_SMALL"} : cela correspond à la deuxième règle, car TOO_SMALL est l'un des éléments sizeError correspondants et errorCode est WIDGET_SIZE.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "NOT_A_NUMBER"} : cela correspond à la troisième règle, car même si errorCode est WIDGET_SIZE, sizeError ne correspond pas à l'une des valeurs spécifiées par la deuxième règle (TOO_SMALL ou TOO_BIG).

Ce mécanisme correspondant vous permet de spécifier des erreurs de secours afin que vous puissiez obtenir des erreurs spécifiques pour des cas d'erreur importants, mais des messages d'erreur plus génériques pour des erreurs moins courantes. Voici un exemple d'affichage du message personnalisé :

Tester et publier votre action personnalisée

Après avoir créé votre nouvelle action personnalisée, vous pouvez la tester et la publier. 

Tester des actions personnalisées avant publication 

Avant de publier votre action personnalisée, vous pouvez tester les options d'exécution et de récupération de l'action en pointant l'URL vers webhook.site. Cela vous permet d'inspecter la charge utile et de renvoyer une réponse spécifique. 

Vous pouvez également tester l'action dans votre portail de développeur en créant un workflow dans l'outil Workflows. Puis, ajoutez votre nouvelle action.

Lorsque vous avez terminé vos tests, il est recommandé d'archiver vos actions de test. Découvrez-en davantage sur les actions d'archivage dans la section Archiver une action personnalisée de l'onglet Points de terminaison.

Publier des actions personnalisées 

Par défaut, les actions personnalisées sont créées dans un état non publié. Les actions personnalisées non publiées ne sont visibles que dans le portail du développeur associé à l'application HubSpot correspondante. Pour rendre votre action personnalisée visible par les utilisateurs, mettez à jour l'indicateur published de votre définition d'action et définissez-le sur true. Si une action n'est pas publiée, les portails qui ont déjà ajouté l'action à leur workflow pourront toujours modifier et exécuter les actions déjà ajoutées. Cependant, ils ne seront pas en mesure d'ajouter l'action à nouveau. 

Example 1

A basic example with the following input fields, created for contact and deal workflows:

  • a static input field
  • a dropdown field with options
  • a field whose value is a HubSpot owner
  • a field whose value is pulled from a property (that the user creating the workflow selects) on the enrolled object.
// { "actionUrl": "https://example.com/hubspot", "inputFields": [ { "typeDefinition": { "name": "widgetName", "type": "string", "fieldType": "text" }, "supportedValueTypes": ["STATIC_VALUE"], "isRequired": true }, { "typeDefinition": { "name": "widgetColor", "type": "enumeration", "fieldType": "select", "options": [ { "value": "red", "label": "Red" }, { "value": "blue", "label": "Blue" }, { "value": "green", "label": "Green" } ] }, "supportedValueTypes": ["STATIC_VALUE"] }, { "typeDefinition": { "name": "widgetOwner", "type": "enumeration", "referencedObjectType": "OWNER" }, "supportedValueTypes": ["STATIC_VALUE"] }, { "typeDefinition": { "name": "widgetQuantity", "type": "number" }, "supportedValueTypes": ["OBJECT_PROPERTY"] } ], "labels": { "en": { "actionName": "Create Widget - Example 1", "actionDescription": "This action will create a new widget in our system. So cool!", "actionCardContent": "Create widget {{widgetName}}", "inputFieldLabels": { "widgetName": "Widget Name", "widgetColor": "Widget Color", "widgetOwner": "Widget Owner", "widgetQuantity": "Widget Quantity" }, "inputFieldDescriptions": { "widgetName": "Enter the full widget name. I support <a href=\"https://hubspot.com\">links</a> too.", "widgetColor": "This is the color that will be used to paint the widget." } } }, "objectTypes": ["CONTACT", "DEAL"] }

Exemple 2

L'action personnalisée suivante utilise une fonction sans serveur pour transformer la charge utile envoyée à l'élément actionUrl configuré. Étant donné qu'aucun élément objectTypes n'est spécifié, cette action sera disponible dans tous les types de workflow.

// { "actionUrl": "https://api.example.com/v1/widgets", "inputFields": [ { "typeDefinition": { "name": "widgetName", "type": "string", "fieldType": "text" }, "supportedValueTypes": ["STATIC_VALUE"], "isRequired": true } ], "labels": { "en": { "actionName": "Create Widget - Example 2", "actionCardContent": "Create widget {{widgetName}}", "inputFieldLabels": { "widgetName": "Widget Name" } } }, "functions": [ { "functionType": "PRE_ACTION_EXECUTION", "functionSource": "exports.main = function(event, callback) { return callback(transformRequest(event)); }\nfunction transformRequest(request) { return { webhookUrl: request.webhookUrl, body: JSON.stringify(request.fields), contentType: 'application/x-www-form-urlencoded', accept: 'application/json', httpMethod: 'POST' }; }" } ] }

Exemple 3

L'action personnalisée suivante contient des dépendances de champs et des options récupérées depuis une API. Étant donné que la taille du widget dépend de la couleur du widget, l'utilisateur ne pourra pas saisir une valeur pour la taille du widget tant qu'il n'aura pas choisi une couleur.

Le coût du widget dépend également de la couleur du widget, mais il dépend de la valeur que l'utilisateur sélectionne pour la couleur du widget. L'utilisateur ne pourra pas saisir une valeur pour le coût du widget, sauf si la couleur Red est sélectionnée comme couleur du widget.

// { "actionUrl": "https://example.com/hubspot", "inputFields": [ { "typeDefinition": { "name": "widgetName", "type": "string", "fieldType": "text" }, "supportedValueTypes": ["STATIC_VALUE"], "isRequired": true }, { "typeDefinition": { "name": "widgetColor", "type": "enumeration", "fieldType": "select", "options": [ { "value": "red", "description": "red", "label": "Red" }, { "value": "blue", "description": "blue", "label": "Blue" }, { "value": "green", "description": "green", "label": "Green" } ] }, "supportedValueTypes": ["STATIC_VALUE"], }, { "typeDefinition": { "name": "widgetSize", "type": "enumeration", "fieldType": "select", "optionsUrl": "https://api.example.com/v1/widget-sizes" }, "supportedValueTypes": ["STATIC_VALUE"] }, { "typeDefinition": { "name": "widgetCost", "type": "number", "fieldType": "number" }, "supportedValueTypes": ["OBJECT_PROPERTY"] } ], "inputFieldDependencies": [ { "dependencyType": "SINGLE_FIELD", "controllingFieldName": "widgetColor", "dependentFieldNames": ["widgetSize"] }, { "dependencyType": "CONDITIONAL_SINGLE_FIELD", "controllingFieldName": "widgetColor", "controllingFieldValue": "red", "dependentFieldNames": ["widgetCost"] } ], "labels": { "en": { "actionName": "Create Widget - Example 3", "actionCardContent": "Create widget {{widgetName}}", "inputFieldLabels": { "widgetName": "Widget Name", "widgetColor": "Widget Color", "widgetSize": "Widget Size", "widgetCost": "Widget Cost" } } }, "objectTypes": ["CONTACT", "DEAL"], "functions": [ { "functionType": "PRE_FETCH_OPTIONS", "id": "widgetSize", "functionSource": "exports.main = function(event, callback) { return callback(transformRequest(event)); }\nfunction transformRequest(request) { return { webhookUrl: request.webhookUrl + '?color=' + request.fields.widgetColor.value, body: JSON.stringify(request.fields), httpMethod: 'GET' }; }" } ] }

Exemple 4

L'exemple suivant présente le blocage d'une action personnalisée. L'API des rappels peut être utilisée pour indiquer à HubSpot de terminer l'action et de faire avancer l'objet inscrit vers la prochaine action du workflow.

Vous n'aurez pas besoin de spécifier que l'action bloque au moment de la création de l'action. Cela sera déterminé par la réponse de votre élément actionUrl configuré.

// { "actionUrl": "https://example.com/hubspot", "inputFields": [ { "typeDefinition": { "name": "moonPhase", "type": "enumeration", "fieldType": "select", "options": [ { "value": "full_moon", "description": "Full Moon", "label": "Full" }, { "value": "half_moon", "description": "Half Moon", "label": "Half" }, { "value": "quarter_moon", "description": "Quarter Moon", "label": "Quarter" }, { "value": "new_moon", "description": "New Moon", "label": "New" } ] }, "supportedValueTypes": ["STATIC_VALUE"] } ], "objectRequestOptions": { "properties": ["email"] }, "labels": { "en": { "actionName": "Wait For Moon Phase", "actionCardContent": "Wait until a {{moonPhase}} moon", "inputFieldLabels": { "widgetName": "Moon Phase" } }, "fr": { "actionName": "Attendez la phase lunaire", "actionCardContent": "Attendez la lune {{moonPhase}}", "inputFieldLabels": { "widgetName": "Phase de lune" } } }, "objectTypes": ["CONTACT"] }

Cet article vous a-t-il été utile ?
Ce formulaire est destiné à recueillir les avis sur la documentation pour les développeurs. Si vous souhaitez faire part de votre avis sur les produits HubSpot, veuillez le partager sur le forum des idéesde la communauté.