> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---
id: 009d7c33-b534-47df-848a-db63d8ce961a
---

# Serverless functions reference

> Reference information for serverless functions on version 2026.03 of the developer platform.

export const SupportedProducts = ({marketing, sales, service, cms, data, commerce, marketingLevel, salesLevel, serviceLevel, cmsLevel, dataLevel, commerceLevel}) => {
  const translations = {
    description: "Requires one of the following products or higher.",
    productNames: {
      marketing: "Marketing Hub",
      sales: "Sales Hub",
      service: "Service Hub",
      cms: "Content Hub",
      data: "Data Hub",
      commerce: "Commerce Hub"
    },
    tiers: {
      free: "Free",
      starter: "Starter",
      professional: "Professional",
      enterprise: "Enterprise"
    }
  };
  const translateTier = tier => {
    if (!tier) return '';
    const lowerTier = tier.toLowerCase();
    return translations.tiers[lowerTier] || tier;
  };
  const products = [{
    name: marketing ? translations.productNames.marketing : '',
    level: translateTier(marketingLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/marketing-bolt.svg",
    alt: "Marketing Hub"
  }, {
    name: sales ? translations.productNames.sales : '',
    level: translateTier(salesLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/sales-star.svg",
    alt: "Sales Hub"
  }, {
    name: service ? translations.productNames.service : '',
    level: translateTier(serviceLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/service-heart.svg",
    alt: "Service Hub"
  }, {
    name: cms ? translations.productNames.cms : '',
    level: translateTier(cmsLevel),
    icon: "https://mintlify-assets.b-cdn.net/Icons/content-play.svg",
    alt: "Content Hub"
  }, {
    name: data ? translations.productNames.data : '',
    level: translateTier(dataLevel),
    icon: "https://developers.hubspot.com/hubfs/Knowledge_Base_2023-24-25/subscription_key_icons/operations_icon.svg",
    alt: "Data Hub"
  }, {
    name: commerce ? translations.productNames.commerce : '',
    level: translateTier(commerceLevel),
    icon: "https://developers.hubspot.com/hubfs/Knowledge_Base/subscription_key_icons/commerce_icon.svg",
    alt: "Commerce Hub"
  }].filter(product => product.name && product.level);
  if (products.length === 0) return null;
  return <div>
      <div className="text-sm mb-2">{translations.description}</div>
      <div className={`grid ${products.length === 1 ? 'grid-cols-1' : 'grid-cols-2'} gap-1.5`}>
        {products.map((product, index) => <div key={index} style={{
    display: 'flex',
    alignItems: 'center'
  }}>
            <img src={product.icon} alt={product.alt} className="w-3.5 h-3.5 mr-1.5 mt-2.5 mb-2.5 flex-shrink-0 align-middle" />
            <span className="font-medium mr-1 text-sm">{product.name} -</span>
            <span className="text-sm">{product.level}</span>
          </div>)}
      </div>
    </div>;
};

export const RequiredIndicator = () => {
  return <span className="required-indicator">
      required
    </span>;
};

<Accordion title="Supported products" defaultOpen="true" icon="cubes">
  <SupportedProducts marketing={true} sales={true} service={true} cms={true} data={true} marketingLevel="enterprise" salesLevel="enterprise" serviceLevel="enterprise" cmsLevel="enterprise" dataLevel="enterprise" />
</Accordion>

This article provides reference information for configuring serverless functions on version 2026.03 of the developer platform.

<Warning>
  Using serverless functions with 2026.03 apps requires that you're on the latest version of the [HubSpot CLI](/developer-tooling/local-development/hubspot-cli/install-the-cli#install-the-latest-version-of-the-hubspot-cli). Version `8.4.0` or above is recommended.

  You can check the version you're using by running `hs --version`.
</Warning>

## Project structure

To add serverless function support to an existing project, run the following command:

```shell theme={null}
hs project add --features app-function
```

This command will create the following directory and files in your project:

```shell highlight={6-9} theme={null}
project-folder/
└── src/
    └── app/
        ├── app-hsmeta.json
        ...
        └── functions/
            └── private-function-hsmeta.json
            └── NewFunction.js
            └── package.json
```

## Function configuration

The `src/app/functions/private-function-hsmeta.json` file provides the main configuration for your serverless functions, while the code for your serverless function is defined in the `NewFunction.js` file. These boilerplate files are meant as a starting point for your app, which can be adapted to fit your app's needs.

<Tabs>
  <Tab title="private-function-hsmeta.json">
    ```json theme={null}
    {
      "uid": "app_function_private",
      "type": "app-function",
      "config": {
        "entrypoint": "/app/functions/NewFunction.js",
        "secretKeys": []
      }
    }
    ```
  </Tab>

  <Tab title="NewFunction.js">
    ```js theme={null}
      exports.main = async () => {
        return "New Private Function!";
      };
    ```
  </Tab>
</Tabs>

The table below provides details on each of the available properties you can configure in your `function-hsmeta.json` file:

| Field                              | Type   | Description                                                                                                                                                                                                                                                                                                                      |
| ---------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uid` <RequiredIndicator />        | String | A unique identifier for the app function component. This can be any string, but should meaningfully identify the app function. HubSpot will identify the function by this ID.                                                                                                                                                    |
| `type` <RequiredIndicator />       | String | The type of component, which should be `app-function` in this case.                                                                                                                                                                                                                                                              |
| `config` <RequiredIndicator />     | Object | An object containing configuration details, which includes the `entrypoint`, `endpoint`, and `secretKeys` properties, detailed below.                                                                                                                                                                                            |
| `entrypoint` <RequiredIndicator /> | String | A sub-property of the `config` object, which is the path to your serverless function JavaScript file.                                                                                                                                                                                                                            |
| `endpoint`                         | Object | An object that defines a publicly accessible endpoint (<u>without</u> authentication), which requires ***Content Hub** Enterprise*. This object includes the following properties: <ul><li>`path`: The URL path for the public endpoint.</li><li>`method`: the HTTP method for the endpoint (e.g., `"POST"`, `"GET"`).</li></ul> |
| `secretKeys`                       | Array  | Array of secret names to inject as environment variables.                                                                                                                                                                                                                                                                        |

## Manage multiple serverless functions

2026.03 apps support multiple serverless functions, added via sets of `.js` and `*-hsmeta.json` files.

For example, to define another serverless function, you could create two new files, 'SecondFunction.js' and `second-function-hsmeta.json` in the `src/app/functions/` directory:

```shell highlight={8,10} theme={null}
project-folder/
└── src/
    └── app/
        ├── app-hsmeta.json
        ...
        └── functions/
            └── private-function-hsmeta.json
            └── NewFunction.js
            └── second-private-function-hsmeta.json
            └── SecondFunction.js
            └── package.json
```

Then, you'd edit the newly added files to ensure the `second-private-function-hsmeta.json` file references the path to `SecondFunction.js`, and it has a `uid` that's distinct from the `uid` of any other function.

<Tabs>
  <Tab title="second-private-function-hsmeta.json">
    ```json highlight={2,5} theme={null}
    {
      "uid": "second_app_function_private",
      "type": "app-function",
      "config": {
        "entrypoint": "/app/functions/SecondFunction.js",
        "secretKeys": []
      }
    }
    ```
  </Tab>
</Tabs>

## Managing and referencing secrets

Secrets provide secure storage for any API keys, tokens, or other sensitive data your serverless function might need to use when making an external request.

By default, a reserved secret named `PRIVATE_APP_ACCESS_TOKEN` is accessible by default in every private serverless function to make HubSpot API requests on behalf of your app, but you can add new secrets if your serverless function needs to make other external requests.

To add a secret, use the `hs secret add` command. The example below would add a secret with a name of `THIRD_PARTY_ACCESS_TOKEN`:

```shell theme={null}
hs secret add THIRD_PARTY_ACCESS_TOKEN
```

You'd then be prompted to enter or paste in the value of the secret (which will not appear in the terminal).

You should then add the secret name to the `secretKeys` array in the corresponding `private-function-hsmeta.json` file:

```json highlight={6} theme={null}
{
  "uid": "app_function_private",
  "type": "app-function",
  "config": {
    "entrypoint": "/app/functions/NewFunction.js",
    "secretKeys": ["THIRD_PARTY_ACCESS_TOKEN"]
  }
}
```

The secret is then injected as an environment variable in your serverless function:

```js highlight={5} theme={null}
    exports.main = async (context) => {
    // ...

    // Get third-party access token
    const accessToken = process.env.THIRD_PARTY_ACCESS_TOKEN;

    // ...
    };
```

<Tip>
  After adding a secret, you may need to run `hs project upload` to ensure your secret can be correctly referenced in a deployed UI extension.
</Tip>

Learn more about [managing secrets](/developer-tooling/local-development/hubspot-cli/commands/account-commands#managing-secrets) using the HubSpot CLI.

## Calling serverless functions

The way you invoke your serverless function depends on whether you configured a private function to run in a UI extension or whether you configured a publicly accessible endpoint.

### Private functions in UI extensions

To execute your serverless function from one of your UI extensions (e.g., an [app card](/apps/developer-platform/add-features/ui-extensions/extension-points/app-cards/overview), [app pages](/apps/developer-platform/add-features/ui-extensions/extension-points/app-pages/create-app-pages), or [app settings page](/apps/developer-platform/add-features/ui-extensions/extension-points/create-a-settings-page)), use the `hubspot.serverless()` API, as demonstrated in the code block below:

```jsx theme={null}
import { hubspot } from '@hubspot/ui-extensions';

// In your React component (App Card, App Home, App Settings, etc.)
const handleSubmit = async () => {
  try {
    const result = await hubspot.serverless('app_function_private', {
      parameters: {
        customParam: 'value'
      },
      propertiesToSend: ['firstname', 'lastname', 'email']
    });

    console.log('Function result:', result);
  } catch (error) {
    console.error('Function error:', error);
  }
};
```

Learn more about how to [use serverless functions](/apps/developer-platform/add-features/serverless-functions/create-serverless-functions) in an app card.

### Endpoint functions via public HTTP request

<Warning>
  **Please note:** public endpoints require ***Content Hub** Enterprise*, and are accessible without authentication. Only add endpoint configuration if you intentionally need to create a public API. Consider implementing your own authentication logic (API keys, tokens, etc.) within the function if you need to restrict access.
</Warning>

If you configured a public endpoint, you can make HTTP requests to the endpoint that you specified by the `config.endpoint.path` property in your `function-hsmeta.json` file.

The `cURL` example below demonstrates how to make a request to a function with a `path` of `https://your-domain.com/hs/serverless/api/app_function_endpoint`:

```shell theme={null}
curl -X POST https://your-domain.com/hs/serverless/api/app_function_endpoint \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}'
```

## Function context

Serverless functions are passed a `context` object, which contains metadata based on whether you configure your function to be private or public.

### Private function

When your function is called from a UI extension (e.g., an app card, app home, or app settings page), the `context` object can be deconstructed to reference the properties shown below:

```js highlight={5} theme={null}
  exports.main = async (context) => {
    const {
      accountId, userId, userEmail, // User and account information
      parameters, // Parameters passed from your frontend code
      propertiesToSend // CRM properties
    } = context;

    // ...
  };
```

<Tip>
  The `propertiesToSend` field is only available when your function is invoked from a CRM record context (like an App Card on a contact record). It will not be present when called from App Homes or App Settings.
</Tip>

Learn more about using `context` in the UI extensions SDK [reference](/apps/developer-platform/add-features/ui-extensions/ui-extensions-sdk).

### Public function

If your serverless function is a publicly accessible endpoint, the `context` object contains the following fields:

| Field       | Type   | Description                               |
| ----------- | ------ | ----------------------------------------- |
| `accountId` | Number | The HubSpot account ID (if authenticated) |
| `method`    | String | The HTTP request method.                  |
| `body`      | Object | Request body, if provided.                |
| `query`     | Object | Request query parameters, if provided.    |
| `headers`   | Object | Request headers.                          |

## Add NPM packages

Serverless functions support custom NPM dependencies. You can add them by running `npm install <package-name>` in the `src/app/functions/` directory.

For example, if you wanted to add axios as a dependency, you'd run `npm install axios` in the `src/app/functions/` directory, which would install `axios` and update the `package.json` file in the `functions/` directory automatically:

```json highlight={5} theme={null}
{
  "name": "example-function",
  "version": "0.1.0",
  "dependencies": {
    "axios": "^1.13.6"
  }
}
```

## Limitations

Keep the following limits in mind as you develop and test your function:

* Functions have a 15 second execution timeout
* Functions may experience "cold starts" after periods of inactivity.
* Only privately distributed apps with static auth are currently supported. Apps using [OAuth](/apps/developer-platform/build-apps/authentication/overview#oauth) for authentication cannot use 2026.03 serverless functions.

To help mitigate both limitations above, keep your functions lightweight, minimize the number of external API calls, and assign variables within functions instead of at the module level.

## Troubleshooting

The table below outlines common errors you might encounter while you develop and test your serverless function:

| Error                                 | Details                                                                                                                                                                                                                                                                 |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Function "[name]" not found`         | Occurs when the `uid` in your `functions/*-hsmeta.json` file doesn't match the function name. Double-check that the `uid` matches, then check for any errors when running `hs project upload`.                                                                          |
| `Function execution timed out`        | The function didn't complete within 15 seconds. Try reducing any unnecessary external API calls, breaking larger functions into separate functions, or cache results from your requests.                                                                                |
| `Build failed: invalid configuration` | Results from project configuration issues. Run the `hs project validate` command to identify any schema errors, then address any missing fields in your project's `*-hsmeta.json` files. You should also confirm that all `uid` values are unique across all functions. |

## Related resources

Check out the following resources as you develop your app:

* [Create an app card with a serverless function](/apps/developer-platform/add-features/serverless-functions/create-serverless-functions)
* [App card reference](/apps/developer-platform/add-features/ui-extensions/extension-points/app-cards/reference)
* [UI extensions SDK](/apps/developer-platform/add-features/ui-extensions/ui-extensions-sdk)
