Last modified: September 3, 2025
HubSpot agents are AI-powered assistants that users can chat with to perform tasks. Each agent includes a series of actions, called tools, that they’ll use according to the user’s instructions. As a developer, you can create custom agent tools to perform specific, well-defined tasks depending on the agent’s intended use case.
Behind the scenes, tools are custom workflow actions that are configured to be available in the agent context. Tools can be used across multiple agents, and can be configured to work in both agents and workflows.
At a high level, creating an agent tool consists of:
- Adding a workflow action component to an app by including a
workflow-actions
directory in the project, along with a*-hsmeta.json
configuration file for the tool. Each tool and workflow action you create should have its own*-hsmeta.json
configuration file. - Configuring the action to be available in AI agents via the
supportedClients
field.
Note the following limits at this time of the beta:
- The agent does not have access to CRM data unless explicitly given tools to get that data.
- The agent can’t request information from the user after it’s invoked if given insufficient information to complete the task.
Project setup
To build tools, yourhsproject.json
must have its platformVersion
set to 2025.2
. This version is set automatically on all of the boilerplate project types, but will need to be manually updated for projects on older versions.
Note that, when upgrading a project to version 2025.2
you’ll need to adhere to the new *-hsmeta.json
configuration file standards for your app configuration and its features.
Agent tools and custom workflow actions are both contained within the app’s workflow-actions
directory.
Agent tool definition
Configuration options for agent tools are similar to custom workflow actions, with a few notable differences:- The
supportedClients
field must include theAGENTS
client, along with other agent-specific fields, such astoolType
. - Functions are not supported in agent tools.
Fields marked with * are required
Field | Type | Description |
---|---|---|
uid * | String | An internal unique identifier for the agent tool. |
type * | String | The type of component, which should be workflow-action in this case. |
actionUrl * | String | The URL that the tool will make a POST request to. The URL must be a publicly accessible endpoint and cannot be a serverless function defined within the developer project. |
supportedClients * | Array | An array of objects that specifies the clients that support the action. Each object in the array should have a client key with a string value indicating the client type. Values include:
toolType and llmConfig.actionDescription fields. |
toolType * | String | The category of tool functionality. Can be one of:
|
llmConfig.actionDescription * | String | The llmConfig object contains the actionDescription field, which describes the tool to the AI agent. This allows the agent to determine how and when to invoke the tool, along with how to structure the input data. This description is only visible to the agent and will never be shown to users. Learn more about writing effective tool descriptions. |
isPublished | Boolean | Determines whether the definition is visible in accounts that installed your app. By default, this is set to false . |
inputFields | Array | The fields that will be sent to the external service via the actionUrl . |
labels.<locale> * | String | Locale key that maps to the locale definition. At a minimum, an english label (en ) and its definition must be defined. |
labels.<locale>.inputFieldDescriptions | Object | An object that defines the details for the inputs for your action. In the example above, this object includes message and priority fields. |
labels.<locale>.inputFieldOptionLabels | Object | An object that’s required if your input field(s) have options. Provides a map of input field option labels, keyed by the option’s value or label. |
labels.<locale>.outputFieldLabels | Object | An object that maps the definitions from outputFields to the corresponding labels that appear in the agent UI. |
labels.<locale>.actionName * | String | The action’s name as displayed in the agent UI. |
labels.<locale>.appDisplayName * | String | The name of the section in the tool selection panel where all tools appear. If appDisplayName is defined for multiple tools, the first one found will be used. |
labels.<locale>.actionCardContent | String | A summarized description shown in the action’s card. |
labels.<locale>.executionRules | Object | An object that maps the definitions from your executionRules to messages that will appear in the agent UI. |
objectTypes | Array | The available CRM object types that this action can be used with. If empty, the action will be available for all object types. |
outputFields | Array | An array containing the fields and values that the tool will output. Response data must be formatted as comma separated string-string value pairs. Learn more about output fields. |
executionRules | Object | A list of definitions you can specify to surface errors from your service to the user in the agent UI. |
Writing effective tool descriptions
In thellmConfig.actionDescription
field, you can help agents understand how and when to invoke a tool, and how to structure input data. The description is only ever visible to the agent.
When writing the description:
- Describe when the tool should be used so that the agent understands what types of user requests or contexts should trigger the tool.
- Explain how to use the tool, including any technical guidance that the agent should consider when constructing inputs. For example, include details such as:
- Supported input types (e.g., “Accepts video URLs or uploaded .mp4 files.”)
- Format constraints (e.g., ""Date must be in ISO 8601 format.”)
- Default parameter behavior (e.g., If no contact is specified, the tool will not return any results.”)
- Error-tolerant suggestions (e.g., “If company name is ambiguous, prompt user for clarification.”)
- Highlight required fields, expected input formats, or default behaviors.
- Provide fallback logic or edge-case handling if applicable (e.g., “If no date range is provided, default to the last 30 days”).
- Do not include branding, UI labels, or customer-facing copy, as this field is only for agent reasoning.
- Generate meeting summary tool
actionDescription
: Use this tool when the user asks for a summary of one or more meetings. Provide a list of meeting IDs or transcript URLs as input. If no specific meeting is identified, use the most recent one. Summaries should include key topics, action items, and assigned responsibilities.
- Generate invoice PDF tool
actionDescription
: Use this tool when the user needs to create an invoice document. Inputs should include recipient
, items
(with description, quantity, and price), and dueDate
. All currency values must be in USD unless otherwise specified. If items
are missing, do not generate a document. Returns a downloadable PDF link.
Output fields
In the agent tool schema,outputFields
is an array that defines the fields that can contain values returned by the response when the tool is executed. Output field definitions are similar to input field definitions:
outputFields
response sent to HubSpot must be structured as a JSON object with key-value pairs, where both keys and values are strings, as shown below. The keys should correspond with your defined output field names, with the values containing the actual returned data.
toolType
is set to TAKE_ACTION
, you can include a follow-up CTA that lets users navigate to a HubSpot CRM record on click. To do so, add the following fields to the outputFields
object in the response sent to HubSpot.

Field | Type | Description |
---|---|---|
ctaCrmObjectType | String | The type of CRM record (e.g., contact) |
ctaCrmObjectId | String | The ID of the CRM record to navigate to. |
ctaLabel | String | Optionally, you can specify a label. By default, HubSpot will try to autogenerate a label. |
Execution
When an agent request executes, aPOST
request is sent to the actionUrl
. The request will include the v2
x-hubspot-signature
, which you can use to validate the request.
The request body will include the input field values along with context about the account, user, and agent.
Field | Type | Description |
---|---|---|
callbackId | String | A unique ID assigned to the execution. You can use this value for execution blocking. |
origin | Object | Metadata about the account, user, and tool associated with the request. |
context | Object | Additional context about the agent and tool. |
inputFields | Object | Input field data included in the request. |
Execution state
You can manage execution state by returning thehs_execution_state
field in your response to HubSpot. This field can be set to one of the following values:
SUCCESS
: the execution has completed successfully and can proceed.FAIL_CONTINUE
: the execution has failed, but will proceed.BLOCK
: the execution is temporarily blocked and will not proceed until it’s updated via the automation API or when the block expires.
outputFields
to include an hs_execution_state
of BLOCK
:
Prop | Type | Description |
---|---|---|
hs_execution_state | String | Set to BLOCK to prevent the action from continuing to execute. |
hs_expiration_duration | String | By default, actions are blocked for one week. Use this field to specify a different block expiration (ISO 8601 duration format). |
POST
request to https://api.hubspot.com/callbacks/{callbackId}/complete
, where callbackId
is the value provided in the original request body sent by HubSpot to your service.
In the request body, set the hs_execution_state
to either SUCCESS
or FAIL_CONTINUE
, depending on the execution status.
Best practices
When building agent tools, keep the following best practices checklist in mind:- Start with optional fields, then set to required only when stable.
- Label and describe fields for both humans and AI.
- Test with fewer agent instructions at first to understand how the AI interprets a tool.
- Keep tools focused and be mindful of field quantity.
- Use field descriptions to control agent creativity.
Develop with optional fields
Do not set action fields (inputFields
) to be required during active development. Once a field has been set to required and the project is uploaded, you cannot remove or update the field. You should only set a field to required once you’re confident in the field’s details, such as its name
and type
. The reason for this limitation is that changing required fields would break any active workflows that include the action.
Build for human and AI understanding
TheactionName
, inputFields
, and labels
should clearly communicate their usage and utility to both humans and the agent. These fields in particular are used by the agent to understand when to invoke the action and how to pass data to the tool. As you build your tools, keep in mind that LLMs may need more explicit descriptions than human users. For example, while a human might intuitively understand a field labeled Date
, an LLM might prefer Event start date (YYYY-MM-DD)
.
Ideally, tools should be built so that agents don’t require additional instructions to use it. However, there are cases where field details alone may not be sufficient for the agent. For example, it may not understand the intended order of operations for executing tools that are dependent on the output of other tools (e.g., a ‘Send Email’ tool might depend on a ‘Get Contact Info’ tool running first).
While building a tool, you should test it in the agent without adding to the agent’s instructions first to better understand how it interprets the tool. Through testing, you’ll be able to determine whether the reasoning engine performs correctly on its own or if it needs additional instructions.
Be mindful of the number of input fields
Agents can handle a high number of input fields in each tool (more than 26 unique inputs). However, the more input fields there are in a tool, the clearer you need to be when assigningactionName
, inputField
, and label
values. Tools are most effective and reliable when they’re designed for specific tasks with a focused set of parameters. For complex operations, consider whether it would be more effective to create multiple, simpler tools versus a single tool with an excessive number of inputs.
Please note: it’s possible that HubSpot will restrict the number of inputs in the future based on the feedback around the quality of agents handling large numbers of inputs.
Control agent creativity and improvisation
In some scenarios, you might want an agent to be creative and improvisational. However, there may be scenarios where you don’t want the agent to improvise. Experiment with instructing the LLM in your input field names, labels, and descriptions. If you require stricter guidance, add instructions to the agent to set clear expectations. For example, let’s say you give an agent the task of generating a blog post, with one of the fields being the blog post title. Depending on how much you want the agent to improvise, you could label the field permissively or more restrictively:- Permissive:
"Blog title"
- Restrictive:
"Blog title (must include the product name 'HubSpot CRM')"
- Permissive:
"Social post content"
- Moderate:
"Social post content (keep under 280 characters)"
- Restrictive:
"Social post content (must mention our Q4 sale, include #HubSpot, and stay under 280 characters)"
Testing and validation
Agent tools require two-phase testing to ensure both functional correctness and proper AI integration:Phase 1: Workflow testing
Test your tool’s core logic using HubSpot workflows:- Create a test workflow and add your tool as a workflow action
- Test with both correct and incorrect inputs
- Verify expected outputs and error handling
- Iterate on your backend code based on results
Phase 2: Agent integration testing
Use the Developer Tool Testing Agent (available in the Breeze Marketplace) to test AI-specific functionality: Tool Recognition Testing:- Test whether the agent correctly identifies when to use your tool based on its name and description
- Compare performance against other available tools to ensure clear differentiation
- Test both direct commands (“Use Tool X with parameter Y”) and indirect prompts (“Help me accomplish goal Z”)
- Verify the agent correctly extracts all required parameters from natural language
- The testing agent reports exactly what parameters it passes to help with verification
- Test scenarios where your tool works in sequence with other tools
- Verify the agent can correctly pass outputs from one tool as inputs to another
llmConfig.actionDescription
for clearer tool purpose and usagelabels
properties for better parameter extraction- Field descriptions to guide agent behavior
Verifying agent tool request origin
When an agent uses a tool to make a request, it makes aPOST
request to the tool’s actionUrl
. Agent tool invocation is authenticated by validating the X-HubSpot-Signature
header sent with the request. This is the same system HubSpot uses for validating webhook requests.
Please note: you should not create input fields for secrets or API keys, as this is insecure and not the intended authentication pattern, especially because the LLM would need to be given the secret/API key in its instructions or receive it from another tool.