Supported products
Supported products
2026.09 of the developer platform, the current version at the time of writing. These functions are public endpoints served from https://<domain>/hs/serverless/<path>, which you can call from your website pages. Check developer platform versioning for the latest version.
For serverless functions built using the design manager, which are being sunset, see the serverless functions (design manager) reference and migrate design manager serverless functions to developer projects. For private functions that you call from UI extensions rather than from your website, see the developer platform serverless functions reference.
For a high-level overview of serverless functions, see the serverless functions overview. To build your first function, check out the get started guide.
Project structure
Serverless functions belong to an app with static auth and private distribution. Apps that use OAuth can’t include serverless functions. To create a project with an app and an example endpoint function, run:hs project add --features app-function-endpoint from the project directory.
Functions live in the app’s functions directory. Each function is a pair of files: a *-hsmeta.json configuration file and the JavaScript file it points to. One package.json file holds the dependencies for every function in the directory.
hs project upload sends only hsproject.json and the src/ directory to HubSpot. Files at the project root, such as a README, aren’t uploaded.
Function configuration
Each function has its own*-hsmeta.json file. The file name can be anything that ends in -hsmeta.json.
fetch-quote-hsmeta.json
The runtime is set by the platform version in
hsproject.json, not by the function configuration. Functions on 2026.03 and later run Node.js 24. There’s no runtime, version, or environment field. To give a function values it reads at runtime, use secrets.Function file
A function file exports anasync function named main, which receives the context object and returns the response. Use await with try/catch rather than promise chains or callbacks.
Below is the function from the get started guide, which fetches a quote from the Zen Quotes API.
fetch-quote.js
- Catch every error. If a function throws, it returns a
500response whose body includes the raw error message, which anyone who calls the endpoint can see. Log the details and return a generic message instead. - Await all work before you return. Work that’s still running when the function returns may never finish, including follow-up requests whose result the caller doesn’t need.
- Don’t log secrets. Anyone with access to the app can read its logs.
Responses
The returned object sets the response:
To redirect the visitor, return a
301 status code with a Location header:
package.json
List the packages your functions import insrc/app/functions/package.json. When you upload the project, HubSpot installs them and bundles them with your function code. Packages must be published to the public npm registry. Nothing is preloaded, so list every package your functions use.
To add a package, run npm install in the src/app/functions/ directory. For example, to add axios:
package.json:
Endpoints
A public function is invoked by calling its URL, which has the following structure:https://<domain>/hs/serverless/<path>
For example, if both website.com and subdomain.brand.com are connected to the account, you could call the function using
https://website.com/hs/serverless/<path> or https://subdomain.brand.com/hs/serverless/<path>. If the function’s path is fetch-quote, the full URL would be:
https://website.com/hs/serverless/fetch-quote
When you call a function from a page on your site, use a relative URL, such as /hs/serverless/fetch-quote. The request then goes to the page’s own domain, which avoids cross-origin (CORS) errors.
Endpoint paths are global across the account rather than scoped to an app or project. If two projects use the same path, the most recently deployed function takes precedence.
hs project upload builds the project and deploys the build as soon as it succeeds, so an endpoint is public as soon as you upload it. To upload without deploying, add --skip-auto-deploy. You can redeploy any previous build from the project in HubSpot.
Authentication
Functions can authenticate requests with the app’s built-in access token or with secrets. In the function file, you read both withprocess.env.
- App access token: every function can read
process.env.PRIVATE_APP_ACCESS_TOKENto call HubSpot APIs. The token has the scopes listed in the app’srequiredScopesinapp-hsmeta.json. Don’t add it tosecretKeys. Calls made with the token count against your API call limits. - Secrets: store other credentials, such as third-party API keys, as secrets with
hs secret add <NAME>, then list each secret’s name in the function’sconfig.secretKeysarray. Learn more about managing secrets.
oauth in requiredScopes, along with any scopes your functions use.
Below is the same request authenticated with the app access token and with a secret.
- App access token
- Secret
requiredScopes would include hubdb.rows.read.Context object
Thecontext object passed to a public function contains information about the request.
Public functions don’t receive
context.query; read query parameters from context.params. Functions built with developer projects also don’t receive context.limits, which design manager functions used to report remaining executions. A function that exceeds the execution limits returns a 429 response.Headers
If you need to know the headers of the client that’s calling your endpoint, you can access them throughcontext.headers.
Below, review some of the common headers. For a full list, see MDN’s HTTP headers documentation.
Logs
Every call to a function is logged, along with the output of anyconsole.log() and console.error() statements. To view the logs, run hs project open to open the project in HubSpot, open the app, then click the Logs tab. hs project logs --function <uid> prints a link to the logs, but doesn’t show log lines for public functions.
Limits
Serverless functions are intended to be fast and have a narrow focus. Keep the following limits in mind:- Each function has a maximum of 15 seconds of execution time. Give every retry or polling loop a limit, so a function doesn’t run until it times out.
- Functions that exceed the account’s execution limits return a
429response. There’s no field incontextthat reports how close you are to the limits, so handle429responses in the code that calls the function, for example by retrying after a delay. - Functions may experience cold starts after periods of inactivity. To reduce their impact, keep functions lightweight and minimize the number of external API calls.
- Requests with a body must use a content type of
application/json. Form posts (application/x-www-form-urlencoded) return a415response, so send form data as JSON. - Only privately distributed apps with static auth can include serverless functions.