Ações de fluxo de trabalho personalizados

Use a ferramenta de fluxos de trabalho da HubSpot para automatizar os processos de negócios e permitir que sua equipe seja mais eficiente. Você pode criar ações de fluxo de trabalho personalizadas para integrar seu serviço a fluxos de trabalho do HubSpot.

Depois de configurar sua ação personalizada, quando os usuários instalarem o aplicativo, eles poderão adicionar a ação personalizada aos seus fluxos de trabalho. 

Quando esses fluxos de trabalho forem executados, as solicitações HTTPS serão enviadas à URL configurada com a payload definida. As solicitações feitas para sua ação personalizada usarão a versão v2 do X-HubSpot-Signature. Saiba mais sobre como validar solicitações do HubSpot.

Você também pode avançar para as seguintes seções:

A seção final deste artigo fornece vários exemplos de ações personalizadas.

Antes de começar

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

Definir sua ação personalizada

Para criar uma ação de fluxo de trabalho personalizada, você precisará definir a ação usando os seguintes campos. Isso também especifica o formato das solicitações provenientes do HubSpot, bem como o tratamento das respostas pelo seu serviço.

  • actionUrl: a URL para a qual uma solicitação HTTPS é enviada quando a ação é executada. O corpo da solicitação conterá informações sobre o usuário para o qual ação está sendo executada e quais valores foram inseridos para os campos de entrada.
  • objectTypes: em quais objetos do CRM esta ação pode ser usada.
  • published: por padrão, as ações personalizadas são criadas em um estado não publicado. As ações não publicadas ficam visíveis somente no portal do desenvolvedor associado ao seu aplicativo HubSpot. Para tornar uma ação personalizada visível para os usuários, atualize o sinalizador published na definição da ação para true.
  • inputFields: as entradas recebidas pela ação. Os campos serão preenchidos pelo usuário.
  • inputFieldDependencies: essas regras permitem que os campos fiquem esmaecidos até que outros campos atendam a condições específicas.
  • outputFields: os valores que a ação enviará e que poderão ser usados por ações posteriores no fluxo de trabalho. Uma ação personalizada pode ter zero, uma ou muitas saídas.
  • objectRequestOptions: propriedades do objeto inscrito incluídas na payload de actionUrl.
  • labels: texto que descreve o que os campos de ação representam e o que a ação faz ao usuário. Rótulos em inglês são obrigatórios, mas os rótulos podem ser especificados em qualquer um dos seguintes idiomas permitidos: francês (fr), alemão (de), japonês (ja), espanhol (es), português do Brasil (pt-br) e holandês (nl).
  • executionRules: uma lista de definições que você pode especificar para revelar erros do seu serviço ao usuário que cria o fluxo de trabalho.
  • functions: snippets de código que são executados para transformar a payload que está sendo enviada para uma URL e/ou transformar a resposta dessa URL.

Exemplo de definição de ação personalizada

// { "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}" } ] }

A definição acima renderizará o seguinte na ferramenta de fluxos de trabalho:

 

Há dois tipos de chamadas feitas para ações de fluxo de trabalho personalizado:

  • Buscas de opção de campo: preencha uma lista de opções válidas quando um usuário está configurando um campo. Saiba mais sobre como usar as buscas de opção de campo para buscar campos de dados externos. 
  • Solicitações de execução de ação: feitas quando uma ação está sendo executada por um fluxo de trabalho que inclui a ação personalizada. 

Funções

Funções são snippets usados para modificar payloads antes de enviá-las a uma API. Você também pode usar funções para analisar os resultados de uma API. As funções do HubSpot têm o suporte do AWS Lambda. No seguinte código:

  • event contém os dados que são passados para a função 
  • export.main é o método que será chamado quando a função for executada. 
  • A função callback pode ser usada para retornar um resultado.

O código deve ser formatado da seguinte forma:

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

Ao configurar uma função, o formato functionSource será uma string. Verifique se os caracteres no código passaram por escape.

Geralmente, a definição de uma função seguirá o formato: 

// { "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" }

Exemplo de função

No exemplo abaixo, examine o código de entrada, a função usada e a saída produzida.  

Entrada de função: 

// { "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" } }

Função utilizada: 

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

Resultado esperado

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

Campos de entrada

As definições do campo de entrada seguirão o seguinte formato:

  • name: o nome interno do campo de entrada, separado do seu rótulo. O rótulo exibido na interface do usuário deve ser definido usando a seção de rótulos da definição de ação personalizada.
  • type: o tipo de valor exigido pela entrada.
  • fieldType: como o campo de entrada deve ser renderizado na interface do usuário.  Os campos de entrada imitam as propriedades do CRM; saiba mais sobre as combinações válidas de type e fieldType
  • supportedValueTypes têm dois valores válidos:
    • OBJECT_PROPERTY: o usuário pode selecionar uma propriedade do objeto inscrito ou uma saída de uma ação anterior para usar como o valor do campo.
    • STATIC_VALUE: deve ser usado em todos os outros casos. Indica que o usuário deve inserir um valor. 
  • isRequired: determina se o usuário deve fornecer um valor para esta entrada

As definições do campo de entrada devem ser formatadas da seguinte forma: 

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

Você também pode embutir opções para o usuário selecionar: 

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

Uso de dados externos

Em vez de embutir opções de campo, você também pode buscar dados externos com campos de dados externos. Por exemplo, você pode recuperar uma lista de projetos de reunião ou uma lista de produtos para servir como entradas. O campo de entrada deve ser formatado da seguinte forma: 

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

A payload enviada para optionsURL será formatada da seguinte forma:

// { "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=" } }

A resposta esperada deve estar formatada da seguinte forma: 

// { "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 }

No código acima, observe que há uma paginação sendo definida para limitar o número de opções retornadas. Isso instrui o fluxo de trabalho de que mais opções podem ser carregadas.

Além disso, a lista de opções se torna pesquisável ao incluir searchable:true.

Modificar dados externos

Para gerenciar dados externos, você pode incluir dois ganchos para personalizar o ciclo de vida de busca de opção de campo:

  • PRE_FETCH_OPTIONS: uma função que configura a payload enviada do HubSpot.
  • POST_FETCH_OPTIONS: uma função que transforma a resposta do seu serviço em um formato compreendido pelo HubSpot.

 

PRE_FETCH_OPTIONS

Quando incluída, esta função será aplicada a cada campo de entrada. Você pode aplicá-la a um campo de entrada específico especificando um id na definição da função.

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

A payload enviada do HubSpot será formatada da seguinte forma:

// { "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=" } } }

A resposta deve ser formatada da seguinte forma:

// { // 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

Para analisar a resposta em um formato esperado, de acordo com os campos de dados externos, use a função POST_FETCH_OPTIONS. A definição para a função POST_FETCH_OPTIONS é a mesma que para a função PRE_FETCH_OPTIONS.  Quando opções externas de busca de dados estiverem definidas, um menu suspenso será renderizado nas opções de entrada para a ação. 

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

A entrada da função será formatada da seguinte forma:

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

A saída da função será formatada da seguinte forma:

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

Campos de saída

Use campos de saída para gerar valores de ação personalizada para usar em outras ações. A definição dos campos de saída é similar à definição dos campos de entrada: 

  • name: a forma como este campo é referenciado em outras partes da Ação personalizada. O rótulo exibido na interface do usuário deve ser definido usando a seção labels da Ação personalizada 
  • type: o tipo de valor exigido pela entrada.
  • fieldType: é como o campo de entrada deve ser renderizado na interface do usuário. Os campos de entrada imitam as propriedades do CRM; saiba mais sobre as combinações válidas de type e fieldType

O campo de saída deve ser formatado da seguinte forma: 

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

Ao usar um campo de saída, os valores são analisados a partir da resposta de actionURL. Por exemplo, você pode copiar campos de saída para uma propriedade existente no HubSpot.  

Rótulos

Use rótulos para adicionar texto às saídas ou entradas no editor de fluxo de trabalho. Os rótulos são carregados no serviço de linguagem do HubSpot e podem levar alguns minutos para serem exibidos. Os portais definidos para regiões ou idiomas diferentes exibirão o rótulo no idioma correspondente, se disponível. 

  • labels: texto que descreve o que os campos de ação representam e o que a ação faz. Rótulos em inglês são obrigatórios, mas os rótulos podem ser especificados em qualquer um dos seguintes idiomas permitidos: francês (fr), alemão (de), japonês (ja), espanhol (es), português do Brasil (pt-br) e holandês (nl).
  • actionName: o nome da ação mostrado no painel Escolha uma ação no editor de fluxo de trabalho.
  • actionDescription: uma descrição detalhada da ação exibida quando o usuário está configurando a ação personalizada.
  • actionCardContent: uma descrição resumida exibida no cartão de ação.
  • appDisplayName: o nome da seção no painel "Escolher uma ação", em que todas as ações do aplicativo são exibidas. Se appDisplayName for definido para várias ações, a primeira ação encontrada será usada.  
  • inputFieldLabels: um objeto que mapeia as definições de inputFields para os rótulos correspondentes que o usuário verá ao configurar a ação.
  • outputFieldLabels: um objeto que mapeia as definições de outputFields para os rótulos correspondentes mostrados na ferramenta de fluxos de trabalho.
  • inputFieldDescriptions: um objeto que mapeia as definições de inputFields para as descrições abaixo dos rótulos correspondentes.
  • executionRules: um objeto que mapeia as definições de executionRules às mensagens que serão mostradas para os resultados de execução das ações no histórico do fluxo de trabalho. Há uma seção separada nestes documentos para as regras de execução. 

As definições de rótulo devem ser formatadas da seguinte forma:

// { "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" } } } }

Execução

Quando uma execução é realizada, uma solicitação https é enviada para actionUrl.

  • callbackId: um ID exclusivo para a execução específica. Se a execução da ação personalizada for bloqueio, use este ID. 
  • object: os valores das propriedades solicitadas em objectRequestOptions.
  • InputFields: os valores para as entradas que o usuário preencheu. 

A payload de execução será formatada da seguinte forma: 

// { "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" } }

A resposta esperada deve estar formatada da seguinte forma: 

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

Ao analisar a resposta de execução: 

  • outputFields: os valores dos campos de saída definidos anteriormente. Esses valores podem ser usados em ações posteriores. 
  • hs_execution_state: um valor especial opcional que pode ser adicionado a outputFields.  Não é possível especificar uma nova tentativa; somente os seguintes valores podem ser adicionados:
    • SUCCESS
    • FAIL_CONTINUE
    • BLOCK
    • ASYNC

SUCCESS e FAIL_CONTINUE indicam que a ação foi concluída e o fluxo de trabalho deve passar para a próxima ação a ser executada. Se nenhum estado de execução for especificado, os códigos de status serão usados para determinar o resultado de uma ação: 

  • Códigos de status 2xx: a ação foi concluída com sucesso.
  • Códigos de status 4xx: a ação falhou. A exceção aqui são os códigos de status de taxa limitada 429, que são retratados como novas tentativas e o cabeçalho Retry-After é respeitado.
  • Códigos de status 5xx: indicam que houve um problema temporário com o serviço e uma nova tentativa será realizada para a ação mais tarde. Um sistema de retirada exponencial é usado para novas tentativas; novas tentativas serão feitas por até 3 dias antes de falhar. 

Funções de execução

Use as funções de execução para formatar os dados antes de enviá-los para actionURL e analisar os dados de actionURL. Há dois tipos de funções de execução:

  • PRE_ACTION_EXECUTION
  • POST_ACTION_EXECUTION

Função PRE_ACTION_EXECUTION

Use as funções PRE_ACTION_EXECUTION para formatar os dados antes de enviá-los para actionURL

A definição da função será formatada da seguinte forma:

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

A entrada da função deve ser formatada da seguinte forma:

// { "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" } }

A saída da função deve ser formatada da seguinte forma:

// { // 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" }

Função POST_ACTION_EXECUTION 

Depois de receber uma resposta de actionURL, use uma função POST_ACTION_EXECUTION para formatar os dados para o HubSpot.

A definição da função será formatada da seguinte forma:

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

A entrada da função deve ser formatada da seguinte forma:

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

The function output should be formatted as follows:

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

Execução assíncrona

Execute ações de fluxo de trabalho personalizadas de forma assíncrona, bloqueando e, posteriormente, concluindo a ação.

Bloqueio da execução de ações personalizadas

Use ações personalizadas para bloquear a execução do fluxo de trabalho. Em vez de executar a próxima ação no fluxo de trabalho após a ação personalizada depois de receber uma resposta completed (2xx or 4xx status code) do seu serviço, o fluxo de trabalho deixará de executar ("bloqueará") essa inscrição até você instruir o fluxo de trabalho para continuar.

Ao bloquear, você pode especificar um valor para o campo hs_default_expiration, após a qual a sua ação personalizada será considerada expirada. A execução do fluxo de trabalho será retomada e a ação que se segue à ação personalizada será executada, mesmo que a ação não tenha sido concluída. 

Para bloquear uma ação personalizada, sua resposta de execução de ação precisa ter o seguinte formato:

// { "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" } }

Concluir uma execução bloqueada

Para concluir uma execução de ação personalizada bloqueada, use o endpoint a seguir: /callbacks/{callbackId}/complete

Formate o corpo da solicitação da seguinte maneira:

// { "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" } }

Adicionar mensagens de execução personalizadas com regras

Especifique as regras na sua ação que determinam qual mensagem é exibida na página de histórico do fluxo de trabalho quando a ação for executada.

As regras corresponderão aos valores de saída da sua ação.  Esses valores de saída devem ser fornecidos no corpo de resposta de actionURL, no seguinte formato:

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

As mensagens reais podem ser especificadas na seção de rótulos da ação personalizada:

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

O executionRules será testado na ordem fornecida. Se houver várias correspondências, apenas a mensagem da primeira regra que corresponde será mostrada ao usuário.

A regra corresponde quando a saída de execução corresponde a um valor especificado na regra. Por exemplo, considere esse conjunto de 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" } } ]

Portanto, as seguintes correspondências ocorrerão:

  • {"errorCode": "ALREADY_EXISTS", "widgetName": "Test widget"}: isso corresponderia à primeira regra, pois errorCode é igual a ALREADY_EXISTS. Nesse caso, embora haja uma saída widgetNameela não é usada na definição de regra, de forma que qualquer valor é permitido.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "TOO_SMALL"}: isso corresponderia à segunda regra, pois TOO_SMALL é um dos sizeError correspondentes e errorCode é WIDGET_SIZE.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "NOT_A_NUMBER"}: isso corresponderia à terceira regra, pois, embora errorCode seja WIDGET_SIZE, o sizeError não corresponde a nenhum dos valores especificados pela segunda regra (TOO_SMALL ou TOO_BIG).

Esse mecanismo de correspondência permite especificar erros de fallback, para que você possa ter erros específicos para casos de erro importantes, mas retornar a mensagens de erro mais genéricas para erros menos comuns. Este é um exemplo de como a mensagem personalizada seria exibida:

Testar e publicar sua ação personalizada

Depois de criar sua nova ação personalizada, você pode testá-la e publicá-la. 

Testar ações personalizadas antes de publicar 

Antes de publicar sua ação personalizada, você pode testar a execução da ação e a busca de opções apontando a URL para webhook.site. Dessa forma, você pode inspecionar a payload e retornar uma resposta específica. 

Você também pode testar a ação no portal do desenvolvedor criando um fluxo de trabalho na ferramenta de fluxos de trabalho. Em seguida, adicione sua nova ação.

Ao concluir o teste, é recomendável arquivar as ações de teste. Saiba mais sobre as ações de arquivamento na seção Arquivar uma ação personalizada na guia Endpoints na parte superior deste artigo..

Publicação de ações personalizadas 

Por padrão, as ações personalizadas são criadas em um estado não publicado. Ações personalizadas não publicadas ficam visíveis somente no portal do desenvolvedor associado ao aplicativo HubSpot correspondente. Para tornar uma ação personalizada visível para os usuários, atualize o sinalizador published na definição da ação para true. Se uma ação não for publicada, os portais que já adicionaram a ação ao fluxo de trabalho ainda poderão editá-la e executá-la. Porém, não poderão adicionar a ação novamente. 

Exemplos de ação personalizada

Os snippets de código abaixo fornecem exemplos de vários casos de uso comuns para ações personalizadas, como definir um widget ou invocar uma função sem servidor.

Exemplo 1

Este exemplo apresenta os seguintes campos de entrada, criados para fluxos de trabalho de contato e negócio:

  • widgetName: um campo de entrada estática
  • widgetColor: um campo suspenso com opções
  • widgetOwner: um campo que representa um proprietário do HubSpot.
  • widgetQuantity: um campo derivado de uma propriedade (selecionado pelo usuário que cria o fluxo de trabalho) no objeto inscrito.
// { "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"] }

Exemplo 2

A ação personalizada a seguir usa uma função sem servidor para transformar a carga útil que é enviada ao actionUrl configurado. Como o campo objectTypes não está especificado na definição de ação personalizada, essa ação estará disponível em todos os tipos de fluxos de trabalho.

// { "actionUrl": "https://example.com", "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' }; }" } ] }

Exemplo 3

A ação personalizada a seguir tem dependências de campo e opções que são buscadas de uma API externa. Como o tamanho do widget depende da cor do widget, o usuário não poderá inserir um valor para o tamanho do widget até que uma cor de widget seja escolhida.

O custo do widget também depende da cor do widget, porém, está condicionado ao valor que o usuário seleciona para a cor do widget. O usuário não poderá inserir um valor para o custo do widget, a menos que Vermelho esteja selecionado como a cor do 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' }; }" } ] }

Este artigo foi útil?
Este formulário deve ser usado apenas para fazer comentários sobre esses artigos. Saiba como obter ajuda para usar a HubSpot..