Last modified: August 22, 2025
This feature requires approval from HubSpot to use. If you’re interested in applying to get access to app objects, or if you want to learn more about the functionality, please submit this interest form.
Below, find reference information for developer platform app features with app objects, including configuration file definitions, scopes details, and more.

Project structure

  • All project components must live within the src directory specified in the hsproject.json config file.
  • All app features and components must live within the app/ directory.
  • App objects are defined within the app-objects/ directory.
  • App object associations are defined within the app-object-associations/ directory.
  • All component and feature instances are declared using *-hsmeta.json files. You can use any file name you’d like, as long as it ends in -hsmeta.json (e.g., my-cool-object-hsmeta.json). These files must live at the root level of their respective folder.
project-folder/
└──src/
   └── app/
      ├── app-hsmeta.json
      └── app-objects/
        └── my-cool-object-hsmeta.json
      └── app-object-associations/
        └── my-cool-object-association-hsmeta.json

View example on GitHub

App objects

To create an app object, include an app-objects component directory in the project, along with a configuration file.
project-folder/
└───src/
   └── app/
      └── app-hsmeta.json
      └── app-objects/
        └── my-cool-object-hsmeta.json
Below are the configuration options available for *-object-hsmeta.json.
{
  "uid": "car-app-object",
  "type": "app-object",
  "config": {
    "name": "CAR",
    "appPrefix": "Vroom",
    "description": "An automobile in our warehouse.",
    "singularForm": "Car",
    "pluralForm": "Cars",
    "primaryDisplayLabelPropertyName": "model",
    "secondaryDisplayLabelPropertyNames": ["make"],
    "settings": {
      "hasRecordPage": true,
      "allowsUserCreatedRecords": true,
      "hasEngagements": true
    },
    "properties": [
      {
        "type": "string",
        "fieldType": "text",
        "name": "model",
        "label": "Model",
        "description": "The model of the car"
      },
      {
        "type": "enumeration",
        "fieldType": "select",
        "name": "make",
        "label": "Make",
        "description": "The manufacturer of the car.",
        "options": [
          {
            "label": "Ford",
            "value": "ford",
            "displayOrder": 0
          },
          {
            "label": "Toyota",
            "value": "toyota",
            "displayOrder": 1
          },
          {
            "label": "Chevrolet",
            "value": "chevrolet",
            "displayOrder": 2
          }
        ]
      }
    ]
  }
}

View example on GitHub

Fields marked with * are required.

FieldTypeDescription
uid*StringA unique identifier for the app object. Must be globally unique within the project.
type*StringThe type of component. Must match the name of the parent folder (app-object).
name*StringThe name of your app object. Use the approved name that you received in your approved app confirmation. Must be uppercase snake case (MY_OBJECT_NAME).
appPrefixStringA string that precedes the singular or plural name of the object in HubSpot’s UI to help differentiate it from other objects. In this example, the appPrefix of Vroom and singularForm of Car would result in “Vroom Car” displaying in the UI.
description*Stringthe description of the object, which will display in HubSpot.
singularForm*StringThe singular form of the object name.
pluralForm*StringThe plural form of the object name.
properties*ArrayA list of CRM properties defined for the object. Properties are defined using the same fields as the properties API. The resulting properties will automatically have a<appId>_ prepended to it (e.g., a12345_make) on creation. You should not include the prefix in the config file.
primaryDisplayLabelPropertyName*StringThe name of the property that should be used as the primary display property. The value should match the name provided in the properties list (i.e., it should not include the generated a<appId>_ prefix.)
secondaryDisplayLabelPropertyNames*ArrayThe list of properties that should be used as secondary display properties. The value should match the name provided in the properties list (i.e., it should not include the generated a<appId>_ prefix.)
settings*ObjectAn object containing object settings.
hasRecordPage*BooleanWhether record pages exist for instances of this app object. When set to false, the index page will still exist, but it will not include links to individual record pages.
allowsUserCreatedRecords*BooleanWhether end-users will be able to create records using the object. When set to false, users will not be able to create records in HubSpot
hasEngagements*BooleanWhether the app object records support activities/engagements. When set to false, app object record pages will not include any engagement functionalities, such as the activity tab or activity-related timeline filters.
The fully-qualified name (FQN) for your app object will be a<appId>_<objectName>. For example: if your appId is 16858319 and the app object name is CARS, then the FQN would be a16858319_CARS. You’ll use the FQN when setting scope values for your app objects.

App schema

To create an app object, include an app-hsmeta.json configuration file in the app directory.
project-folder/
└── src/
    └── app/
        └── app-hsmeta.json
Below are the configuration options available for app-hsmeta.json.
{
  "uid": "app_object_poc_app",
  "type": "app",
  "config": {
    "description": "An example to demonstrate how to build an app with an app object on developer projects.",
    "name": "my first app object app",
    "distribution": "marketplace",
    "auth": {
      "type": "oauth",
      "redirectUrls": ["http://localhost:3000/oauth-callback"],
      "requiredScopes": [
        "crm.objects.contacts.read",
        "crm.objects.contacts.write"
      ],
      "optionalScopes": [],
      "conditionallyRequiredScopes": []
    },
    "permittedUrls": {
      "fetch": ["https://api.hubapi.com"],
      "iframe": [],
      "img": []
    },
    "support": {
      "supportEmail": "support@example.com",
      "documentationUrl": "https://example.com/docs",
      "supportUrl": "https://example.com/support",
      "supportPhone": "+18005555555"
    }
  }
}

View example on GitHub

App schema *-hsmeta.json fields

Fields marked with * are required

FieldTypeDescription
uid*StringAn internal unique identifier for the app. Must be globally unique within the project. Can be any string up to 64 characters. Characters can be uppercase or lowercase, and can include numbers, underscores (_), dashes (-), and periods (.).
type*StringThe type of component. Must match the name of the parent folder (app).
description*StringA description of what the app does for the installing user. Can be any string up to 8192 characters.
name*StringThe name of the app, which will display in HubSpot. Can be any string up to 200 characters. Must not start or end with a whitespace character.
distribution*StringThe method of app distribution. Must be set to marketplace for the app to be eligible for App Marketplace listing.
auth*ObjectAn object containing the app’s authentication method details. See the auth table for details.
permittedUrlsObjectAn array containing the URLs that the app is allowed to call. URLs must use the HTTPS scheme and must contain an authority, followed by an optional path prefix if needed.
supportEmailStringA valid email address that users can contact for support.
documentationUrlStringThe external URL that users can navigate to for supporting documentation. Must use HTTPS.
supportUrlStringThe external URL that users can navigate to for additional support. Must use HTTPS.
supportPhoneStringThe phone number that users can contact for support. Must start with a plus sign (+).

auth fields

Fields marked with * are required.

FieldTypeDescription
type*StringThe type of authentication. Must be set to oauth for the app to use OAuth authentication.
redirectUrls*ArrayA list of URLs that the OAuth process is allowed to reroute back to. Each app must have at least one auth redirect URL, and it must use HTTPS. The only exception is that http://localhost is allowed for testing.
requiredScopes*ArrayA list of your app’s required scopes. Each app must include at least one scope, and the installing user must grant these scopes to successfully install the app. Learn more about scopes below.
optionalScopesArrayA list of your app’s optional scopes. These scopes can be excluded from the authorization during installation if the account or user installing the app doesn’t have the proper permissions. In that case, the scope will not be included in the resulting refresh token or access token. Learn more about scopes below.
conditionallyRequiredScopesArrayA list of scopes that are required only when included in the scope query parameter of the install URL. Learn more about scopes below.

Scopes

In the auth field of an app configuration file, you can specify three types of scopes: required scopes, conditionally required scopes, and optional scopes. For this stage of the beta, you should only include your app object scopes as conditionallyRequiredScopes. This will allow you to silo your new features to specific customers by including the app object scopes in the install URL. App object scopes use the following format: crm.app.schemas.<appObjectFullyQualifiedName>.read For example, for an app object with the FQN a16858319_cars, the read scope would be: crm.app.schemas.a16858319_cars.read. At a minimum, your app must include the above read scope to enable customers to access the object. It’s recommended to include all app object scopes in your app, as shown below.
"auth": {
      "type" : "oauth",
      "redirectUrls": ["http://localhost:3000/oauth-callback"],
      "requiredScopes": [
        "crm.objects.contacts.read",
        "crm.objects.contacts.write",
        "crm.app.objects.a12345_MY_APP_OBJECT.view",
        "crm.app.objects.a12345_MY_APP_OBJECT.create",
        "crm.app.objects.a12345_MY_APP_OBJECT.edit",
        "crm.app.schemas.a12345_MY_APP_OBJECT.read",
        "crm.app.objects.a12345_MY_APP_OBJECT.merge",
        "crm.app.objects.a12345_MY_APP_OBJECT.delete",
        "crm.app.schemas.a12345_MY_APP_OBJECT.properties.write"
      ],
      "optionalScopes": [],
      "conditionallyRequiredScopes": []
    },

For a full list of available scopes, see the scopes reference.

Webhooks component definition

To define a set of webhook subscriptions for your app, include a webhooks directory in the project, along with a *-hsmeta.json configuration file.
project-folder/
└── src/
    └── app/
        ├── app-hsmeta.json
        └── webhooks/
            └── webhook-hsmeta.json
Below are the available configuration options for the *-hsmeta.json file.
{
  "uid": "webhooks",
  "type": "webhooks",
  "config": {
    "settings": {
      "targetUrl": "https://example.com/webhook",
      "maxConcurrentRequests": 10
    },
    "subscriptions": {
      "crmObjects": [
        {
          "subscriptionType": "object.creation",
          "objectType": "contact",
          "active": true
        },
        {
          "subscriptionType": "object.propertyChange",
          "objectType": "car_app_object",
          "propertyName": "carProperty",
          "active": true
        }
      ],
      "legacyCrmObjects": [
        {
          "subscriptionType": "contact.propertyChange",
          "propertyName": "lastname",
          "active": true
        },
        {
          "subscriptionType": "contact.deletion",
          "active": true
        }
      ],
      "hubEvents": [
        {
          "subscriptionType": "contact.privacyDeletion",
          "active": true
        }
      ]
    }
  }
}

Webhook *-hsmeta.json fields

Fields marked with * are required.

FieldTypeDescription
uid*StringAn internal unique identifier for the webhook component.
type*StringThe type of component, which should be webhooks in this case.
settings*ObjectAn object that specifies two fields: targetUrl, which is the publicly available URL for HubSpot to call where event payloads will be delivered, and maxConcurrentRequests, which is the upper threshold of HTTP requests that HubSpot will make in a given time frame.
subscriptions*ObjectAn object that specifies the subscription types your app will subscribe to.
crmObjectsArrayAn array containing event subscription definitions. This is the standard array to include, and should be used for all events in the new format (object.*). Classic webhook subscription types should instead be included in legacyCrmObjects and hubEvents arrays, depending on the event.
legacyCrmObjectsArrayAn array containing classic subscription types, such as contact.creation and deal.deletion.
hubEventsArrayAn array containing the classic subscription types contact.privacyDeletion and conversation.*
For each subscription object, the following fields can be specified, based on the subscription definition type you’re subscribed to (i.e., crmObjects, legacyCrmObjects, or hubEvents) or whether you’re subscribing to a specific property change (e.g., contact.propertyChange).
FieldTypeDescription
subscriptionTypeStringThe type of event being subscribed to.
objectTypeStringFor subscriptions specified within the crmObjects array, this specifies the CRM object your app is subscribing to. For subscribing to changes to an app object, include your app object name for this field (e.g., car_app_object).
propertyNameStringFor property change subscriptions, this specifies which property will trigger the webhook event.
activeBooleanWhether webhook events will be triggered for this subscription.

App card schema

To create an app card that appears on an app object record page, include a cards component directory in the project, along with a configuration file.
project-folder/
└── src/
    └── app/
        ├── app-hsmeta.json
        └── cards/
            └── my-app-card-hsmeta.json
            └── my-app-card.jsx
  • Make sure you’ve run hs project upload after you created your app object component and the associated configuration files.
  • In your my-app-card-hsmeta.json file, add your app object UID to the objectTypes array (e.g., "app_object_uid" in this example). Each of the available fields in the .json file are detailed in the table below.
{
  "uid": "my-app-card",
  "type": "card",
  "config": {
    "name": "My app card",
    "description": "An example description of the card, which lives on contact records.",
    "previewImage": {
      "file": "./preview.png",
      "altText": "A short description of the preview image"
    },
    "entrypoint": "/app/cards/MyCard.jsx",
    "location": "crm.record.tab",
    "objectTypes": ["contacts", "app_object_uid"]
  }
}
  • After you’ve saved the changes to your example-card-hsmeta.json file, run hs project upload.
Cards are added automatically to the default view for app objects. If the card doesn’t automatically show up, learn how to add cards to CRM records.

View example on GitHub

App card *-hsmeta.json fields

Fields marked with * are required.

FieldTypeDescription
uid*StringThe card’s unique identifier. This can be any string, but should meaningfully identify the card. HubSpot will identify the card by this ID so that you can change the card’s title without removing historical or stateful data, such as the position on the CRM record.
typeStringThe type of component, which should be card in this case.
configObjectAn object containing configuration details.
name*StringThe card’s title, as displayed in HubSpot’s UI.
descriptionStringA description of the card.
previewImageObjectAn object containing the file and altText fields. The file field is the relative path to the preview image. Valid file extensions are png, jpeg, jpg, or gif. The maximum file size is 5.0 MB. The altText field is a short description of the image.
entrypoint*StringThe file path of the card’s front-end React code.
location*crm.record.tab | crm.record.sidebar | helpdesk.sidebarWhere the card appears in HubSpot’s UI. Learn more about extension location.
objectTypes*ArrayThe types of CRM records that the card will appear on.

App object associations

To enable associations between your app object and other CRM objects, include an app-object-associations component directory in the project, along with a configuration file.
project-folder/
└── src/
    └── app/
        ├── app-hsmeta.json
        └── app-object-associations/
            └── my-cool-object-associations-hsmeta.json
Below are the available app object configuration options (*-association-hsmeta.json).
{
  "uid": "car_to_contact_association",
  "type": "app-object-association",
  "config": {
    "firstObjectType": "car-app-object",
    "secondObjectType": "CONTACT"
  }
}

Association *-association-hsmeta.json fields

Fields marked with * are required.

FieldTypeDescription
uid*StringAn internal unique identifier for the app. Must be globally unique within the project.
type*StringThe type of component. Must match the name of the parent folder (app-object-association).
config*ObjectAn object containing the object association configuration.
firstObjectType*StringThe first object in the association. Can be either an app object or HubSpot CRM object. App objects are referred to by their uid specified in their source file. Standard objects are referred to by their fullyQualifiedName. The resulting association will be bi-directional, so the order of these field values is arbitrary.
secondObjectType*StringThe second object in the association. See firstObjectType for details.