Acciones de workflow personalizadas

Utiliza la herramienta de workflows de HubSpot para automatizar los procesos empresariales y permitir que tu equipo sea más eficiente. Puedes crear acciones personalizadas de workflow para integrar tu servicio con workflows de HubSpot.

Después de configurar tu acción personalizada, cuando los usuarios instalen tu aplicación, pueden agregar la acción personalizada a sus workflows. 

Cuando se ejecutan esos workflows, las solicitudes HTTPS se enviarán a la URL configurada con la carga que configuras. Las solicitudes realizadas para tu acción personalizada usarán la versión v2 del X-HubSpot-Signature. Más información sobre cómo validar solicitudes de HubSpot.

También puedes pasar a las siguientes secciones:

Antes de comenzar

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

Definir tu acción personalizada

Para crear una acción de workflow personalizada, deberás definir la acción usando los siguientes campos. Esto también especifica el formato de solicitud para solicitudes procedentes de HubSpot, así como el manejo de respuestas de tu servicio.

  • actionUrl: la URL donde se envía una solicitud HTTPS cuando se ejecuta la acción. El cuerpo de la solicitud contiene información sobre a nombre de qué usuario se está ejecutando la acción y qué valores se ingresaron para los campos de entrada.
  • objectTypes: con qué objetos de CRM se puede utilizar esta acción.
  • published: por opción predeterminada, las acciones personalizadas se crean en un estado no publicado. Las acciones no publicadas solo son visibles en el portal para desarrolladores asociado a tu aplicación HubSpot. Para que tu acción personalizada sea visible para los usuarios, actualiza la bandera publicada en tu definición de acción a verdadero.
  • inputFields: las entradas que recibe la acción. Estas serán rellenadas por el usuario.
  • inputFieldDependencies: estas reglas permiten que los campos se atenúen hasta que otros campos cumplan con condiciones específicas.
  • outputFields: los valores que se mostrarán en la acción que se pueden usar más tarde en el workflow. Una acción personalizada puede tener cero, una o muchas salidas.
  • objectRequestOptions:  propiedades del objeto inscrito incluidas en la carga útil de actionUrl.
  • labels: copia que describe al usuario lo que representa los campos de la acción y lo que hace la acción. Se requieren etiquetas en inglés, pero estas también pueden especificarse en cualquiera de los siguientes idiomas compatibles: Francés (fr), Alemán (de), Japonés (ja), Español (es), Portugués de Brasil(pt-br) y Holandés (nl).
  • executionRules: una lista de definiciones que puedes especificar para exponer errores de tu servicio al usuario que crean el workflow.
  • functions: fragmentos de código que se ejecutan para transformar la carga útil que se envía a una url y/o transformar la respuesta desde esa url.

Ejemplo de definición de acción 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}" } ] }

La definición anterior mostrará lo siguiente en la herramienta de workflows:

 

Hay dos tipos de llamadas realizadas para acciones de workflow personalizadas:

  • Recuperaciones de opciones de campo: se completa una lista de opciones válidas cuando un usuario está configurando un campo. Obtén más información sobre el uso de las recuperaciones de opciones de campo para obtener campos de datos externos. 
  • Solicitudes de ejecución de acciones: se realizan cuando una acción se ejecuta por un workflow que incluye tu acción personalizada. 

Funciones

Las funciones son fragmentos de código utilizados para modificar cargas útiles antes de enviarlas a una API. También puedes usar funciones para analizar los resultados de una API. Las funciones de HubSpot están respaldadas por AWS Lambda. En el siguiente código:

  • event contiene los datos que se pasan a la función 
  • exports.main es el método que se llamará cuando se ejecute la función. 
  • La función callback se puede utilizar para devolver un resultado.

El código debe tener el siguiente formato:

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

Al configurar una función, el formato functionSource estará en cadena. Asegúrate de que los caracteres del código tengan secuencia de escape.

Generalmente, la definición de una función seguirá el 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" }

Función de ejemplo

En el siguiente ejemplo, examina el código de entrada, la función utilizada y la salida producida.  

Entrada de función: 

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

Función utilizada: 

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

Salida esperada:

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

Campos de entrada

Las definiciones de los campos de entrada se ajustarán al siguiente formato:

  • name: el nombre interno del campo de entrada, separado de su etiqueta. La etiqueta que se muestra en la interfaz de usuario debe definirse utilizando la sección de etiquetas de la definición de acción personalizada.
  • type: el tipo de valor requerido por la entrada.
  • fieldType: cómo se debe representar el campo de entrada en la interfaz de usuario.  Los campos de entrada imitan las propiedades de CRM. Obtén más información sobre combinaciones válidas de type y fieldType
  • supportedValueTypes tiene dos valores válidos:
    • OBJECT_PROPERTY: el usuario puede seleccionar una propiedad del objeto inscrito o una salida de una acción anterior para usarla como valor del campo.
    • STATIC_VALUE: debe usarse en todos los demás casos. Indica que el usuario debe introducir un valor por sí mismo. 
  • isRequired: determina si el usuario debe dar un valor para esta entrada o no

Las definiciones de los campos de entrada deben tener el siguiente formato: 

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

También puedes codificar opciones para que el usuario seleccione: 

// { "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 datos externos

En lugar de opciones de campo de codificación dura, también puedes obtener datos externos con campos de datos externos. Por ejemplo, puedes recuperar una lista de proyectos de reuniones o una lista de productos para que sirvan como entradas. El campo de entrada debe tener el siguiente formato: 

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

La carga útil enviada a optionsURL se formateará de la siguiente manera:

// { "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 respuesta esperada debe formatearse de la siguiente manera: 

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

En el código anterior, ten en cuenta que se está configurando la paginación para limitar el número de opciones devueltas. Esto indica al workflow que se pueden cargar más opciones.

Además, la lista de opciones se puede buscar al incluir searchable:true.

Modificar datos externos

Para gestionar los datos externos, puedes incluir dos ganchos para personalizar el ciclo de vida de la opción de búsqueda de campos:

  • PRE_FETCH_OPTIONS: una función que configura la carga útil enviada desde HubSpot.
  • Post_FETCH_OPTIONS: una función que transforma la respuesta de tu servicio en un formato que sea entendido por HubSpot.

 

PRE_FETCH_OPTIONS

Cuando se incluya, esta función se aplicará a cada campo de entrada. Puedes aplicarlo a un campo de entrada específico especificando un id en la definición de la función.

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

La carga útil enviada desde HubSpot se formateará de la siguiente manera:

// { "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 respuesta debe formatearse de la siguiente manera:

// { // 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 analizar la respuesta en un formato esperado, según los campos de datos externos, usa una función POST_FETCH_OPTIONS. La definición de una función POST_FETCH_OPTIONS es la misma que una función PRE_FETCH_OPTIONS.  Cuando se definen opciones externas de obtención de datos externos, se representará un menú desplegable en las opciones de entrada para la acción. 

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

La entrada de función se formateará de la siguiente manera:

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

La salida de la función se formateará de la siguiente manera:

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

Campos de salida

Utiliza campos de salida para generar valores de tu acción personalizada para usar en otras acciones. La definición de los campos de salida es similar a la definición de los campos de entrada: 

  • name: cómo se hace referencia a este campo en otras partes de la acción personalizada. La etiqueta que se muestra en la interfaz de usuario debe definirse utilizando la sección "etiquetas" de la acción personalizada 
  • type: el tipo de valor requerido por la entrada.
  • fieldType: es cómo se debe representar el campo de entrada en la interfaz de usuario. Los campos de entrada imitan las propiedades de CRM. Obtén más información sobre combinaciones válidas de type y fieldType

El campo de salida debe formatearse de la siguiente manera: 

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

Cuando se utiliza un campo de salida, los valores se analizan a partir de la respuesta de actionURL. Por ejemplo, puedes copiar campos de salida en una propiedad existente en HubSpot.  

Etiquetas

Utiliza etiquetas para agregar texto a tus salidas o entradas en el editor de workflow. Las etiquetas se cargan en el servicio de idiomas de HubSpot y pueden tardar unos minutos en mostrarse. Los portales configurados para diferentes regiones o idiomas mostrarán la etiqueta en el idioma correspondiente, si está disponible. 

  • labels: copia que describe al usuario lo que representa los campos de la acción y lo que hace la acción. Se requieren etiquetas en inglés, pero estas también pueden especificarse en cualquiera de los siguientes idiomas compatibles: Francés (fr), Alemán (de), Japonés (ja), Español (es), Portugués de Brasil(pt-br)y Holandés (nl).
  • actionName: el nombre de la acción que aparece en el panel Elegir una acción en el editor de workflows.
  • actionDescription: una descripción detallada de la acción que se muestra cuando el usuario está configurando la acción personalizada.
  • actionCardContent: una descripción resumida que se muestra en la tarjeta de la acción.
  • appDisplayName: el nombre de la sección en el panel "Elegir una acción" donde se muestran todas las acciones de la aplicación. Si appDisplayName se define para múltiples acciones, se utiliza la primera que se encuentre.  
  • inputFieldLabels: un objeto que mapea las definiciones de inputFields a las etiquetas correspondientes que el usuario verá cuando configure la acción.
  • outputFieldLabels: un objeto que mapea las definiciones de outputFields a las etiquetas correspondientes que se muestran en la herramienta de workflows.
  • inputFieldDescriptions: un objeto que mapea las definiciones de inputFields a las descripciones debajo de las etiquetas correspondientes.
  • executionRules: un objeto que asigna las definiciones de tus executionRules a los mensajes que se mostrarán para los resultados de la ejecución de acciones en el historial del workflow. Hay una sección separada en estos documentos para las reglas de ejecución. 

Las definiciones de etiquetas deben tener el siguiente formato:

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

Ejecución

Cuando se ejecuta una ejecución, se envía una solicitud https al actionUrl.

  • callbackId: un ID único para la ejecución específica. Si la ejecución de la acción personalizada está bloqueando, utiliza este ID. 
  • object: los valores de las propiedades solicitadas en objectRequestOptions.
  • InputFields: los valores de las entradas que el usuario ha rellenado. 

La carga útil de ejecución se formateará de la siguiente manera: 

// { "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 respuesta esperada debe formatearse de la siguiente manera: 

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

Al observar la respuesta de ejecución: 

  • outputFields: los valores de los campos de salida definidos anteriormente. Estos valores se pueden utilizar en acciones posteriores. 
  • hs_execution_state: un valor especial opcional que se puede agregar a outputFields.  No es posible especificar un reintento, solo se pueden agregar los siguientes valores:
    • SUCCESS
    • FAIL_CONTINUE
    • BLOCK
    • ASYNC

SUCCESS y FAIL_CONTINUE indican que la acción se ha completado y que el workflow debe pasar a la siguiente acción a ejecutar. Si no se especifica ningún estado de ejecución, se utilizarán códigos de estado para determinar el resultado de una acción: 

  • Códigos de estado 2xx: la acción se ha completado correctamente.
  • Códigos de estado 4xx: la acción ha fallado. La excepción son los códigos de estado Tasa limitada 429, que se vuelven a tratar como reintentos y se respeta el título Reintentar después.
  • Códigos de estado 5xx: hubo un problema temporal con el servicio y la acción se volverá a intentar más tarde. Se utiliza un sistema de retroceso exponencial para los reintentos. Los reintentos continuarán hasta 3 días antes de fallar. 

Funciones de ejecución

Utiliza las funciones de ejecución para formatear los datos antes de enviarlos a actionURL y analizar los datos de actionURL. Hay dos tipos de funciones de ejecución:

  • PRE_ACTION_EXECUTION
  • POST_ACTION_EXECUTION

Función PRE_ACTION_EXECUTION

Utilice las funciones PRE_ACTION_EXECUTION para formatear los datos antes de enviarlos a actionURL

La definición de la función tendrá el siguiente formato:

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

La entrada de función debe tener el siguiente formato:

// { "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 salida de la función debe formatearse de la siguiente manera:

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

Función POST_ACTION_EXECUTION 

Después de recibir una respuesta de actionURL, use una función POST_ACTION_EXECUTION para formatear los datos para HubSpot.

La definición de la función tendrá el siguiente formato:

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

La entrada de función debe tener el siguiente formato:

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

The function output should be formatted as follows:

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

Ejecución asíncrona

Ejecuta acciones de worflow personalizadas de forma asíncrona bloqueando y completando posteriormente la acción.

Bloquear ejecución de acción

Utiliza acciones personalizadas para bloquear la ejecución del workflow. En lugar de ejecutar la siguiente acción en el workflow después de la acción personalizada después de recibir una respuesta completado (2xx o 4xx) de tu servicio, el workflow dejará de ejecutarse ("bloquear") esa inscripción hasta que el workflow continúe.

Al bloquear, puedes especificar un valor para el campo hs_default_expiration, después de que tu acción personalizada se considere vencida. La ejecución del workflow se reanudará y la acción que sigue a la acción personalizada se ejecutará, aunque no se haya completado la acción. 

Para bloquear una acción personalizada, la respuesta de ejecución de tu acción debe tener el siguiente 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" } }

Completar una ejecución bloqueada

Para completar la ejecución de una acción personalizada bloqueada, usa el siguiente punto de terminación: /callbacks/{appId}/{callbackId}/complete.

Formatea el cuerpo de la solicitud de la siguiente manera:

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

Agregar mensajes de de ejecución personalizados con reglas

Especifica reglas sobre tu acción que determinen qué mensaje aparece en la página de historial del workflow cuando se ejecuta la acción.

Las reglas se emparejarán con los valores de salida de tu acción.  Estos valores de salida se deben proporcionar en el cuerpo de la respuesta de actionURL, en el siguiente formato:

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

Los mensajes reales se pueden especificar en la sección de etiquetas de la acción personalizada:

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

Las executionRules se probarán en el orden proporcionado. Si hay varias coincidencias, solo el mensaje de la primera regla que coincide se muestra al usuario.

La regla coincide cuando la salida de ejecución corresponde a un valor especificado en la regla. Por ejemplo, considera este 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" } } ]

Con lo anterior, se producirían las siguientes coincidencias:

  • {"errorCode": "ALREADY_EXISTS", "widgetName": "Test widget"}: Esto coincidirá con la primera regla, ya que errorCode es igual a ALREADY_EXISTS. En este caso, aunque haya una salida widgetName, no se utiliza en la definición de regla, por lo que se permite cualquier valor.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "TOO_SMALL"}: Esto coincidirá con la segunda regla, ya que TOO_SMALL es uno de los valores de sizeErrorque coinciden, y errorCode es WIDGET_SIZE.
  • {"errorCode": "WIDGET_SIZE", "sizeError": "NOT_A_NUMBER"}: Esto coincidirá con la tercera regla, ya que aunque el errorCode es WIDGET_SIZE, el sizeError no coincide con ninguno de los valores especificados por la segunda regla (TOO_SMALL o TOO_BIG).

Este mecanismo de coincidencia te permite especificar errores de reserva, por lo que puedes tener errores específicos para casos de error importantes, pero regresa a mensajes de error genéricos para errores más comunes. Aquí tienes un ejemplo de cómo se mostraría el mensaje personalizado:

Probar y publicar tu acción personalizada

Después de crear tu nueva acción personalizada, puedes probarla y publicarla. 

Probar acciones personalizadas antes de publicar 

Antes de publicar su acción personalizada, puedes probar la ejecución de la acción y las opciones de obtención apuntando la URL a webhook.site. Esto te permite inspeccionar la carga útil y devolver una respuesta específica. 

También puedes probar la acción en tu portal de desarrolladores creando un workflow en la herramienta de workflows. A continuación, agrega tu nueva acción.

Cuando hayas completado tus pruebas, se recomienda archivar tus acciones de prueba. Obtén más información sobre las acciones de archivado en la sección Archivar una acción personalizada en la pestaña Puntos de terminación.

Publicar acciones personalizadas 

Por opción predeterminada, las acciones personalizadas se crean en un estado no publicado. Las acciones personalizadas no publicadas solo son visibles en el portal de desarrolladores asociado con la aplicación HubSpot correspondiente. Para que tu acción personalizada sea visible para los usuarios, actualiza la bandera publicado en tu definición de acción a verdadero. Si una acción no está publicada, los portales que ya han agregado la acción a tu workflow aún podrán editar y ejecutar acciones ya agregadas. Sin embargo, no podrán volver a agregar la acción. 

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

Ejemplo 2

La siguiente acción personalizada usa una función sin servidor para transformar la carga que se envía a la acción configurada actionUrl. Dado que no se especifican objectTypes, esta acción estará disponible en todos los tipos de workflows.

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

Ejemplo 3

La siguiente acción personalizada tiene dependencias y opciones de campo que se recuperan desde una API. Debido a que el tamaño del widget depende del color del widget, el usuario no podrá introducir un valor para el tamaño del widget hasta que se elige un color del widget.

El costo del widget también depende del color del widget, pero está condicionado al valor que el usuario selecciona para el color del widget; el usuario no podrá introducir un valor para el costo del widget, a menos que Red esté seleccionada como el color del 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' }; }" } ] }

Ejemplo 4

El siguiente ejemplo es una acción personalizada de bloqueo. La API de devolución de llamadas se puede usar para indicarle a HubSpot que complete la acción y hacer que el objeto inscrito pase a la siguiente acción en el workflow.

No necesitarás especificar que la acción se bloquea en el momento en que creas la acción; eso será determinado por la respuesta de tu actionUrlconfigurada.

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

¿Te resultó útil este artículo?
Con este formulario puedes enviar tu opinión sobre nuestros documentos para desarrolladores. Si tienes comentarios sobre el producto de HubSpot, puedes enviarlos al Foro de ideas.